diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 224e7f2140..2a71571a27 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -1248,31 +1248,31 @@ struct intel_free_graphics_memory { #define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2 << 22) #define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3 << 22) -//(FDI) PIPE M/N DATA AND LINK VALUES (refreshrate) -#define PCH_FDI_PIPE_A_DATA_M1 0x0030 -#define PCH_FDI_PIPE_A_DATA_M2 0x0038 -#define PCH_FDI_PIPE_B_DATA_M1 0x1030 -#define PCH_FDI_PIPE_B_DATA_M2 0x1038 -#define PCH_FDI_PIPE_C_DATA_M1 0x2030 -#define PCH_FDI_PIPE_C_DATA_M2 0x2038 -#define PCH_FDI_PIPE_A_DATA_N1 0x0034 -#define PCH_FDI_PIPE_A_DATA_N2 0x003c -#define PCH_FDI_PIPE_B_DATA_N1 0x1034 -#define PCH_FDI_PIPE_B_DATA_N2 0x103c -#define PCH_FDI_PIPE_C_DATA_N1 0x2034 -#define PCH_FDI_PIPE_C_DATA_N2 0x203c -#define PCH_FDI_PIPE_A_LINK_M1 0x0040 -#define PCH_FDI_PIPE_A_LINK_M2 0x0048 -#define PCH_FDI_PIPE_B_LINK_M1 0x1040 -#define PCH_FDI_PIPE_B_LINK_M2 0x1048 -#define PCH_FDI_PIPE_C_LINK_M1 0x2040 -#define PCH_FDI_PIPE_C_LINK_M2 0x2048 -#define PCH_FDI_PIPE_A_LINK_N1 0x0044 -#define PCH_FDI_PIPE_A_LINK_N2 0x004c -#define PCH_FDI_PIPE_B_LINK_N1 0x1044 -#define PCH_FDI_PIPE_B_LINK_N2 0x104c -#define PCH_FDI_PIPE_C_LINK_N1 0x2044 -#define PCH_FDI_PIPE_C_LINK_N2 0x204c +// FDI/PIPE M/N DATA AND LINK VALUES (refreshrate) +#define PCH_FDI_PIPE_A_DATA_M1 (0x0030 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_A_DATA_M2 (0x0038 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_B_DATA_M1 (0x1030 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_B_DATA_M2 (0x1038 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_C_DATA_M1 (0x2030 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_C_DATA_M2 (0x2038 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_A_DATA_N1 (0x0034 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_A_DATA_N2 (0x003c | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_B_DATA_N1 (0x1034 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_B_DATA_N2 (0x103c | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_C_DATA_N1 (0x2034 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_C_DATA_N2 (0x203c | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_A_LINK_M1 (0x0040 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_A_LINK_M2 (0x0048 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_B_LINK_M1 (0x1040 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_B_LINK_M2 (0x1048 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_C_LINK_M1 (0x2040 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_C_LINK_M2 (0x2048 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_A_LINK_N1 (0x0044 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_A_LINK_N2 (0x004c | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_B_LINK_N1 (0x1044 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_B_LINK_N2 (0x104c | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_C_LINK_N1 (0x2044 | REGS_NORTH_PIPE_AND_PORT) +#define PCH_FDI_PIPE_C_LINK_N2 (0x204c | REGS_NORTH_PIPE_AND_PORT) #define FDI_PIPE_MN_TU_SIZE_MASK (0x3f << 25) #define FDI_PIPE_MN_VALUE_MASK (0xffffff << 0) diff --git a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp index 6bdbaa38a6..619380bbd5 100644 --- a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp +++ b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp @@ -250,60 +250,56 @@ FDILink::FDILink(pipe_index pipeIndex) status_t -FDILink::Train(display_timing* target) // fixme: seperate FDI training and PIPE M/N programming.. +FDILink::PreTrain(display_timing* target, uint32* linkBandwidth, uint32* lanes, uint32* bitsPerPixel) { CALLED(); - status_t result = B_OK; - uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; //Link bit depth: this should be globally known per FDI link (i.e. laptop panel 3x6, rest 3x8) - uint32 bitsPerPixel = ((read32(rxControl) & FDI_RX_LINK_BPC_MASK) >> FDI_RX_LINK_COLOR_SHIFT); - switch (bitsPerPixel) { + *bitsPerPixel = ((read32(rxControl) & FDI_RX_LINK_BPC_MASK) >> FDI_RX_LINK_COLOR_SHIFT); + switch (*bitsPerPixel) { case INTEL_PIPE_8BPC: - bitsPerPixel = 24; + *bitsPerPixel = 24; break; case INTEL_PIPE_10BPC: - bitsPerPixel = 30; + *bitsPerPixel = 30; break; case INTEL_PIPE_6BPC: - bitsPerPixel = 18; + *bitsPerPixel = 18; break; case INTEL_PIPE_12BPC: - bitsPerPixel = 36; + *bitsPerPixel = 36; break; default: + *bitsPerPixel = 0; ERROR("%s: FDI illegal link colordepth set.\n", __func__); return B_ERROR; } TRACE("%s: FDI Link %s:\n", __func__, (fPipeIndex == INTEL_PIPE_A) ? "A" : "B"); - TRACE("%s: FDI Link Colordepth: %" B_PRIu32 "\n", __func__, bitsPerPixel); + TRACE("%s: FDI Link Colordepth: %" B_PRIu32 "\n", __func__, *bitsPerPixel); // Khz / 10. ( each output octet encoded as 10 bits. // note: if used for eDP (PORT_A) might be we should check reg. DP_CTL (0x64000), bit 16-17 (Ivy). - uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10; + *linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10; //Reserving 5% bandwidth for possible spread spectrum clock use - uint32 bps = target->pixel_clock * bitsPerPixel * 21 / 20; + uint32 bps = target->pixel_clock * *bitsPerPixel * 21 / 20; //use DIV_ROUND_UP: - uint32 lanes = (bps + (linkBandwidth * 8) - 1) / (linkBandwidth * 8); + *lanes = (bps + (*linkBandwidth * 8) - 1) / (*linkBandwidth * 8); //remove below line when link training is to be done - lanes = ((read32(txControl) & FDI_DP_PORT_WIDTH_MASK) >> FDI_DP_PORT_WIDTH_SHIFT) + 1; + *lanes = ((read32(txControl) & FDI_DP_PORT_WIDTH_MASK) >> FDI_DP_PORT_WIDTH_SHIFT) + 1; - TRACE("%s: FDI Link Lanes: %" B_PRIu32 "\n", __func__, lanes); + TRACE("%s: FDI Link Lanes: %" B_PRIu32 "\n", __func__, *lanes); //assuming we'll only use link A and B (not C) - if (lanes > 4) { - result = B_ERROR; - } - if (result != B_OK) { + if (*lanes > 4) { ERROR("%s: FDI not enough lanes in hardware.\n", __func__); - return result; + return B_ERROR; } - TRACE("%s: FDI TX ctrl: 0x%" B_PRIx32 "\n", __func__, read32(txControl)); - TRACE("%s: FDI RX ctrl: 0x%" B_PRIx32 "\n", __func__, read32(rxControl)); + TRACE("%s: FDI TX ctrl before: 0x%" B_PRIx32 "\n", __func__, read32(txControl)); + TRACE("%s: FDI RX ctrl before: 0x%" B_PRIx32 "\n", __func__, read32(rxControl)); #if 0 //when link training is to be done re-enable this code @@ -330,51 +326,19 @@ FDILink::Train(display_timing* target) // fixme: seperate FDI training and PIPE Receiver().DisablePLL(); #endif - TRACE("%s: FDI M1 data before: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_M1)); - TRACE("%s: FDI N1 data before: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_N1)); - TRACE("%s: FDI M1 link before: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_M1)); - TRACE("%s: FDI N1 link before: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_N1)); + return B_OK; +} - //Setup Data M/N - uint64 linkspeed = lanes * linkBandwidth * 8; - uint64 ret_n = 1; - while(ret_n < linkspeed) { - ret_n *= 2; - } - if (ret_n > 0x800000) { - ret_n = 0x800000; - } - uint64 ret_m = target->pixel_clock * ret_n * bitsPerPixel / linkspeed; - while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) { - ret_m >>= 1; - ret_n >>= 1; - } - //Set TU size bits (to default, max) before link training so that error detection works - write32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_M1, ret_m | FDI_PIPE_MN_TU_SIZE_MASK); - write32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_N1, ret_n); - //Setup Link M/N - linkspeed = linkBandwidth; - ret_n = 1; - while(ret_n < linkspeed) { - ret_n *= 2; - } - if (ret_n > 0x800000) { - ret_n = 0x800000; - } - ret_m = target->pixel_clock * ret_n / linkspeed; - while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) { - ret_m >>= 1; - ret_n >>= 1; - } - write32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_M1, ret_m); - //Writing Link N triggers all four registers to be activated also (on next VBlank) - write32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_N1, ret_n); +status_t +FDILink::Train(display_timing* target, uint32 lanes) +{ + CALLED(); - TRACE("%s: FDI M1 data after: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_M1)); - TRACE("%s: FDI N1 data after: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_N1)); - TRACE("%s: FDI M1 link after: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_M1)); - TRACE("%s: FDI N1 link after: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_N1)); + status_t result = B_OK; + + uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; + uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; //Set receiving end TU size bits to match sending end's setting write32(Receiver().Base() + PCH_FDI_RX_TRANS_UNIT_SIZE_1, FDI_RX_TRANS_UNIT_MASK); @@ -399,9 +363,11 @@ FDILink::Train(display_timing* target) // fixme: seperate FDI training and PIPE result = _NormalTrain(lanes); #endif - if (result != B_OK) { + TRACE("%s: FDI TX ctrl after: 0x%" B_PRIx32 "\n", __func__, read32(txControl)); + TRACE("%s: FDI RX ctrl after: 0x%" B_PRIx32 "\n", __func__, read32(rxControl)); + + if (result != B_OK) ERROR("%s: FDI training fault.\n", __func__); - } return result; } diff --git a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h index aac632fec8..cc3a28fde8 100644 --- a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h +++ b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h @@ -65,7 +65,12 @@ public: FDIReceiver& Receiver() { return fReceiver; }; - status_t Train(display_timing* target); + status_t PreTrain( + display_timing* target, + uint32* linkBandwidth, + uint32* lanes, + uint32* bitsPerPixel); + status_t Train(display_timing* target, uint32 lanes); private: status_t _NormalTrain(uint32 lanes); diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.cpp b/src/add-ons/accelerants/intel_extreme/Pipes.cpp index ba3233de2c..4a97991b46 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.cpp +++ b/src/add-ons/accelerants/intel_extreme/Pipes.cpp @@ -219,6 +219,73 @@ Pipe::_ConfigureTranscoder(display_mode* target) } +status_t +Pipe::SetFDILink(const display_timing& timing, uint32 linkBandwidth, uint32 lanes, uint32 bitsPerPixel) +{ + TRACE("%s: fPipeOffset: 0x%" B_PRIx32"\n", __func__, fPipeOffset); + TRACE("%s: FDI/PIPE link reference clock is %gMhz\n", __func__, linkBandwidth / 1000.0f); + TRACE("%s: FDI/PIPE M1 data before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset)); + TRACE("%s: FDI/PIPE N1 data before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset)); + TRACE("%s: FDI/PIPE M1 link before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset)); + TRACE("%s: FDI/PIPE N1 link before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset)); + + if ((bitsPerPixel < 18) || (bitsPerPixel > 36)) { + ERROR("%s: FDI/PIPE illegal colordepth set.\n", __func__); + return B_ERROR; + } + TRACE("%s: FDI/PIPE link colordepth: %" B_PRIu32 "\n", __func__, bitsPerPixel); + + if (lanes > 4) { + ERROR("%s: FDI/PIPE illegal number of lanes set.\n", __func__); + return B_ERROR; + } + TRACE("%s: FDI/PIPE link with %" B_PRIx32 " lane(s) in use\n", __func__, lanes); + + //Setup Data M/N + uint64 linkspeed = lanes * linkBandwidth * 8; + uint64 ret_n = 1; + while(ret_n < linkspeed) { + ret_n *= 2; + } + if (ret_n > 0x800000) { + ret_n = 0x800000; + } + uint64 ret_m = timing.pixel_clock * ret_n * bitsPerPixel / linkspeed; + while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) { + ret_m >>= 1; + ret_n >>= 1; + } + //Set TU size bits (to default, max) before link training so that error detection works + write32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset, ret_m | FDI_PIPE_MN_TU_SIZE_MASK); + write32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset, ret_n); + + //Setup Link M/N + linkspeed = linkBandwidth; + ret_n = 1; + while(ret_n < linkspeed) { + ret_n *= 2; + } + if (ret_n > 0x800000) { + ret_n = 0x800000; + } + ret_m = timing.pixel_clock * ret_n / linkspeed; + while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) { + ret_m >>= 1; + ret_n >>= 1; + } + write32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset, ret_m); + //Writing Link N triggers all four registers to be activated also (on next VBlank) + write32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset, ret_n); + + TRACE("%s: FDI/PIPE M1 data after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset)); + TRACE("%s: FDI/PIPE N1 data after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset)); + TRACE("%s: FDI/PIPE M1 link after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset)); + TRACE("%s: FDI/PIPE N1 link after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset)); + + return B_OK; +} + + void Pipe::ConfigureScalePos(display_mode* target) { diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.h b/src/add-ons/accelerants/intel_extreme/Pipes.h index ade27f7030..c9ed4be238 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.h +++ b/src/add-ons/accelerants/intel_extreme/Pipes.h @@ -40,6 +40,11 @@ public: void Disable(); void Configure(display_mode* mode); + status_t SetFDILink( + const display_timing& timing, + uint32 linkBandwidth, + uint32 lanes, + uint32 bitsPerPixel); void ConfigureScalePos(display_mode* mode); void ConfigureTimings(display_mode* mode, bool hardware = true); diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index 0491260f56..be703f7059 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -416,9 +416,14 @@ AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode) if (fitter != NULL) fitter->Enable(target->timing); FDILink* link = fPipe->FDI(); - if (link != NULL) - link->Train(&target->timing); - + if (link != NULL) { + uint32 lanes = 0; + uint32 linkBandwidth = 0; + uint32 bitsPerPixel = 0; + link->PreTrain(&target->timing, &linkBandwidth, &lanes, &bitsPerPixel); + fPipe->SetFDILink(target->timing, linkBandwidth, lanes, bitsPerPixel); + link->Train(&target->timing, lanes); + } pll_divisors divisors; compute_pll_divisors(&target->timing, &divisors, false); @@ -656,8 +661,14 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode) if (fitter != NULL) fitter->Enable(hardwareTarget); FDILink* link = fPipe->FDI(); - if (link != NULL) - link->Train(&hardwareTarget); + if (link != NULL) { + uint32 lanes = 0; + uint32 linkBandwidth = 0; + uint32 bitsPerPixel = 0; + link->PreTrain(&hardwareTarget, &linkBandwidth, &lanes, &bitsPerPixel); + fPipe->SetFDILink(hardwareTarget, linkBandwidth, lanes, bitsPerPixel); + link->Train(&hardwareTarget, lanes); + } pll_divisors divisors; compute_pll_divisors(&hardwareTarget, &divisors, true); @@ -853,8 +864,14 @@ DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode) if (fitter != NULL) fitter->Enable(target->timing); FDILink* link = fPipe->FDI(); - if (link != NULL) - link->Train(&target->timing); + if (link != NULL) { + uint32 lanes = 0; + uint32 linkBandwidth = 0; + uint32 bitsPerPixel = 0; + link->PreTrain(&target->timing, &linkBandwidth, &lanes, &bitsPerPixel); + fPipe->SetFDILink(target->timing, linkBandwidth, lanes, bitsPerPixel); + link->Train(&target->timing, lanes); + } pll_divisors divisors; compute_pll_divisors(&target->timing, &divisors, false); @@ -1371,8 +1388,14 @@ DisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode) fitter->Enable(hardwareTarget); // we should skip FDI if PORT_A, but need pipe M/N programming (is eDP link), so call always for now FDILink* link = fPipe->FDI(); - if (link != NULL) - link->Train(&target->timing); + if (link != NULL) { + uint32 lanes = 0; + uint32 linkBandwidth = 0; + uint32 bitsPerPixel = 0; + link->PreTrain(&hardwareTarget, &linkBandwidth, &lanes, &bitsPerPixel); + fPipe->SetFDILink(hardwareTarget, linkBandwidth, lanes, bitsPerPixel); + link->Train(&hardwareTarget, lanes); + } // Program general pipe config fPipe->Configure(target);