Commit b41df85a authored by Ville Syrjälä's avatar Ville Syrjälä

drm/i915: Extract some helpers to compute cdclk register values

Extract a few of the switch statements into helper functions to
reduce the pollution in the cdclk programming functions.
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210430153444.29270-2-ville.syrjala@linux.intel.comReviewed-by: default avatarJani Nikula <jani.nikula@intel.com>
parent fcf83a21
...@@ -724,6 +724,23 @@ static void bdw_get_cdclk(struct drm_i915_private *dev_priv, ...@@ -724,6 +724,23 @@ static void bdw_get_cdclk(struct drm_i915_private *dev_priv,
bdw_calc_voltage_level(cdclk_config->cdclk); bdw_calc_voltage_level(cdclk_config->cdclk);
} }
static u32 bdw_cdclk_freq_sel(int cdclk)
{
switch (cdclk) {
default:
MISSING_CASE(cdclk);
fallthrough;
case 337500:
return LCPLL_CLK_FREQ_337_5_BDW;
case 450000:
return LCPLL_CLK_FREQ_450;
case 540000:
return LCPLL_CLK_FREQ_54O_BDW;
case 675000:
return LCPLL_CLK_FREQ_675_BDW;
}
}
static void bdw_set_cdclk(struct drm_i915_private *dev_priv, static void bdw_set_cdclk(struct drm_i915_private *dev_priv,
const struct intel_cdclk_config *cdclk_config, const struct intel_cdclk_config *cdclk_config,
enum pipe pipe) enum pipe pipe)
...@@ -763,25 +780,7 @@ static void bdw_set_cdclk(struct drm_i915_private *dev_priv, ...@@ -763,25 +780,7 @@ static void bdw_set_cdclk(struct drm_i915_private *dev_priv,
val = intel_de_read(dev_priv, LCPLL_CTL); val = intel_de_read(dev_priv, LCPLL_CTL);
val &= ~LCPLL_CLK_FREQ_MASK; val &= ~LCPLL_CLK_FREQ_MASK;
val |= bdw_cdclk_freq_sel(cdclk);
switch (cdclk) {
default:
MISSING_CASE(cdclk);
fallthrough;
case 337500:
val |= LCPLL_CLK_FREQ_337_5_BDW;
break;
case 450000:
val |= LCPLL_CLK_FREQ_450;
break;
case 540000:
val |= LCPLL_CLK_FREQ_54O_BDW;
break;
case 675000:
val |= LCPLL_CLK_FREQ_675_BDW;
break;
}
intel_de_write(dev_priv, LCPLL_CTL, val); intel_de_write(dev_priv, LCPLL_CTL, val);
val = intel_de_read(dev_priv, LCPLL_CTL); val = intel_de_read(dev_priv, LCPLL_CTL);
...@@ -955,10 +954,8 @@ static void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, ...@@ -955,10 +954,8 @@ static void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv,
intel_update_max_cdclk(dev_priv); intel_update_max_cdclk(dev_priv);
} }
static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) static u32 skl_dpll0_link_rate(struct drm_i915_private *dev_priv, int vco)
{ {
u32 val;
drm_WARN_ON(&dev_priv->drm, vco != 8100000 && vco != 8640000); drm_WARN_ON(&dev_priv->drm, vco != 8100000 && vco != 8640000);
/* /*
...@@ -970,17 +967,22 @@ static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) ...@@ -970,17 +967,22 @@ static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco)
* rate later on, with the constraint of choosing a frequency that * rate later on, with the constraint of choosing a frequency that
* works with vco. * works with vco.
*/ */
if (vco == 8640000)
return DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, SKL_DPLL0);
else
return DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0);
}
static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco)
{
u32 val;
val = intel_de_read(dev_priv, DPLL_CTRL1); val = intel_de_read(dev_priv, DPLL_CTRL1);
val &= ~(DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | DPLL_CTRL1_SSC(SKL_DPLL0) | val &= ~(DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | DPLL_CTRL1_SSC(SKL_DPLL0) |
DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)); DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0));
val |= DPLL_CTRL1_OVERRIDE(SKL_DPLL0); val |= DPLL_CTRL1_OVERRIDE(SKL_DPLL0);
if (vco == 8640000) val |= skl_dpll0_link_rate(dev_priv, vco);
val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080,
SKL_DPLL0);
else
val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810,
SKL_DPLL0);
intel_de_write(dev_priv, DPLL_CTRL1, val); intel_de_write(dev_priv, DPLL_CTRL1, val);
intel_de_posting_read(dev_priv, DPLL_CTRL1); intel_de_posting_read(dev_priv, DPLL_CTRL1);
...@@ -1007,6 +1009,29 @@ static void skl_dpll0_disable(struct drm_i915_private *dev_priv) ...@@ -1007,6 +1009,29 @@ static void skl_dpll0_disable(struct drm_i915_private *dev_priv)
dev_priv->cdclk.hw.vco = 0; dev_priv->cdclk.hw.vco = 0;
} }
static u32 skl_cdclk_freq_sel(struct drm_i915_private *dev_priv,
int cdclk, int vco)
{
switch (cdclk) {
default:
drm_WARN_ON(&dev_priv->drm,
cdclk != dev_priv->cdclk.hw.bypass);
drm_WARN_ON(&dev_priv->drm, vco != 0);
fallthrough;
case 308571:
case 337500:
return CDCLK_FREQ_337_308;
case 450000:
case 432000:
return CDCLK_FREQ_450_432;
case 540000:
return CDCLK_FREQ_540;
case 617143:
case 675000:
return CDCLK_FREQ_675_617;
}
}
static void skl_set_cdclk(struct drm_i915_private *dev_priv, static void skl_set_cdclk(struct drm_i915_private *dev_priv,
const struct intel_cdclk_config *cdclk_config, const struct intel_cdclk_config *cdclk_config,
enum pipe pipe) enum pipe pipe)
...@@ -1037,29 +1062,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, ...@@ -1037,29 +1062,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv,
return; return;
} }
/* Choose frequency for this cdclk */ freq_select = skl_cdclk_freq_sel(dev_priv, cdclk, vco);
switch (cdclk) {
default:
drm_WARN_ON(&dev_priv->drm,
cdclk != dev_priv->cdclk.hw.bypass);
drm_WARN_ON(&dev_priv->drm, vco != 0);
fallthrough;
case 308571:
case 337500:
freq_select = CDCLK_FREQ_337_308;
break;
case 450000:
case 432000:
freq_select = CDCLK_FREQ_450_432;
break;
case 540000:
freq_select = CDCLK_FREQ_540;
break;
case 617143:
case 675000:
freq_select = CDCLK_FREQ_675_617;
break;
}
if (dev_priv->cdclk.hw.vco != 0 && if (dev_priv->cdclk.hw.vco != 0 &&
dev_priv->cdclk.hw.vco != vco) dev_priv->cdclk.hw.vco != vco)
...@@ -1550,13 +1553,40 @@ static u32 bxt_cdclk_cd2x_pipe(struct drm_i915_private *dev_priv, enum pipe pipe ...@@ -1550,13 +1553,40 @@ static u32 bxt_cdclk_cd2x_pipe(struct drm_i915_private *dev_priv, enum pipe pipe
} }
} }
static u32 bxt_cdclk_cd2x_div_sel(struct drm_i915_private *dev_priv,
int cdclk, int vco)
{
/* cdclk = vco / 2 / div{1,1.5,2,4} */
switch (DIV_ROUND_CLOSEST(vco, cdclk)) {
default:
drm_WARN_ON(&dev_priv->drm,
cdclk != dev_priv->cdclk.hw.bypass);
drm_WARN_ON(&dev_priv->drm, vco != 0);
fallthrough;
case 2:
return BXT_CDCLK_CD2X_DIV_SEL_1;
case 3:
drm_WARN(&dev_priv->drm,
DISPLAY_VER(dev_priv) >= 10,
"Unsupported divider\n");
return BXT_CDCLK_CD2X_DIV_SEL_1_5;
case 4:
return BXT_CDCLK_CD2X_DIV_SEL_2;
case 8:
drm_WARN(&dev_priv->drm,
DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv),
"Unsupported divider\n");
return BXT_CDCLK_CD2X_DIV_SEL_4;
}
}
static void bxt_set_cdclk(struct drm_i915_private *dev_priv, static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
const struct intel_cdclk_config *cdclk_config, const struct intel_cdclk_config *cdclk_config,
enum pipe pipe) enum pipe pipe)
{ {
int cdclk = cdclk_config->cdclk; int cdclk = cdclk_config->cdclk;
int vco = cdclk_config->vco; int vco = cdclk_config->vco;
u32 val, divider; u32 val;
int ret; int ret;
/* Inform power controller of upcoming frequency change. */ /* Inform power controller of upcoming frequency change. */
...@@ -1581,33 +1611,6 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, ...@@ -1581,33 +1611,6 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
return; return;
} }
/* cdclk = vco / 2 / div{1,1.5,2,4} */
switch (DIV_ROUND_CLOSEST(vco, cdclk)) {
default:
drm_WARN_ON(&dev_priv->drm,
cdclk != dev_priv->cdclk.hw.bypass);
drm_WARN_ON(&dev_priv->drm, vco != 0);
fallthrough;
case 2:
divider = BXT_CDCLK_CD2X_DIV_SEL_1;
break;
case 3:
drm_WARN(&dev_priv->drm,
DISPLAY_VER(dev_priv) >= 10,
"Unsupported divider\n");
divider = BXT_CDCLK_CD2X_DIV_SEL_1_5;
break;
case 4:
divider = BXT_CDCLK_CD2X_DIV_SEL_2;
break;
case 8:
drm_WARN(&dev_priv->drm,
DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv),
"Unsupported divider\n");
divider = BXT_CDCLK_CD2X_DIV_SEL_4;
break;
}
if (DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv)) { if (DISPLAY_VER(dev_priv) >= 11 || IS_CANNONLAKE(dev_priv)) {
if (dev_priv->cdclk.hw.vco != 0 && if (dev_priv->cdclk.hw.vco != 0 &&
dev_priv->cdclk.hw.vco != vco) dev_priv->cdclk.hw.vco != vco)
...@@ -1625,8 +1628,9 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, ...@@ -1625,8 +1628,9 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
bxt_de_pll_enable(dev_priv, vco); bxt_de_pll_enable(dev_priv, vco);
} }
val = divider | skl_cdclk_decimal(cdclk) | val = bxt_cdclk_cd2x_div_sel(dev_priv, cdclk, vco) |
bxt_cdclk_cd2x_pipe(dev_priv, pipe); bxt_cdclk_cd2x_pipe(dev_priv, pipe) |
skl_cdclk_decimal(cdclk);
/* /*
* Disable SSA Precharge when CD clock frequency < 500 MHz, * Disable SSA Precharge when CD clock frequency < 500 MHz,
...@@ -1712,23 +1716,9 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) ...@@ -1712,23 +1716,9 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
expected = skl_cdclk_decimal(cdclk); expected = skl_cdclk_decimal(cdclk);
/* Figure out what CD2X divider we should be using for this cdclk */ /* Figure out what CD2X divider we should be using for this cdclk */
switch (DIV_ROUND_CLOSEST(dev_priv->cdclk.hw.vco, expected |= bxt_cdclk_cd2x_div_sel(dev_priv,
dev_priv->cdclk.hw.cdclk)) { dev_priv->cdclk.hw.cdclk,
case 2: dev_priv->cdclk.hw.vco);
expected |= BXT_CDCLK_CD2X_DIV_SEL_1;
break;
case 3:
expected |= BXT_CDCLK_CD2X_DIV_SEL_1_5;
break;
case 4:
expected |= BXT_CDCLK_CD2X_DIV_SEL_2;
break;
case 8:
expected |= BXT_CDCLK_CD2X_DIV_SEL_4;
break;
default:
goto sanitize;
}
/* /*
* Disable SSA Precharge when CD clock frequency < 500 MHz, * Disable SSA Precharge when CD clock frequency < 500 MHz,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment