intel_extreme: skylake PLL works, all outputs fully functional.
This commit is contained in:
parent
4500c381d2
commit
39e05c7d01
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user