From 39e05c7d01484d9aed5438f0b4fef70f4f4728ff Mon Sep 17 00:00:00 2001 From: Rudolf Cornelissen Date: Thu, 25 Nov 2021 22:41:48 +0000 Subject: [PATCH] intel_extreme: skylake PLL works, all outputs fully functional. --- .../graphics/intel_extreme/intel_extreme.h | 9 +++ .../accelerants/intel_extreme/Pipes.cpp | 67 ++++++++++++++++++- src/add-ons/accelerants/intel_extreme/Pipes.h | 2 +- .../accelerants/intel_extreme/Ports.cpp | 16 ++--- src/add-ons/accelerants/intel_extreme/Ports.h | 9 --- src/add-ons/accelerants/intel_extreme/pll.cpp | 37 ++++++++-- 6 files changed, 112 insertions(+), 28 deletions(-) diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 71ad2b0330..c210dd4044 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -212,6 +212,15 @@ struct DeviceType { } }; +enum port_index { + INTEL_PORT_ANY, // wildcard for lookup functions + INTEL_PORT_A, + INTEL_PORT_B, + INTEL_PORT_C, + INTEL_PORT_D, + INTEL_PORT_E +}; + enum pch_info { INTEL_PCH_NONE = 0, // No PCH present INTEL_PCH_IBX, // Ibexpeak diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.cpp b/src/add-ons/accelerants/intel_extreme/Pipes.cpp index 08280b7194..e1f3b4c4a0 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.cpp +++ b/src/add-ons/accelerants/intel_extreme/Pipes.cpp @@ -463,10 +463,75 @@ Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock, void Pipe::ConfigureClocksSKL(const skl_wrpll_params& wrpll_params, uint32 pixelClock, - uint32 extraFlags) + port_index pllForPort) { CALLED(); + //find our PLL as set by the BIOS + uint32 portSel = read32(SKL_DPLL_CTRL2); + uint32 pllSel = 0; + switch (pllForPort) { + case INTEL_PORT_A: + pllSel = (portSel & 0x0006) >> 1; + break; + case INTEL_PORT_B: + pllSel = (portSel & 0x0030) >> 4; + break; + case INTEL_PORT_C: + pllSel = (portSel & 0x0180) >> 7; + break; + case INTEL_PORT_D: + pllSel = (portSel & 0x0c00) >> 10; + break; + case INTEL_PORT_E: + pllSel = (portSel & 0x6000) >> 13; + break; + default: + TRACE("No port selected!"); + return; + } + TRACE("PLL selected is %" B_PRIx32 "\n", pllSel); + + TRACE("Skylake DPLL_CFGCR1 0x%" B_PRIx32 "\n", + read32(SKL_DPLL1_CFGCR1 + (pllSel - 1) * 8)); + TRACE("Skylake DPLL_CFGCR2 0x%" B_PRIx32 "\n", + 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 + // enable pgm on our PLL in case that's currently disabled + write32(SKL_DPLL_CTRL1, portSel | (1 << (pllSel * 6))); + + 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, + 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); + + //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))) { + 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)); + TRACE("Skylake DPLL_CFGCR2 now: 0x%" B_PRIx32 "\n", + read32(SKL_DPLL1_CFGCR2 + (pllSel - 1) * 8)); + } else { + TRACE("PLL programming not needed, skipping.\n"); + } + TRACE("Skylake DPLL_CTRL1: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL1)); TRACE("Skylake DPLL_CTRL2: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL2)); TRACE("Skylake DPLL_STATUS: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_STATUS)); diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.h b/src/add-ons/accelerants/intel_extreme/Pipes.h index fcf160b08f..1c69805c4e 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.h +++ b/src/add-ons/accelerants/intel_extreme/Pipes.h @@ -50,7 +50,7 @@ public: void ConfigureClocksSKL( const skl_wrpll_params& wrpll_params, uint32 pixelClock, - uint32 extraFlags); + port_index pllForPort); // 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 f09b8f5531..1124b019c1 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -1527,16 +1527,6 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode) // Program general pipe config fPipe->Configure(target); - //pll_divisors divisors; - //compute_pll_divisors(&target->timing, &divisors, false); - - //uint32 extraPLLFlags = 0; - //if (gInfo->shared_info->device_type.Generation() >= 3) - // extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL | DISPLAY_PLL_2X_CLOCK; - - // Program pipe PLL's - //fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags); - if (gInfo->shared_info->device_type.Generation() <= 8) { unsigned int r2_out, n2_out, p_out; hsw_ddi_calculate_wrpll( @@ -1546,9 +1536,11 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode) skl_wrpll_params wrpll_params; skl_ddi_calculate_wrpll( target->timing.pixel_clock * 1000 /* in Hz */, - gInfo->shared_info->pll_info.reference_frequency,//fixme Hz? kHz? + 24000,//gInfo->shared_info->pll_info.reference_frequency, //fixme &wrpll_params); - fPipe->ConfigureClocksSKL(wrpll_params, target->timing.pixel_clock, 0); + fPipe->ConfigureClocksSKL(wrpll_params, + target->timing.pixel_clock, + PortIndex()); } // Program target display mode diff --git a/src/add-ons/accelerants/intel_extreme/Ports.h b/src/add-ons/accelerants/intel_extreme/Ports.h index e69beaf6eb..de4ac1eb1d 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.h +++ b/src/add-ons/accelerants/intel_extreme/Ports.h @@ -32,15 +32,6 @@ enum port_type { INTEL_PORT_TYPE_HDMI }; -enum port_index { - INTEL_PORT_ANY, // wildcard for lookup functions - INTEL_PORT_A, - INTEL_PORT_B, - INTEL_PORT_C, - INTEL_PORT_D, - INTEL_PORT_E -}; - class Port { public: diff --git a/src/add-ons/accelerants/intel_extreme/pll.cpp b/src/add-ons/accelerants/intel_extreme/pll.cpp index ed765b6da7..a04e8e4d15 100644 --- a/src/add-ons/accelerants/intel_extreme/pll.cpp +++ b/src/add-ons/accelerants/intel_extreme/pll.cpp @@ -591,6 +591,15 @@ refclk_activate_ilk(bool hasPanel) #define VCO_MIN 2400 #define VCO_MAX 4800 +static uint64 AbsSubtr64(uint64 nr1, uint64 nr2) +{ + if (nr1 >= nr2) { + return nr1 - nr2; + } else { + return nr2 - nr1; + } +} + struct hsw_wrpll_rnp { unsigned p, n2, r2; }; @@ -700,8 +709,8 @@ static void hsw_wrpll_update_rnp(uint64 freq2k, unsigned int budget, */ a = freq2k * budget * p * r2; b = freq2k * budget * best->p * best->r2; - diff = labs((uint64)freq2k * p * r2 - LC_FREQ_2K * n2); - diff_best = labs((uint64)freq2k * best->p * best->r2 - + diff = AbsSubtr64((uint64)freq2k * p * r2, LC_FREQ_2K * n2); + diff_best = AbsSubtr64((uint64)freq2k * best->p * best->r2, LC_FREQ_2K * best->n2); c = 1000000 * diff; d = 1000000 * diff_best; @@ -812,8 +821,8 @@ static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx, { uint64 deviation; - deviation = ((uint64)10000 * labs(dco_freq - central_freq) - / (uint64)central_freq); + deviation = ((uint64)10000 * AbsSubtr64(dco_freq, central_freq) + / central_freq); /* positive deviation */ if (dco_freq >= central_freq) { @@ -823,6 +832,11 @@ static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx, ctx->central_freq = central_freq; ctx->dco_freq = dco_freq; ctx->p = divider; + + TRACE("%s: DCO central frequency %" B_PRIu64 "Hz\n", __func__, central_freq); + TRACE("%s: DCO frequency %" B_PRIu64 "Hz\n", __func__, dco_freq); + TRACE("%s: positive offset accepted, deviation %" B_PRIu64 "\n", + __func__, deviation); } /* negative deviation */ } else if (deviation < SKL_DCO_MAX_NDEVIATION && @@ -831,6 +845,11 @@ static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx, ctx->central_freq = central_freq; ctx->dco_freq = dco_freq; ctx->p = divider; + + TRACE("%s: DCO central frequency %" B_PRIu64 "Hz\n", __func__, central_freq); + TRACE("%s: DCO frequency %" B_PRIu64 "Hz\n", __func__, dco_freq); + TRACE("%s: negative offset accepted, deviation %" B_PRIu64 "\n", + __func__, deviation); } } @@ -946,6 +965,10 @@ static void skl_wrpll_params_populate(struct skl_wrpll_params *params, params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1; dco_freq = p0 * p1 * p2 * afe_clock; + TRACE("%s: AFE frequency %" B_PRIu64 "Hz\n", __func__, afe_clock); + TRACE("%s: p0: %" B_PRIu32 ", p1: %" B_PRIu32 ", p2: %" B_PRIu32 "\n", + __func__, p0,p1,p2); + TRACE("%s: DCO frequency %" B_PRIu64 "Hz\n", __func__, dco_freq); /* * Intermediate values are in Hz. @@ -954,8 +977,11 @@ static void skl_wrpll_params_populate(struct skl_wrpll_params *params, params->dco_integer = (uint64)dco_freq / ((uint64)ref_clock * 1000); params->dco_fraction = ( (uint64)dco_freq / ((uint64)ref_clock / 1000) - - (uint64)params->dco_integer * 1000000 * 0x8000) / + (uint64)params->dco_integer * 1000000) * 0x8000 / 1000000; + + TRACE("%s: DCO integer %" B_PRIu32 "\n", __func__, params->dco_integer); + TRACE("%s: DCO fraction 0x%" B_PRIx32 "\n", __func__, params->dco_fraction); } #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -1021,6 +1047,7 @@ skip_remaining_dividers: TRACE("%s: No valid divider found for %dHz\n", __func__, clock); return false; } + TRACE("%s: Full devider (p) found is %d\n", __func__, ctx.p); /* * gcc incorrectly analyses that these can be used without being