From 022986d5109628f6f8e8ea4e0bac53834ff9066a Mon Sep 17 00:00:00 2001 From: Rudolf Cornelissen Date: Wed, 26 Jan 2022 23:42:14 +0000 Subject: [PATCH] intel_extreme: sandy/ivybridge DP links to screens are now programmed to the actual mode if possible --- .../graphics/intel_extreme/intel_extreme.h | 6 + .../accelerants/intel_extreme/Ports.cpp | 169 ++++++++++++++---- src/add-ons/accelerants/intel_extreme/Ports.h | 1 + 3 files changed, 144 insertions(+), 32 deletions(-) diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 674327baef..9ca3f3512e 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -857,6 +857,12 @@ struct intel_free_graphics_memory { #define INTEL_DISPLAY_PORT_C (0x4200 | REGS_SOUTH_TRANSCODER_PORT) #define INTEL_DISPLAY_PORT_D (0x4300 | REGS_SOUTH_TRANSCODER_PORT) +#define INTEL_DISP_PORT_WIDTH_SHIFT 19 +#define INTEL_DISP_PORT_WIDTH_MASK (7 << INTEL_DISP_PORT_WIDTH_SHIFT) +#define INTEL_DISP_PORT_WIDTH_1 0 +#define INTEL_DISP_PORT_WIDTH_2 1 +#define INTEL_DISP_PORT_WIDTH_4 2 + #define INTEL_TRANSCODER_A_DP_CTL (0x0300 | REGS_SOUTH_TRANSCODER_PORT) #define INTEL_TRANSCODER_B_DP_CTL (0x1300 | REGS_SOUTH_TRANSCODER_PORT) #define INTEL_TRANSCODER_C_DP_CTL (0x2300 | REGS_SOUTH_TRANSCODER_PORT) diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index 956aa77adb..6e5c6040a4 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -1173,6 +1173,117 @@ DisplayPort::_SetPortLinkGen4(const display_timing& timing) } +status_t +DisplayPort::_SetPortLinkGen6(const display_timing& timing) +{ + // Khz / 10. ( each output octet encoded as 10 bits. + //uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10; //=270000 khz + //fixme: eDP is fixed option 162 or 270Mc, other DPs go via DPLL programming to one of the same vals. + uint32 linkBandwidth = 270000; //khz + TRACE("%s: DP link reference clock is %gMhz\n", __func__, linkBandwidth / 1000.0f); + + uint32 fPipeOffset = 0; + switch (fPipe->Index()) { + case INTEL_PIPE_B: + fPipeOffset = 0x1000; + break; + case INTEL_PIPE_C: + fPipeOffset = 0x2000; + break; + default: + break; + } + + TRACE("%s: DP M1 data before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_TRANSCODER_A_DATA_M1 + fPipeOffset)); + TRACE("%s: DP N1 data before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_TRANSCODER_A_DATA_N1 + fPipeOffset)); + TRACE("%s: DP M1 link before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_TRANSCODER_A_LINK_M1 + fPipeOffset)); + TRACE("%s: DP N1 link before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_TRANSCODER_A_LINK_N1 + fPipeOffset)); + + uint32 bitsPerPixel = + (read32(INTEL_TRANSCODER_A_DP_CTL + fPipeOffset) & INTEL_TRANS_DP_BPC_MASK) >> INTEL_TRANS_DP_COLOR_SHIFT; + switch (bitsPerPixel) { + case PIPE_DDI_8BPC: + bitsPerPixel = 24; + break; + case PIPE_DDI_10BPC: + bitsPerPixel = 30; + break; + case PIPE_DDI_6BPC: + bitsPerPixel = 18; + break; + case PIPE_DDI_12BPC: + bitsPerPixel = 36; + break; + default: + ERROR("%s: DP illegal link colordepth set.\n", __func__); + return B_ERROR; + } + TRACE("%s: DP link colordepth: %" B_PRIu32 "\n", __func__, bitsPerPixel); + + uint32 lanes = + 1 << ((read32(_PortRegister()) & INTEL_DISP_PORT_WIDTH_MASK) >> INTEL_DISP_PORT_WIDTH_SHIFT); + if (lanes > 4) { + ERROR("%s: DP illegal number of lanes set.\n", __func__); + return B_ERROR; + } + TRACE("%s: DP mode with %" B_PRIx32 " lane(s) in use\n", __func__, lanes); + + //Reserving 5% bandwidth for possible spread spectrum clock use + uint32 bps = timing.pixel_clock * bitsPerPixel * 21 / 20; + //use DIV_ROUND_UP: + uint32 required_lanes = (bps + (linkBandwidth * 8) - 1) / (linkBandwidth * 8); + TRACE("%s: DP mode needs %" B_PRIx32 " lane(s) in use\n", __func__, required_lanes); + if (required_lanes > lanes) { + //Note that we *must* abort as otherwise the PIPE/DP-link hangs forever (without retraining!). + ERROR("%s: DP not enough lanes active for requested mode.\n", __func__); + return B_ERROR; + } + + //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(INTEL_TRANSCODER_A_DATA_M1 + fPipeOffset, ret_m | INTEL_TRANSCODER_MN_TU_SIZE_MASK); + write32(INTEL_TRANSCODER_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(INTEL_TRANSCODER_A_LINK_M1 + fPipeOffset, ret_m); + //Writing Link N triggers all four registers to be activated also (on next VBlank) + write32(INTEL_TRANSCODER_A_LINK_N1 + fPipeOffset, ret_n); + + TRACE("%s: DP M1 data after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_TRANSCODER_A_DATA_M1 + fPipeOffset)); + TRACE("%s: DP N1 data after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_TRANSCODER_A_DATA_N1 + fPipeOffset)); + TRACE("%s: DP M1 link after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_TRANSCODER_A_LINK_M1 + fPipeOffset)); + TRACE("%s: DP N1 link after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_TRANSCODER_A_LINK_N1 + fPipeOffset)); + + return B_OK; +} + + status_t DisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode) { @@ -1190,37 +1301,31 @@ DisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode) fPipe->ConfigureTimings(target); result = _SetPortLinkGen4(target->timing); } else { - //fixme: doesn't work yet. For now just scale to native mode. -#if 0 - // Setup PanelFitter and Train FDI if it exists - PanelFitter* fitter = fPipe->PFT(); - if (fitter != NULL) - fitter->Enable(*target); - // skip FDI if it doesn't exist - if (gInfo->shared_info->device_type.Generation() <= 8) { - FDILink* link = fPipe->FDI(); - if (link != NULL) - link->Train(target); + result = _SetPortLinkGen6(target->timing); + if (result == B_OK) { + // Setup PanelFitter and Train FDI if it exists + PanelFitter* fitter = fPipe->PFT(); + if (fitter != NULL) + fitter->Enable(target->timing); + // skip FDI if it doesn't exist or we don't use it (eDP) + if ((gInfo->shared_info->device_type.Generation() <= 8) && (PortIndex() != INTEL_PORT_A)) { + FDILink* link = fPipe->FDI(); + if (link != NULL) + link->Train(&target->timing); + } + + // Program general pipe config + fPipe->Configure(target); + + // Pll programming is not needed for (e)DP.. + + // Program target display mode + fPipe->ConfigureTimings(target); + } else { + TRACE("%s: Setting display mode via fallback: using scaling!\n", __func__); + // Keep monitor at native mode and scale image to that + fPipe->ConfigureScalePos(target); } - pll_divisors divisors; - compute_pll_divisors(target, &divisors, false); - - uint32 extraPLLFlags = 0; - if (gInfo->shared_info->device_type.Generation() >= 3) - extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL | DISPLAY_PLL_2X_CLOCK; - - // Program general pipe config - fPipe->Configure(target); - - // Program pipe PLL's - fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags); - - // Program target display mode - fPipe->ConfigureTimings(target); -#endif - - // Keep monitor at native mode and scale image to that - fPipe->ConfigureScalePos(target); } // Set fCurrentMode to our set display mode @@ -1533,9 +1638,9 @@ DigitalDisplayInterface::_SetPortLinkGen8(const display_timing& timing, uint32 p if (((pipeFunc & PIPE_DDI_MODESEL_MASK) >> PIPE_DDI_MODESEL_SHIFT) >= PIPE_DDI_MODE_DP_SST) { // On gen 9.5 IceLake 3x mode exists (DSI only), earlier models: reserved value. lanes = ((pipeFunc & PIPE_DDI_DP_WIDTH_MASK) >> PIPE_DDI_DP_WIDTH_SHIFT) + 1; - TRACE("%s: DDI in DP mode with %" B_PRIx32 " lanes in use\n", __func__, lanes); + TRACE("%s: DDI in DP mode with %" B_PRIx32 " lane(s) in use\n", __func__, lanes); } else { - TRACE("%s: DDI in non-DP mode with %" B_PRIx32 " lanes in use\n", __func__, lanes); + TRACE("%s: DDI in non-DP mode with %" B_PRIx32 " lane(s) in use\n", __func__, lanes); } //Setup Data M/N diff --git a/src/add-ons/accelerants/intel_extreme/Ports.h b/src/add-ons/accelerants/intel_extreme/Ports.h index 02a57ba16d..acac7f6cdb 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.h +++ b/src/add-ons/accelerants/intel_extreme/Ports.h @@ -182,6 +182,7 @@ virtual addr_t _PortRegister(); private: status_t _SetPortLinkGen4(const display_timing& timing); + status_t _SetPortLinkGen6(const display_timing& timing); };