From aca9888e37580d9adee2e66fb91f4c542e834692 Mon Sep 17 00:00:00 2001 From: Rudolf Cornelissen Date: Tue, 8 Jun 2021 09:20:34 +0000 Subject: [PATCH] Intel_extreme: fixed hrev55115 regression and added FDI data/link M/N programming. --- .../graphics/intel_extreme/intel_extreme.h | 15 +- .../FlexibleDisplayInterface.cpp | 157 +++++++++++++++--- .../accelerants/intel_extreme/Pipes.cpp | 10 +- .../accelerants/intel_extreme/Ports.cpp | 41 ++--- 4 files changed, 176 insertions(+), 47 deletions(-) diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 9f5594bd90..6bfb530860 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -727,10 +727,13 @@ struct intel_free_graphics_memory { #define INTEL_PIPE_DITHER_TYPE_ST2 (2 << 2) #define INTEL_PIPE_DITHER_TYPE_TEMP (3 << 2) #define INTEL_PIPE_DITHER_EN (1 << 4) -#define INTEL_PIPE_8BPC (0 << 5) -#define INTEL_PIPE_10BPC (1 << 5) -#define INTEL_PIPE_6BPC (2 << 5) -#define INTEL_PIPE_12BPC (3 << 5) +#define INTEL_PIPE_COLOR_SHIFT 5 +#define INTEL_PIPE_BPC(x) ((x) << INTEL_PIPE_COLOR_SHIFT) +#define INTEL_PIPE_BPC_MASK (7 << INTEL_PIPE_COLOR_SHIFT) +#define INTEL_PIPE_8BPC 0 +#define INTEL_PIPE_10BPC 1 +#define INTEL_PIPE_6BPC 2 +#define INTEL_PIPE_12BPC 3 #define INTEL_PIPE_PROGRESSIVE (0 << 21) // cursors @@ -917,6 +920,10 @@ struct intel_free_graphics_memory { #define FDI_RX_ENABLE (1 << 31) #define FDI_RX_PLL_ENABLED (1 << 13) +#define FDI_RX_LINK_COLOR_SHIFT 16 +#define FDI_RX_LINK_BPC(x) ((x) << FDI_RX_LINK_COLOR_SHIFT) +#define FDI_RX_LINK_BPC_MASK (7 << FDI_RX_LINK_COLOR_SHIFT) + // Transcoder - same base as FDI_RX #define PCH_TRANS_CONF_A 0x0008 #define PCH_TRANS_CONF_B 0x1008 diff --git a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp index 5fbc9df472..9096c74253 100644 --- a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp +++ b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp @@ -103,6 +103,13 @@ FDITransmitter::EnablePLL(uint32 lanes) return; } + value &= ~FDI_DP_PORT_WIDTH_MASK; + value |= FDI_DP_PORT_WIDTH(lanes); + + //first update config, -then- enable PLL to be sure config is indeed updated + write32(targetRegister, value); + read32(targetRegister); + write32(targetRegister, value | FDI_TX_PLL_ENABLED); read32(targetRegister); spin(100); // warmup 10us + dmi delay 20us, be generous @@ -189,9 +196,17 @@ FDIReceiver::EnablePLL(uint32 lanes) return; } - value &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16)); + //Link bit depth: this should be globally known per FDI link (i.e. laptop panel 3x6, rest 3x8) + //currently using BIOS preconfigured setup + //value &= ~FDI_DP_PORT_WIDTH_MASK; + //value |= FDI_RX_LINK_BPC(INTEL_PIPE_8BPC); + + value &= ~FDI_DP_PORT_WIDTH_MASK; value |= FDI_DP_PORT_WIDTH(lanes); - //value |= (read32(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; + + //first update config, -then- enable PLL to be sure config is indeed updated + write32(targetRegister, value); + read32(targetRegister); write32(targetRegister, value | FDI_RX_PLL_ENABLED); read32(targetRegister); @@ -239,38 +254,132 @@ FDILink::Train(display_mode* target) { CALLED(); - uint32 bitsPerPixel; - switch (target->space) { - case B_RGB32_LITTLE: - bitsPerPixel = 32; + 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) { + case INTEL_PIPE_8BPC: + bitsPerPixel = 24; break; - case B_RGB16_LITTLE: - bitsPerPixel = 16; + case INTEL_PIPE_10BPC: + bitsPerPixel = 30; break; - case B_RGB15_LITTLE: - bitsPerPixel = 15; + case INTEL_PIPE_6BPC: + bitsPerPixel = 18; + break; + case INTEL_PIPE_12BPC: + bitsPerPixel = 36; break; - case B_CMAP8: default: - bitsPerPixel = 8; - break; + ERROR("%s: FDI illegal link colordepth set.\n", __func__); + return B_ERROR; } + TRACE("%s: FDI Link Colordepth: %" B_PRIu32 "\n", __func__, bitsPerPixel); // Khz / 10. ( each output octet encoded as 10 bits. uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10; + //Reserving 5% bandwidth for possible spread spectrum clock use uint32 bps = target->timing.pixel_clock * bitsPerPixel * 21 / 20; - uint32 lanes = bps / (linkBandwidth * 8); + //use DIV_ROUND_UP: + uint32 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; 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) { + ERROR("%s: FDI not enough lanes in hardware.\n", __func__); + return result; + } + TRACE("%s: FDI TX ctrl: 0x%" B_PRIx32 "\n", __func__, read32(txControl)); + TRACE("%s: FDI RX ctrl: 0x%" B_PRIx32 "\n", __func__, read32(rxControl)); + +#if 0 + //when link training is to be done re-enable this code + + //The order of handling things is important here.. + write32(txControl, read32(txControl) & ~FDI_TX_ENABLE); + read32(txControl); + write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE); + read32(rxControl); + + write32(txControl, (read32(txControl) & ~FDI_LINK_TRAIN_NONE) | FDI_LINK_TRAIN_PATTERN_1); + read32(txControl); + if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { + write32(rxControl, (read32(rxControl) & ~FDI_LINK_TRAIN_PATTERN_MASK_CPT) | FDI_LINK_TRAIN_PATTERN_1_CPT); + } else { + write32(rxControl, (read32(rxControl) & ~FDI_LINK_TRAIN_NONE) | FDI_LINK_TRAIN_PATTERN_1); + } + read32(rxControl); + spin(100); + + // Disable FDI clocks + Receiver().SwitchClock(false); + Transmitter().DisablePLL(); + Receiver().DisablePLL(); +#endif + + //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->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(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->timing.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); + + TRACE("%s: FDI data M1: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_M1)); + TRACE("%s: FDI data N1: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_N1)); + TRACE("%s: FDI link M1: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_M1)); + TRACE("%s: FDI link N1: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_N1)); + + //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); + write32(Receiver().Base() + PCH_FDI_RX_TRANS_UNIT_SIZE_2, FDI_RX_TRANS_UNIT_MASK); + +#if 0 + //when link training is to be done re-enable this code // Enable FDI clocks Receiver().EnablePLL(lanes); Receiver().SwitchClock(true); Transmitter().EnablePLL(lanes); - status_t result = B_ERROR; - // TODO: Only _AutoTrain on IVYB Stepping B or later // otherwise, _ManualTrain if (gInfo->shared_info->device_type.Generation() >= 7) @@ -281,6 +390,7 @@ FDILink::Train(display_mode* target) result = _IlkTrain(lanes); else result = _NormalTrain(lanes); +#endif if (result != B_OK) { ERROR("%s: FDI training fault.\n", __func__); @@ -580,6 +690,7 @@ FDILink::_AutoTrain(uint32 lanes) uint32 buffer = read32(txControl); // Clear port width selection and set number of lanes + // fixme: does not belong in the train routines (?), (now) sits in FDI EnablePLL() routines buffer &= ~(7 << 19); buffer |= (lanes - 1) << 19; @@ -589,6 +700,9 @@ FDILink::_AutoTrain(uint32 lanes) buffer &= ~FDI_LINK_TRAIN_NONE; write32(txControl, buffer); + write32(Receiver().Base() + PCH_FDI_RX_MISC, + FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + bool trained = false; for (uint32 i = 0; i < (sizeof(gSnbBFDITrainParam) @@ -599,10 +713,11 @@ FDILink::_AutoTrain(uint32 lanes) buffer &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; buffer |= gSnbBFDITrainParam[i]; write32(txControl, buffer | FDI_TX_ENABLE); - + read32(txControl); write32(rxControl, read32(rxControl) | FDI_RX_ENABLE); + read32(rxControl); - spin(5); + spin(50);//looks like datasheet specified 5uS is not enough..? buffer = read32(txControl); if ((buffer & FDI_AUTO_TRAIN_DONE) != 0) { @@ -612,6 +727,7 @@ FDILink::_AutoTrain(uint32 lanes) } write32(txControl, read32(txControl) & ~FDI_TX_ENABLE); + read32(txControl); write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE); read32(rxControl); @@ -628,11 +744,14 @@ FDILink::_AutoTrain(uint32 lanes) return B_ERROR; } - // Enable ecc on IVB + // Enable ecc on IVB (and disable test pattern at sending and receiving end) if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) { write32(rxControl, read32(rxControl) | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE); read32(rxControl); + //enable normal pixels (kill testpattern) + write32(txControl, read32(txControl) | (0x3 << 8)); + read32(txControl); } return B_OK; diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.cpp b/src/add-ons/accelerants/intel_extreme/Pipes.cpp index 5eeef0ba20..f136974e66 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.cpp +++ b/src/add-ons/accelerants/intel_extreme/Pipes.cpp @@ -107,8 +107,10 @@ Pipe::Configure(display_mode* mode) //if (gInfo->shared_info->device_type.Generation() >= 4) { // pipeControl |= (INTEL_PIPE_DITHER_EN | INTEL_PIPE_DITHER_TYPE_SP); - //Link bit depth, which is currently hardcoded to 8-bits per color - pipeControl = (pipeControl & ~(0x7 << 5)) | INTEL_PIPE_8BPC; + //Link bit depth: this should be globally known per FDI link (i.e. laptop panel 3x6, rest 3x8) + //currently using BIOS preconfigured setup + //pipeControl = (pipeControl & ~INTEL_PIPE_BPC_MASK) | INTEL_PIPE_BPC(INTEL_PIPE_8BPC); + // TODO: CxSR downclocking? // TODO: Interlaced modes @@ -356,7 +358,7 @@ Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock, // register which routes the PLL output to the transcoder that we need // to configure uint32 pllSel = read32(SNB_DPLL_SEL); - TRACE("Old PLL selection: %x\n", pllSel); + TRACE("Old PLL selection: 0x%" B_PRIx32 "\n", pllSel); uint32 shift = 0; uint32 pllIndex = 0; @@ -381,7 +383,7 @@ Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock, // Set up the new configuration for this transcoder and enable it pllSel |= (8 | pllIndex) << shift; - TRACE("New PLL selection: %x\n", pllSel); + TRACE("New PLL selection: 0x%" B_PRIx32 "\n", pllSel); write32(SNB_DPLL_SEL, pllSel); } } diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index bef4fe42d4..e9cf899a0d 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -21,6 +21,7 @@ #include "accelerant_protos.h" #include "FlexibleDisplayInterface.h" #include "intel_extreme.h" +#include "PanelFitter.h" #include @@ -133,7 +134,7 @@ Port::SetPipe(Pipe* pipe) // FIXME is the use of PORT_TRANS_* constants correct for Sandy Bridge / // Cougar Point? Or is it only for Ivy Bridge / Panther point onwards? if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { - portState &= ~PORT_TRANS_SEL_MASK; + portState &= ~PORT_TRANS_SEL_MASK; //fixme should be done sooner, not here! if (pipe->Index() == INTEL_PIPE_A) write32(portRegister, portState | PORT_TRANS_A_SEL_CPT); else @@ -144,7 +145,6 @@ Port::SetPipe(Pipe* pipe) else write32(portRegister, portState | DISPLAY_MONITOR_PIPE_B); } - fPipe = pipe; if (fPipe == NULL) @@ -306,6 +306,7 @@ AnalogPort::_PortRegister() status_t AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode) { + CALLED(); TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width, target->virtual_height); @@ -314,14 +315,13 @@ AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode) return B_ERROR; } -#if 0 - // Disabled for now as our code doesn't work. Let's hope VESA/EFI has - // already set things up for us during boot. - // Train FDI if it exists + // Setup PanelFitter and Train FDI if it exists FDILink* link = fPipe->FDI(); - if (link != NULL) + if (link != NULL) { + // fixme insert fitter setup here + link->Train(target); -#endif + } pll_divisors divisors; compute_pll_divisors(target, &divisors, false); @@ -500,14 +500,13 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode) } } -#if 0 - // Disabled for now as our code doesn't work. Let's hope VESA/EFI has - // already set things up for us during boot. - // Train FDI if it exists + // Setup PanelFitter and Train FDI if it exists FDILink* link = fPipe->FDI(); - if (link != NULL) + if (link != NULL) { + // fixme insert fitter setup here + link->Train(target); -#endif + } // For LVDS panels, we may need to set the timings according to the panel // native video mode, and let the panel fitter do the scaling. But the @@ -727,6 +726,7 @@ DigitalPort::_PortRegister() status_t DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode) { + CALLED(); TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width, target->virtual_height); @@ -735,14 +735,13 @@ DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode) return B_ERROR; } -#if 0 - // Disabled for now as our code doesn't work. Let's hope VESA/EFI has - // already set things up for us during boot. - // Train FDI if it exists + // Setup PanelFitter and Train FDI if it exists FDILink* link = fPipe->FDI(); - if (link != NULL) + if (link != NULL) { + // fixme insert fitter setup here + link->Train(target); -#endif + } pll_divisors divisors; compute_pll_divisors(target, &divisors, false); @@ -934,6 +933,7 @@ DisplayPort::_PortRegister() status_t DisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode) { + CALLED(); TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width, target->virtual_height); @@ -1095,6 +1095,7 @@ DigitalDisplayInterface::IsConnected() status_t DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode) { + CALLED(); TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width, target->virtual_height);