intel_extreme: skylake PLL works, all outputs fully functional.

This commit is contained in:
Rudolf Cornelissen 2021-11-25 22:41:48 +00:00
parent 4500c381d2
commit 39e05c7d01
6 changed files with 112 additions and 28 deletions

View File

@ -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

View File

@ -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));

View File

@ -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()

View File

@ -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

View File

@ -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:

View File

@ -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