drm/i915: Move SKL/KLB pll selection logic to intel_dpll_mgr.c
Move the code for selecting plls for SKL/KLB into the shared dpll code, so that the platform specific details are hidden behind that interface. Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1457451987-17466-11-git-send-email-ander.conselvan.de.oliveira@intel.com
This commit is contained in:
parent
daedf20a4f
commit
304b65cbdc
|
@ -1005,311 +1005,15 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct skl_wrpll_context {
|
|
||||||
uint64_t min_deviation; /* current minimal deviation */
|
|
||||||
uint64_t central_freq; /* chosen central freq */
|
|
||||||
uint64_t dco_freq; /* chosen dco freq */
|
|
||||||
unsigned int p; /* chosen divider */
|
|
||||||
};
|
|
||||||
|
|
||||||
static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
|
|
||||||
{
|
|
||||||
memset(ctx, 0, sizeof(*ctx));
|
|
||||||
|
|
||||||
ctx->min_deviation = U64_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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_t central_freq,
|
|
||||||
uint64_t dco_freq,
|
|
||||||
unsigned int divider)
|
|
||||||
{
|
|
||||||
uint64_t deviation;
|
|
||||||
|
|
||||||
deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct skl_wrpll_params {
|
|
||||||
uint32_t dco_fraction;
|
|
||||||
uint32_t dco_integer;
|
|
||||||
uint32_t qdiv_ratio;
|
|
||||||
uint32_t qdiv_mode;
|
|
||||||
uint32_t kdiv;
|
|
||||||
uint32_t pdiv;
|
|
||||||
uint32_t central_freq;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
|
|
||||||
uint64_t afe_clock,
|
|
||||||
uint64_t central_freq,
|
|
||||||
uint32_t p0, uint32_t p1, uint32_t p2)
|
|
||||||
{
|
|
||||||
uint64_t 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:
|
|
||||||
WARN(1, "Incorrect PDiv\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
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:
|
|
||||||
WARN(1, "Incorrect KDiv\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = div_u64(dco_freq, 24 * MHz(1));
|
|
||||||
params->dco_fraction =
|
|
||||||
div_u64((div_u64(dco_freq, 24) -
|
|
||||||
params->dco_integer * MHz(1)) * 0x8000, MHz(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
skl_ddi_calculate_wrpll(int clock /* in Hz */,
|
|
||||||
struct skl_wrpll_params *wrpll_params)
|
|
||||||
{
|
|
||||||
uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
|
|
||||||
uint64_t 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;
|
|
||||||
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_t 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) {
|
|
||||||
DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", 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, ctx.central_freq,
|
|
||||||
p0, p1, p2);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
skl_ddi_pll_select(struct intel_crtc *intel_crtc,
|
skl_ddi_pll_select(struct intel_crtc *intel_crtc,
|
||||||
struct intel_crtc_state *crtc_state,
|
struct intel_crtc_state *crtc_state,
|
||||||
struct intel_encoder *intel_encoder)
|
struct intel_encoder *intel_encoder)
|
||||||
{
|
{
|
||||||
struct intel_shared_dpll *pll;
|
struct intel_shared_dpll *pll;
|
||||||
uint32_t ctrl1, cfgcr1, cfgcr2;
|
|
||||||
int clock = crtc_state->port_clock;
|
|
||||||
|
|
||||||
/*
|
if (intel_encoder->type == INTEL_OUTPUT_EDP)
|
||||||
* See comment in intel_dpll_hw_state to understand why we always use 0
|
|
||||||
* as the DPLL id in this function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ctrl1 = DPLL_CTRL1_OVERRIDE(0);
|
|
||||||
|
|
||||||
if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
|
|
||||||
struct skl_wrpll_params wrpll_params = { 0, };
|
|
||||||
|
|
||||||
ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
|
|
||||||
|
|
||||||
if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
|
|
||||||
DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
|
|
||||||
wrpll_params.dco_integer;
|
|
||||||
|
|
||||||
cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
|
|
||||||
DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
|
|
||||||
DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
|
|
||||||
DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
|
|
||||||
wrpll_params.central_freq;
|
|
||||||
} else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
|
|
||||||
intel_encoder->type == INTEL_OUTPUT_DP_MST) {
|
|
||||||
switch (crtc_state->port_clock / 2) {
|
|
||||||
case 81000:
|
|
||||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
|
|
||||||
break;
|
|
||||||
case 135000:
|
|
||||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
|
|
||||||
break;
|
|
||||||
case 270000:
|
|
||||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfgcr1 = cfgcr2 = 0;
|
|
||||||
} else if (intel_encoder->type == INTEL_OUTPUT_EDP) {
|
|
||||||
return true;
|
return true;
|
||||||
} else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
memset(&crtc_state->dpll_hw_state, 0,
|
|
||||||
sizeof(crtc_state->dpll_hw_state));
|
|
||||||
|
|
||||||
crtc_state->dpll_hw_state.ctrl1 = ctrl1;
|
|
||||||
crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
|
|
||||||
crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
|
|
||||||
|
|
||||||
pll = intel_get_shared_dpll(intel_crtc, crtc_state, intel_encoder);
|
pll = intel_get_shared_dpll(intel_crtc, crtc_state, intel_encoder);
|
||||||
if (pll == NULL) {
|
if (pll == NULL) {
|
||||||
|
@ -1318,9 +1022,6 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shared DPLL id 0 is DPLL 1 */
|
|
||||||
crtc_state->ddi_pll_sel = pll->id + 1;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -837,15 +837,318 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct skl_wrpll_context {
|
||||||
|
uint64_t min_deviation; /* current minimal deviation */
|
||||||
|
uint64_t central_freq; /* chosen central freq */
|
||||||
|
uint64_t dco_freq; /* chosen dco freq */
|
||||||
|
unsigned int p; /* chosen divider */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
|
||||||
|
{
|
||||||
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
|
|
||||||
|
ctx->min_deviation = U64_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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_t central_freq,
|
||||||
|
uint64_t dco_freq,
|
||||||
|
unsigned int divider)
|
||||||
|
{
|
||||||
|
uint64_t deviation;
|
||||||
|
|
||||||
|
deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct skl_wrpll_params {
|
||||||
|
uint32_t dco_fraction;
|
||||||
|
uint32_t dco_integer;
|
||||||
|
uint32_t qdiv_ratio;
|
||||||
|
uint32_t qdiv_mode;
|
||||||
|
uint32_t kdiv;
|
||||||
|
uint32_t pdiv;
|
||||||
|
uint32_t central_freq;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
|
||||||
|
uint64_t afe_clock,
|
||||||
|
uint64_t central_freq,
|
||||||
|
uint32_t p0, uint32_t p1, uint32_t p2)
|
||||||
|
{
|
||||||
|
uint64_t 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:
|
||||||
|
WARN(1, "Incorrect PDiv\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
WARN(1, "Incorrect KDiv\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = div_u64(dco_freq, 24 * MHz(1));
|
||||||
|
params->dco_fraction =
|
||||||
|
div_u64((div_u64(dco_freq, 24) -
|
||||||
|
params->dco_integer * MHz(1)) * 0x8000, MHz(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
skl_ddi_calculate_wrpll(int clock /* in Hz */,
|
||||||
|
struct skl_wrpll_params *wrpll_params)
|
||||||
|
{
|
||||||
|
uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
|
||||||
|
uint64_t 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;
|
||||||
|
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_t 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) {
|
||||||
|
DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", 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, ctx.central_freq,
|
||||||
|
p0, p1, p2);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static struct intel_shared_dpll *
|
static struct intel_shared_dpll *
|
||||||
skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||||
struct intel_encoder *encoder)
|
struct intel_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct intel_shared_dpll *pll;
|
struct intel_shared_dpll *pll;
|
||||||
|
uint32_t ctrl1, cfgcr1, cfgcr2;
|
||||||
|
int clock = crtc_state->port_clock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See comment in intel_dpll_hw_state to understand why we always use 0
|
||||||
|
* as the DPLL id in this function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ctrl1 = DPLL_CTRL1_OVERRIDE(0);
|
||||||
|
|
||||||
|
if (encoder->type == INTEL_OUTPUT_HDMI) {
|
||||||
|
struct skl_wrpll_params wrpll_params = { 0, };
|
||||||
|
|
||||||
|
ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
|
||||||
|
|
||||||
|
if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
|
||||||
|
DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
|
||||||
|
wrpll_params.dco_integer;
|
||||||
|
|
||||||
|
cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
|
||||||
|
DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
|
||||||
|
DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
|
||||||
|
DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
|
||||||
|
wrpll_params.central_freq;
|
||||||
|
} else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
|
||||||
|
encoder->type == INTEL_OUTPUT_DP_MST) {
|
||||||
|
switch (crtc_state->port_clock / 2) {
|
||||||
|
case 81000:
|
||||||
|
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
|
||||||
|
break;
|
||||||
|
case 135000:
|
||||||
|
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
|
||||||
|
break;
|
||||||
|
case 270000:
|
||||||
|
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgcr1 = cfgcr2 = 0;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&crtc_state->dpll_hw_state, 0,
|
||||||
|
sizeof(crtc_state->dpll_hw_state));
|
||||||
|
|
||||||
|
crtc_state->dpll_hw_state.ctrl1 = ctrl1;
|
||||||
|
crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
|
||||||
|
crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
|
||||||
|
|
||||||
pll = intel_find_shared_dpll(crtc, crtc_state,
|
pll = intel_find_shared_dpll(crtc, crtc_state,
|
||||||
DPLL_ID_SKL_DPLL1, DPLL_ID_SKL_DPLL3);
|
DPLL_ID_SKL_DPLL1, DPLL_ID_SKL_DPLL3);
|
||||||
if (pll)
|
if (!pll)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* shared DPLL id 0 is DPLL 1 */
|
||||||
|
crtc_state->ddi_pll_sel = pll->id + 1;
|
||||||
|
|
||||||
intel_reference_shared_dpll(pll, crtc_state);
|
intel_reference_shared_dpll(pll, crtc_state);
|
||||||
|
|
||||||
return pll;
|
return pll;
|
||||||
|
|
Loading…
Reference in New Issue