intel_extreme: add haswell/skylake PLL calcs, no functional change yet.
This commit is contained in:
parent
4106e3f146
commit
efde34c2fc
@ -512,7 +512,7 @@ struct intel_free_graphics_memory {
|
||||
#define LVDS_18BIT_DITHER (1UL << 25)
|
||||
#define LVDS_PORT_EN (1UL << 31)
|
||||
|
||||
// PLL flags
|
||||
// PLL flags (pre-DDI)
|
||||
#define DISPLAY_PLL_ENABLED (1UL << 31)
|
||||
#define DISPLAY_PLL_2X_CLOCK (1UL << 30)
|
||||
#define DISPLAY_PLL_SYNC_LOCK_ENABLED (1UL << 29)
|
||||
@ -540,6 +540,17 @@ struct intel_free_graphics_memory {
|
||||
#define DISPLAY_PLL_M2_DIVISOR_SHIFT 0
|
||||
#define DISPLAY_PLL_PULSE_PHASE_SHIFT 9
|
||||
|
||||
// Skylake PLLs
|
||||
#define SKL_DPLL1_CFGCR1 (0xc040 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define SKL_DPLL1_CFGCR2 (0xc044 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define SKL_DPLL2_CFGCR1 (0xc048 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#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)
|
||||
#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)
|
||||
|
||||
// display
|
||||
|
||||
#define INTEL_DISPLAY_OFFSET 0x1000
|
||||
|
@ -461,6 +461,17 @@ Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pipe::ConfigureClocksSKL(const skl_wrpll_params& wrpll_params, uint32 pixelClock,
|
||||
uint32 extraFlags)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void
|
||||
Pipe::Enable(bool enable)
|
||||
{
|
||||
|
@ -47,6 +47,10 @@ public:
|
||||
const pll_divisors& divisors,
|
||||
uint32 pixelClock,
|
||||
uint32 extraFlags);
|
||||
void ConfigureClocksSKL(
|
||||
const skl_wrpll_params& wrpll_params,
|
||||
uint32 pixelClock,
|
||||
uint32 extraFlags);
|
||||
|
||||
// access to the various parts of the pipe
|
||||
::FDILink* FDI()
|
||||
|
@ -1524,18 +1524,32 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
//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(
|
||||
target->timing.pixel_clock * 1000 /* in Hz */,
|
||||
&r2_out, &n2_out, &p_out);
|
||||
} else {
|
||||
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?
|
||||
&wrpll_params);
|
||||
fPipe->ConfigureClocksSKL(wrpll_params, target->timing.pixel_clock, 0);
|
||||
}
|
||||
|
||||
// Program target display mode
|
||||
fPipe->ConfigureTimings(target);
|
||||
|
@ -552,3 +552,485 @@ refclk_activate_ilk(bool hasPanel)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//excerpt (plus modifications) from intel_dpll_mgr.c:
|
||||
|
||||
/*
|
||||
* Copyright © 2006-2016 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define LC_FREQ 2700
|
||||
#define LC_FREQ_2K (uint64)(LC_FREQ * 2000)
|
||||
|
||||
#define P_MIN 2
|
||||
#define P_MAX 64
|
||||
#define P_INC 2
|
||||
|
||||
/* Constraints for PLL good behavior */
|
||||
#define REF_MIN 48
|
||||
#define REF_MAX 400
|
||||
#define VCO_MIN 2400
|
||||
#define VCO_MAX 4800
|
||||
|
||||
struct hsw_wrpll_rnp {
|
||||
unsigned p, n2, r2;
|
||||
};
|
||||
|
||||
static unsigned hsw_wrpll_get_budget_for_freq(int clock)
|
||||
{
|
||||
unsigned budget;
|
||||
|
||||
switch (clock) {
|
||||
case 25175000:
|
||||
case 25200000:
|
||||
case 27000000:
|
||||
case 27027000:
|
||||
case 37762500:
|
||||
case 37800000:
|
||||
case 40500000:
|
||||
case 40541000:
|
||||
case 54000000:
|
||||
case 54054000:
|
||||
case 59341000:
|
||||
case 59400000:
|
||||
case 72000000:
|
||||
case 74176000:
|
||||
case 74250000:
|
||||
case 81000000:
|
||||
case 81081000:
|
||||
case 89012000:
|
||||
case 89100000:
|
||||
case 108000000:
|
||||
case 108108000:
|
||||
case 111264000:
|
||||
case 111375000:
|
||||
case 148352000:
|
||||
case 148500000:
|
||||
case 162000000:
|
||||
case 162162000:
|
||||
case 222525000:
|
||||
case 222750000:
|
||||
case 296703000:
|
||||
case 297000000:
|
||||
budget = 0;
|
||||
break;
|
||||
case 233500000:
|
||||
case 245250000:
|
||||
case 247750000:
|
||||
case 253250000:
|
||||
case 298000000:
|
||||
budget = 1500;
|
||||
break;
|
||||
case 169128000:
|
||||
case 169500000:
|
||||
case 179500000:
|
||||
case 202000000:
|
||||
budget = 2000;
|
||||
break;
|
||||
case 256250000:
|
||||
case 262500000:
|
||||
case 270000000:
|
||||
case 272500000:
|
||||
case 273750000:
|
||||
case 280750000:
|
||||
case 281250000:
|
||||
case 286000000:
|
||||
case 291750000:
|
||||
budget = 4000;
|
||||
break;
|
||||
case 267250000:
|
||||
case 268500000:
|
||||
budget = 5000;
|
||||
break;
|
||||
default:
|
||||
budget = 1000;
|
||||
break;
|
||||
}
|
||||
|
||||
return budget;
|
||||
}
|
||||
|
||||
static void hsw_wrpll_update_rnp(uint64 freq2k, unsigned int budget,
|
||||
unsigned int r2, unsigned int n2,
|
||||
unsigned int p,
|
||||
struct hsw_wrpll_rnp *best)
|
||||
{
|
||||
uint64 a, b, c, d, diff, diff_best;
|
||||
|
||||
/* No best (r,n,p) yet */
|
||||
if (best->p == 0) {
|
||||
best->p = p;
|
||||
best->n2 = n2;
|
||||
best->r2 = r2;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
|
||||
* freq2k.
|
||||
*
|
||||
* delta = 1e6 *
|
||||
* abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
|
||||
* freq2k;
|
||||
*
|
||||
* and we would like delta <= budget.
|
||||
*
|
||||
* If the discrepancy is above the PPM-based budget, always prefer to
|
||||
* improve upon the previous solution. However, if you're within the
|
||||
* budget, try to maximize Ref * VCO, that is N / (P * R^2).
|
||||
*/
|
||||
a = freq2k * budget * p * r2;
|
||||
b = freq2k * budget * best->p * best->r2;
|
||||
diff = abs((uint64)freq2k * p * r2 - LC_FREQ_2K * n2);
|
||||
diff_best = abs((uint64)freq2k * best->p * best->r2 -
|
||||
LC_FREQ_2K * best->n2);
|
||||
c = 1000000 * diff;
|
||||
d = 1000000 * diff_best;
|
||||
|
||||
if (a < c && b < d) {
|
||||
/* If both are above the budget, pick the closer */
|
||||
if (best->p * best->r2 * diff < p * r2 * diff_best) {
|
||||
best->p = p;
|
||||
best->n2 = n2;
|
||||
best->r2 = r2;
|
||||
}
|
||||
} else if (a >= c && b < d) {
|
||||
/* If A is below the threshold but B is above it? Update. */
|
||||
best->p = p;
|
||||
best->n2 = n2;
|
||||
best->r2 = r2;
|
||||
} else if (a >= c && b >= d) {
|
||||
/* Both are below the limit, so pick the higher n2/(r2*r2) */
|
||||
if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) {
|
||||
best->p = p;
|
||||
best->n2 = n2;
|
||||
best->r2 = r2;
|
||||
}
|
||||
}
|
||||
/* Otherwise a < c && b >= d, do nothing */
|
||||
}
|
||||
|
||||
void
|
||||
hsw_ddi_calculate_wrpll(int clock /* in Hz */,
|
||||
unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
|
||||
{
|
||||
uint64 freq2k;
|
||||
unsigned p, n2, r2;
|
||||
struct hsw_wrpll_rnp best = { 0, 0, 0 };
|
||||
unsigned budget;
|
||||
|
||||
freq2k = clock / 100;
|
||||
|
||||
budget = hsw_wrpll_get_budget_for_freq(clock);
|
||||
|
||||
/* Special case handling for 540 pixel clock: bypass WR PLL entirely
|
||||
* and directly pass the LC PLL to it. */
|
||||
if (freq2k == 5400000) {
|
||||
*n2_out = 2;
|
||||
*p_out = 1;
|
||||
*r2_out = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ref = LC_FREQ / R, where Ref is the actual reference input seen by
|
||||
* the WR PLL.
|
||||
*
|
||||
* We want R so that REF_MIN <= Ref <= REF_MAX.
|
||||
* Injecting R2 = 2 * R gives:
|
||||
* REF_MAX * r2 > LC_FREQ * 2 and
|
||||
* REF_MIN * r2 < LC_FREQ * 2
|
||||
*
|
||||
* Which means the desired boundaries for r2 are:
|
||||
* LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
|
||||
*
|
||||
*/
|
||||
for (r2 = LC_FREQ * 2 / REF_MAX + 1;
|
||||
r2 <= LC_FREQ * 2 / REF_MIN;
|
||||
r2++) {
|
||||
|
||||
/*
|
||||
* VCO = N * Ref, that is: VCO = N * LC_FREQ / R
|
||||
*
|
||||
* Once again we want VCO_MIN <= VCO <= VCO_MAX.
|
||||
* Injecting R2 = 2 * R and N2 = 2 * N, we get:
|
||||
* VCO_MAX * r2 > n2 * LC_FREQ and
|
||||
* VCO_MIN * r2 < n2 * LC_FREQ)
|
||||
*
|
||||
* Which means the desired boundaries for n2 are:
|
||||
* VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
|
||||
*/
|
||||
for (n2 = VCO_MIN * r2 / LC_FREQ + 1;
|
||||
n2 <= VCO_MAX * r2 / LC_FREQ;
|
||||
n2++) {
|
||||
|
||||
for (p = P_MIN; p <= P_MAX; p += P_INC)
|
||||
hsw_wrpll_update_rnp(freq2k, budget,
|
||||
r2, n2, p, &best);
|
||||
}
|
||||
}
|
||||
|
||||
*n2_out = best.n2;
|
||||
*p_out = best.p;
|
||||
*r2_out = best.r2;
|
||||
}
|
||||
|
||||
struct skl_wrpll_context {
|
||||
uint64 min_deviation; /* current minimal deviation */
|
||||
uint64 central_freq; /* chosen central freq */
|
||||
uint64 dco_freq; /* chosen dco freq */
|
||||
unsigned int p; /* chosen divider */
|
||||
};
|
||||
|
||||
/* DCO freq must be within +1%/-6% of the DCO central freq */
|
||||
#define SKL_DCO_MAX_PDEVIATION 100
|
||||
#define SKL_DCO_MAX_NDEVIATION 600
|
||||
|
||||
static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
|
||||
uint64 central_freq,
|
||||
uint64 dco_freq,
|
||||
unsigned int divider)
|
||||
{
|
||||
uint64 deviation;
|
||||
|
||||
deviation = ((uint64)10000 * abs(dco_freq - central_freq)
|
||||
/ (uint64)central_freq);
|
||||
|
||||
/* positive deviation */
|
||||
if (dco_freq >= central_freq) {
|
||||
if (deviation < SKL_DCO_MAX_PDEVIATION &&
|
||||
deviation < ctx->min_deviation) {
|
||||
ctx->min_deviation = deviation;
|
||||
ctx->central_freq = central_freq;
|
||||
ctx->dco_freq = dco_freq;
|
||||
ctx->p = divider;
|
||||
}
|
||||
/* negative deviation */
|
||||
} else if (deviation < SKL_DCO_MAX_NDEVIATION &&
|
||||
deviation < ctx->min_deviation) {
|
||||
ctx->min_deviation = deviation;
|
||||
ctx->central_freq = central_freq;
|
||||
ctx->dco_freq = dco_freq;
|
||||
ctx->p = divider;
|
||||
}
|
||||
}
|
||||
|
||||
static void skl_wrpll_get_multipliers(unsigned int p,
|
||||
unsigned int *p0 /* out */,
|
||||
unsigned int *p1 /* out */,
|
||||
unsigned int *p2 /* out */)
|
||||
{
|
||||
/* even dividers */
|
||||
if (p % 2 == 0) {
|
||||
unsigned int half = p / 2;
|
||||
|
||||
if (half == 1 || half == 2 || half == 3 || half == 5) {
|
||||
*p0 = 2;
|
||||
*p1 = 1;
|
||||
*p2 = half;
|
||||
} else if (half % 2 == 0) {
|
||||
*p0 = 2;
|
||||
*p1 = half / 2;
|
||||
*p2 = 2;
|
||||
} else if (half % 3 == 0) {
|
||||
*p0 = 3;
|
||||
*p1 = half / 3;
|
||||
*p2 = 2;
|
||||
} else if (half % 7 == 0) {
|
||||
*p0 = 7;
|
||||
*p1 = half / 7;
|
||||
*p2 = 2;
|
||||
}
|
||||
} else if (p == 3 || p == 9) { /* 3, 5, 7, 9, 15, 21, 35 */
|
||||
*p0 = 3;
|
||||
*p1 = 1;
|
||||
*p2 = p / 3;
|
||||
} else if (p == 5 || p == 7) {
|
||||
*p0 = p;
|
||||
*p1 = 1;
|
||||
*p2 = 1;
|
||||
} else if (p == 15) {
|
||||
*p0 = 3;
|
||||
*p1 = 1;
|
||||
*p2 = 5;
|
||||
} else if (p == 21) {
|
||||
*p0 = 7;
|
||||
*p1 = 1;
|
||||
*p2 = 3;
|
||||
} else if (p == 35) {
|
||||
*p0 = 7;
|
||||
*p1 = 1;
|
||||
*p2 = 5;
|
||||
}
|
||||
}
|
||||
|
||||
static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->min_deviation = UINT64_MAX;
|
||||
}
|
||||
|
||||
static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
|
||||
uint64 afe_clock,
|
||||
int ref_clock,
|
||||
uint64 central_freq,
|
||||
uint32 p0, uint32 p1, uint32 p2)
|
||||
{
|
||||
uint64 dco_freq;
|
||||
|
||||
switch (central_freq) {
|
||||
case 9600000000ULL:
|
||||
params->central_freq = 0;
|
||||
break;
|
||||
case 9000000000ULL:
|
||||
params->central_freq = 1;
|
||||
break;
|
||||
case 8400000000ULL:
|
||||
params->central_freq = 3;
|
||||
}
|
||||
|
||||
switch (p0) {
|
||||
case 1:
|
||||
params->pdiv = 0;
|
||||
break;
|
||||
case 2:
|
||||
params->pdiv = 1;
|
||||
break;
|
||||
case 3:
|
||||
params->pdiv = 2;
|
||||
break;
|
||||
case 7:
|
||||
params->pdiv = 4;
|
||||
break;
|
||||
default:
|
||||
TRACE("%s: Incorrect PDiv\n", __func__);
|
||||
}
|
||||
|
||||
switch (p2) {
|
||||
case 5:
|
||||
params->kdiv = 0;
|
||||
break;
|
||||
case 2:
|
||||
params->kdiv = 1;
|
||||
break;
|
||||
case 3:
|
||||
params->kdiv = 2;
|
||||
break;
|
||||
case 1:
|
||||
params->kdiv = 3;
|
||||
break;
|
||||
default:
|
||||
TRACE("%s: Incorrect KDiv\n", __func__);
|
||||
}
|
||||
|
||||
params->qdiv_ratio = p1;
|
||||
params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
|
||||
|
||||
dco_freq = p0 * p1 * p2 * afe_clock;
|
||||
|
||||
/*
|
||||
* Intermediate values are in Hz.
|
||||
* Divide by MHz to match bsepc
|
||||
*/
|
||||
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) /
|
||||
1000000;
|
||||
}
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
bool
|
||||
skl_ddi_calculate_wrpll(int clock /* in Hz */,
|
||||
int ref_clock,
|
||||
struct skl_wrpll_params *wrpll_params)
|
||||
{
|
||||
uint64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
|
||||
uint64 dco_central_freq[3] = { 8400000000ULL,
|
||||
9000000000ULL,
|
||||
9600000000ULL };
|
||||
static const int even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20,
|
||||
24, 28, 30, 32, 36, 40, 42, 44,
|
||||
48, 52, 54, 56, 60, 64, 66, 68,
|
||||
70, 72, 76, 78, 80, 84, 88, 90,
|
||||
92, 96, 98 };
|
||||
static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
|
||||
static const struct {
|
||||
const int *list;
|
||||
unsigned int n_dividers;
|
||||
} dividers[] = {
|
||||
{ even_dividers, ARRAY_SIZE(even_dividers) },
|
||||
{ odd_dividers, ARRAY_SIZE(odd_dividers) },
|
||||
};
|
||||
struct skl_wrpll_context ctx;
|
||||
unsigned int dco, d, i;
|
||||
unsigned int p0, p1, p2;
|
||||
|
||||
skl_wrpll_context_init(&ctx);
|
||||
|
||||
for (d = 0; d < ARRAY_SIZE(dividers); d++) {
|
||||
for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
|
||||
for (i = 0; i < dividers[d].n_dividers; i++) {
|
||||
unsigned int p = dividers[d].list[i];
|
||||
uint64 dco_freq = p * afe_clock;
|
||||
|
||||
skl_wrpll_try_divider(&ctx,
|
||||
dco_central_freq[dco],
|
||||
dco_freq,
|
||||
p);
|
||||
/*
|
||||
* Skip the remaining dividers if we're sure to
|
||||
* have found the definitive divider, we can't
|
||||
* improve a 0 deviation.
|
||||
*/
|
||||
if (ctx.min_deviation == 0)
|
||||
goto skip_remaining_dividers;
|
||||
}
|
||||
}
|
||||
|
||||
skip_remaining_dividers:
|
||||
/*
|
||||
* If a solution is found with an even divider, prefer
|
||||
* this one.
|
||||
*/
|
||||
if (d == 0 && ctx.p)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ctx.p) {
|
||||
TRACE("%s: No valid divider found for %dHz\n", __func__, clock);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* gcc incorrectly analyses that these can be used without being
|
||||
* initialized. To be fair, it's hard to guess.
|
||||
*/
|
||||
p0 = p1 = p2 = 0;
|
||||
skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
|
||||
skl_wrpll_params_populate(wrpll_params, afe_clock, ref_clock,
|
||||
ctx.central_freq, p0, p1, p2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,15 @@ struct pll_limits {
|
||||
uint32 max_vco;
|
||||
};
|
||||
|
||||
struct skl_wrpll_params {
|
||||
uint32 dco_fraction;
|
||||
uint32 dco_integer;
|
||||
uint32 qdiv_ratio;
|
||||
uint32 qdiv_mode;
|
||||
uint32 kdiv;
|
||||
uint32 pdiv;
|
||||
uint32 central_freq;
|
||||
};
|
||||
|
||||
bool valid_pll_divisors(pll_divisors* divisors, pll_limits* limits);
|
||||
void compute_pll_divisors(display_timing* current, pll_divisors* divisors,
|
||||
@ -38,5 +47,9 @@ void compute_pll_divisors(display_timing* current, pll_divisors* divisors,
|
||||
|
||||
void refclk_activate_ilk(bool hasPanel);
|
||||
|
||||
void hsw_ddi_calculate_wrpll(int clock /* in Hz */,
|
||||
unsigned *r2_out, unsigned *n2_out, unsigned *p_out);
|
||||
bool skl_ddi_calculate_wrpll(int clock /* in Hz */,
|
||||
int ref_clock, struct skl_wrpll_params *wrpll_params);
|
||||
|
||||
#endif /* INTEL_EXTREME_PLL_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user