intel_extreme: skylake PLL works, all outputs fully functional.
This commit is contained in:
@@ -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 {
|
enum pch_info {
|
||||||
INTEL_PCH_NONE = 0, // No PCH present
|
INTEL_PCH_NONE = 0, // No PCH present
|
||||||
INTEL_PCH_IBX, // Ibexpeak
|
INTEL_PCH_IBX, // Ibexpeak
|
||||||
|
|||||||
@@ -463,10 +463,75 @@ Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock,
|
|||||||
|
|
||||||
void
|
void
|
||||||
Pipe::ConfigureClocksSKL(const skl_wrpll_params& wrpll_params, uint32 pixelClock,
|
Pipe::ConfigureClocksSKL(const skl_wrpll_params& wrpll_params, uint32 pixelClock,
|
||||||
uint32 extraFlags)
|
port_index pllForPort)
|
||||||
{
|
{
|
||||||
CALLED();
|
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_CTRL1: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL1));
|
||||||
TRACE("Skylake DPLL_CTRL2: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL2));
|
TRACE("Skylake DPLL_CTRL2: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL2));
|
||||||
TRACE("Skylake DPLL_STATUS: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_STATUS));
|
TRACE("Skylake DPLL_STATUS: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_STATUS));
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public:
|
|||||||
void ConfigureClocksSKL(
|
void ConfigureClocksSKL(
|
||||||
const skl_wrpll_params& wrpll_params,
|
const skl_wrpll_params& wrpll_params,
|
||||||
uint32 pixelClock,
|
uint32 pixelClock,
|
||||||
uint32 extraFlags);
|
port_index pllForPort);
|
||||||
|
|
||||||
// access to the various parts of the pipe
|
// access to the various parts of the pipe
|
||||||
::FDILink* FDI()
|
::FDILink* FDI()
|
||||||
|
|||||||
@@ -1527,16 +1527,6 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
|
|||||||
// Program general pipe config
|
// Program general pipe config
|
||||||
fPipe->Configure(target);
|
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) {
|
if (gInfo->shared_info->device_type.Generation() <= 8) {
|
||||||
unsigned int r2_out, n2_out, p_out;
|
unsigned int r2_out, n2_out, p_out;
|
||||||
hsw_ddi_calculate_wrpll(
|
hsw_ddi_calculate_wrpll(
|
||||||
@@ -1546,9 +1536,11 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
|
|||||||
skl_wrpll_params wrpll_params;
|
skl_wrpll_params wrpll_params;
|
||||||
skl_ddi_calculate_wrpll(
|
skl_ddi_calculate_wrpll(
|
||||||
target->timing.pixel_clock * 1000 /* in Hz */,
|
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);
|
&wrpll_params);
|
||||||
fPipe->ConfigureClocksSKL(wrpll_params, target->timing.pixel_clock, 0);
|
fPipe->ConfigureClocksSKL(wrpll_params,
|
||||||
|
target->timing.pixel_clock,
|
||||||
|
PortIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Program target display mode
|
// Program target display mode
|
||||||
|
|||||||
@@ -32,15 +32,6 @@ enum port_type {
|
|||||||
INTEL_PORT_TYPE_HDMI
|
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 {
|
class Port {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -591,6 +591,15 @@ refclk_activate_ilk(bool hasPanel)
|
|||||||
#define VCO_MIN 2400
|
#define VCO_MIN 2400
|
||||||
#define VCO_MAX 4800
|
#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 {
|
struct hsw_wrpll_rnp {
|
||||||
unsigned p, n2, r2;
|
unsigned p, n2, r2;
|
||||||
};
|
};
|
||||||
@@ -700,8 +709,8 @@ static void hsw_wrpll_update_rnp(uint64 freq2k, unsigned int budget,
|
|||||||
*/
|
*/
|
||||||
a = freq2k * budget * p * r2;
|
a = freq2k * budget * p * r2;
|
||||||
b = freq2k * budget * best->p * best->r2;
|
b = freq2k * budget * best->p * best->r2;
|
||||||
diff = labs((uint64)freq2k * p * r2 - LC_FREQ_2K * n2);
|
diff = AbsSubtr64((uint64)freq2k * p * r2, LC_FREQ_2K * n2);
|
||||||
diff_best = labs((uint64)freq2k * best->p * best->r2 -
|
diff_best = AbsSubtr64((uint64)freq2k * best->p * best->r2,
|
||||||
LC_FREQ_2K * best->n2);
|
LC_FREQ_2K * best->n2);
|
||||||
c = 1000000 * diff;
|
c = 1000000 * diff;
|
||||||
d = 1000000 * diff_best;
|
d = 1000000 * diff_best;
|
||||||
@@ -812,8 +821,8 @@ static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
|
|||||||
{
|
{
|
||||||
uint64 deviation;
|
uint64 deviation;
|
||||||
|
|
||||||
deviation = ((uint64)10000 * labs(dco_freq - central_freq)
|
deviation = ((uint64)10000 * AbsSubtr64(dco_freq, central_freq)
|
||||||
/ (uint64)central_freq);
|
/ central_freq);
|
||||||
|
|
||||||
/* positive deviation */
|
/* positive deviation */
|
||||||
if (dco_freq >= central_freq) {
|
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->central_freq = central_freq;
|
||||||
ctx->dco_freq = dco_freq;
|
ctx->dco_freq = dco_freq;
|
||||||
ctx->p = divider;
|
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 */
|
/* negative deviation */
|
||||||
} else if (deviation < SKL_DCO_MAX_NDEVIATION &&
|
} 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->central_freq = central_freq;
|
||||||
ctx->dco_freq = dco_freq;
|
ctx->dco_freq = dco_freq;
|
||||||
ctx->p = divider;
|
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;
|
params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
|
||||||
|
|
||||||
dco_freq = p0 * p1 * p2 * afe_clock;
|
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.
|
* 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_integer = (uint64)dco_freq / ((uint64)ref_clock * 1000);
|
||||||
params->dco_fraction = (
|
params->dco_fraction = (
|
||||||
(uint64)dco_freq / ((uint64)ref_clock / 1000) -
|
(uint64)dco_freq / ((uint64)ref_clock / 1000) -
|
||||||
(uint64)params->dco_integer * 1000000 * 0x8000) /
|
(uint64)params->dco_integer * 1000000) * 0x8000 /
|
||||||
1000000;
|
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]))
|
#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);
|
TRACE("%s: No valid divider found for %dHz\n", __func__, clock);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
TRACE("%s: Full devider (p) found is %d\n", __func__, ctx.p);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gcc incorrectly analyses that these can be used without being
|
* gcc incorrectly analyses that these can be used without being
|
||||||
|
|||||||
Reference in New Issue
Block a user