diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index a3b18c0ffc..a757ea6430 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -612,9 +612,21 @@ struct intel_free_graphics_memory { #define SKL_DPLL2_CFGCR2 (0xc04c | REGS_NORTH_PIPE_AND_PORT) #define SKL_DPLL3_CFGCR1 (0xc050 | REGS_NORTH_PIPE_AND_PORT) #define SKL_DPLL3_CFGCR2 (0xc054 | REGS_NORTH_PIPE_AND_PORT) +// These exist also still in CoffeeLake (confirmed): #define SKL_DPLL_CTRL1 (0xc058 | REGS_NORTH_PIPE_AND_PORT) #define SKL_DPLL_CTRL2 (0xc05c | REGS_NORTH_PIPE_AND_PORT) #define SKL_DPLL_STATUS (0xc060 | REGS_NORTH_PIPE_AND_PORT) +#define SKL_DPLL0_DP_LINKRATE_SHIFT 1 +#define SKL_DPLL1_DP_LINKRATE_SHIFT 7 +#define SKL_DPLL2_DP_LINKRATE_SHIFT 13 +#define SKL_DPLL3_DP_LINKRATE_SHIFT 19 +#define SKL_DPLL_DP_LINKRATE_MASK 7 +#define SKL_DPLL_CTRL1_2700 0 +#define SKL_DPLL_CTRL1_1350 1 +#define SKL_DPLL_CTRL1_810 2 +#define SKL_DPLL_CTRL1_1620 3 +#define SKL_DPLL_CTRL1_1080 4 +#define SKL_DPLL_CTRL1_2160 5 // Icelake PLLs #define ICL_DSSM 0x51004 diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.cpp b/src/add-ons/accelerants/intel_extreme/Pipes.cpp index e1f3b4c4a0..ba3233de2c 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.cpp +++ b/src/add-ons/accelerants/intel_extreme/Pipes.cpp @@ -463,71 +463,71 @@ Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock, void Pipe::ConfigureClocksSKL(const skl_wrpll_params& wrpll_params, uint32 pixelClock, - port_index pllForPort) + port_index pllForPort, uint32* pllSel) { CALLED(); //find our PLL as set by the BIOS uint32 portSel = read32(SKL_DPLL_CTRL2); - uint32 pllSel = 0; + *pllSel = 0xff; switch (pllForPort) { case INTEL_PORT_A: - pllSel = (portSel & 0x0006) >> 1; + *pllSel = (portSel & 0x0006) >> 1; break; case INTEL_PORT_B: - pllSel = (portSel & 0x0030) >> 4; + *pllSel = (portSel & 0x0030) >> 4; break; case INTEL_PORT_C: - pllSel = (portSel & 0x0180) >> 7; + *pllSel = (portSel & 0x0180) >> 7; break; case INTEL_PORT_D: - pllSel = (portSel & 0x0c00) >> 10; + *pllSel = (portSel & 0x0c00) >> 10; break; case INTEL_PORT_E: - pllSel = (portSel & 0x6000) >> 13; + *pllSel = (portSel & 0x6000) >> 13; break; default: TRACE("No port selected!"); return; } - TRACE("PLL selected is %" B_PRIx32 "\n", pllSel); + TRACE("PLL selected is %" B_PRIx32 "\n", *pllSel); TRACE("Skylake DPLL_CFGCR1 0x%" B_PRIx32 "\n", - read32(SKL_DPLL1_CFGCR1 + (pllSel - 1) * 8)); + read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8)); TRACE("Skylake DPLL_CFGCR2 0x%" B_PRIx32 "\n", - read32(SKL_DPLL1_CFGCR2 + (pllSel - 1) * 8)); + read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8)); // only program PLL's that are in non-DP mode (otherwise the linkspeed sets refresh) portSel = read32(SKL_DPLL_CTRL1); - if ((portSel & (1 << (pllSel * 6 + 5))) && pllSel) { // DPLL0 might only know DP mode + if ((portSel & (1 << (*pllSel * 6 + 5))) && *pllSel) { // DPLL0 might only know DP mode // enable pgm on our PLL in case that's currently disabled - write32(SKL_DPLL_CTRL1, portSel | (1 << (pllSel * 6))); + write32(SKL_DPLL_CTRL1, portSel | (1 << (*pllSel * 6))); - write32(SKL_DPLL1_CFGCR1 + (pllSel - 1) * 8, + write32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8, 1 << 31 | wrpll_params.dco_fraction << 9 | wrpll_params.dco_integer); - write32(SKL_DPLL1_CFGCR2 + (pllSel - 1) * 8, + write32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8, wrpll_params.qdiv_ratio << 8 | wrpll_params.qdiv_mode << 7 | wrpll_params.kdiv << 5 | wrpll_params.pdiv << 2 | wrpll_params.central_freq); - read32(SKL_DPLL1_CFGCR1 + (pllSel - 1) * 8); - read32(SKL_DPLL1_CFGCR2 + (pllSel - 1) * 8); + read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8); + read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8); //assuming DPLL0 and 1 are already enabled by the BIOS if in use (LCPLL1,2 regs) spin(5); - if (read32(SKL_DPLL_STATUS) & (1 << (pllSel * 8))) { + if (read32(SKL_DPLL_STATUS) & (1 << (*pllSel * 8))) { TRACE("Programmed PLL; PLL is locked\n"); } else { TRACE("Programmed PLL; PLL did not lock\n"); } TRACE("Skylake DPLL_CFGCR1 now: 0x%" B_PRIx32 "\n", - read32(SKL_DPLL1_CFGCR1 + (pllSel - 1) * 8)); + read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8)); TRACE("Skylake DPLL_CFGCR2 now: 0x%" B_PRIx32 "\n", - read32(SKL_DPLL1_CFGCR2 + (pllSel - 1) * 8)); + read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8)); } else { TRACE("PLL programming not needed, skipping.\n"); } diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.h b/src/add-ons/accelerants/intel_extreme/Pipes.h index 1c69805c4e..ade27f7030 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.h +++ b/src/add-ons/accelerants/intel_extreme/Pipes.h @@ -50,7 +50,8 @@ public: void ConfigureClocksSKL( const skl_wrpll_params& wrpll_params, uint32 pixelClock, - port_index pllForPort); + port_index pllForPort, + uint32* pllSel); // access to the various parts of the pipe ::FDILink* FDI() diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index 00006fb8b1..66792a8347 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -1449,13 +1449,43 @@ DigitalDisplayInterface::IsConnected() } status_t -DigitalDisplayInterface::_SetPortLinkGen8(const display_timing& timing) +DigitalDisplayInterface::_SetPortLinkGen8(const display_timing& timing, uint32 pllSel) { - // Khz / 10. ( each output octet encoded as 10 bits. - //uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10; //=270000 khz - //fixme: always so? + //fixme: always so on pre gen 9? uint32 linkBandwidth = 270000; //khz + if (gInfo->shared_info->device_type.Generation() >= 9) { + if (pllSel != 0xff) { + linkBandwidth = (read32(SKL_DPLL_CTRL1) >> (1 + 6 * pllSel)) & SKL_DPLL_DP_LINKRATE_MASK; + switch (linkBandwidth) { + case SKL_DPLL_CTRL1_2700: + linkBandwidth = 2700000 / 5; + break; + case SKL_DPLL_CTRL1_1350: + linkBandwidth = 1350000 / 5; + break; + case SKL_DPLL_CTRL1_810: + linkBandwidth = 810000 / 5; + break; + case SKL_DPLL_CTRL1_1620: + linkBandwidth = 1620000 / 5; + break; + case SKL_DPLL_CTRL1_1080: + linkBandwidth = 1080000 / 5; + break; + case SKL_DPLL_CTRL1_2160: + linkBandwidth = 2160000 / 5; + break; + default: + ERROR("%s: DDI No known DP-link reference clock selected, assuming default\n", __func__); + break; + } + } else { + ERROR("%s: DDI No known PLL selected, assuming default DP-link reference\n", __func__); + } + } + TRACE("%s: DDI DP-link reference clock is %gMhz\n", __func__, linkBandwidth / 1000.0f); + uint32 fPipeOffset = 0; switch (fPipe->Index()) { case INTEL_PIPE_B: @@ -1609,6 +1639,7 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode) // Program general pipe config fPipe->Configure(target); + uint32 pllSel = 0xff; // no PLL selected if (gInfo->shared_info->device_type.Generation() <= 8) { unsigned int r2_out, n2_out, p_out; hsw_ddi_calculate_wrpll( @@ -1622,12 +1653,13 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode) &wrpll_params); fPipe->ConfigureClocksSKL(wrpll_params, hardwareTarget.pixel_clock, - PortIndex()); + PortIndex(), + &pllSel); } // Program target display mode fPipe->ConfigureTimings(target, !needsScaling); - _SetPortLinkGen8(hardwareTarget); + _SetPortLinkGen8(hardwareTarget, pllSel); // Set fCurrentMode to our set display mode memcpy(&fCurrentMode, target, sizeof(display_mode)); diff --git a/src/add-ons/accelerants/intel_extreme/Ports.h b/src/add-ons/accelerants/intel_extreme/Ports.h index 4f4673a712..02a57ba16d 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.h +++ b/src/add-ons/accelerants/intel_extreme/Ports.h @@ -218,7 +218,8 @@ virtual addr_t _PortRegister(); private: uint8 fMaxLanes; - status_t _SetPortLinkGen8(const display_timing& timing); + status_t _SetPortLinkGen8(const display_timing& timing, + uint32 pllSel); };