[Intel-gfx] [PATCH v4 2/8] drm/i915: Use literal representation of cdclk tables
Ville Syrjälä
ville.syrjala at linux.intel.com
Tue Sep 10 16:04:03 UTC 2019
On Tue, Sep 10, 2019 at 08:42:46AM -0700, Matt Roper wrote:
> The bspec lays out legal cdclk frequencies, PLL ratios, and CD2X
> dividers in an easy-to-read table for most recent platforms. We've been
> translating the data from that table into platform-specific code logic,
> but it's easy to overlook an area we need to update when adding new
> cdclk values or enabling new platforms. Let's just add a form of the
> bspec table to the code and then adjust our functions to pull what they
> need directly out of the table.
>
> v2: Fix comparison when finding best cdclk.
>
> v3: Another logic fix for calc_cdclk.
>
> v4:
> - Use named initializers for cdclk tables. (Ville)
> - Include refclk as a field in the table instead of adding all three
> ratios for each entry. (Ville)
> - Terminate tables with an empty entry to avoid needing to store the
> table size. (Ville)
> - Don't try so hard to return reasonable values from our lookup
> functions if we get impossible inputs; just WARN and return 0.
> (Ville)
> - Keep a bxt_ prefix on the lookup functions since they're still only
> used on bxt+ for now. We can rename them later if we extend this
> table-based approach back to older platforms. (Ville)
>
> Cc: Ville Syrjälä <ville.syrjala at linux.intel.com>
> Signed-off-by: Matt Roper <matthew.d.roper at intel.com>
> ---
> drivers/gpu/drm/i915/display/intel_cdclk.c | 303 +++++++--------------
> drivers/gpu/drm/i915/display/intel_cdclk.h | 7 +
> drivers/gpu/drm/i915/i915_drv.h | 3 +
> 3 files changed, 110 insertions(+), 203 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
> index 01ed3262d91e..c8cf288b8e8e 100644
> --- a/drivers/gpu/drm/i915/display/intel_cdclk.c
> +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
> @@ -1161,28 +1161,88 @@ static void skl_uninit_cdclk(struct drm_i915_private *dev_priv)
> skl_set_cdclk(dev_priv, &cdclk_state, INVALID_PIPE);
> }
>
> -static int bxt_calc_cdclk(int min_cdclk)
> -{
> - if (min_cdclk > 576000)
> - return 624000;
> - else if (min_cdclk > 384000)
> - return 576000;
> - else if (min_cdclk > 288000)
> - return 384000;
> - else if (min_cdclk > 144000)
> - return 288000;
> - else
> - return 144000;
> +static const struct intel_cdclk_vals bxt_cdclk_table[] = {
> + { .refclk = 19200, .cdclk = 144000, .divider = 8, .ratio = 60 },
> + { .refclk = 19200, .cdclk = 288000, .divider = 4, .ratio = 60 },
> + { .refclk = 19200, .cdclk = 384000, .divider = 3, .ratio = 60 },
> + { .refclk = 19200, .cdclk = 576000, .divider = 2, .ratio = 60 },
> + { .refclk = 19200, .cdclk = 624000, .divider = 2, .ratio = 65 },
> + {}
> +};
If only we had constexpr so we could do
BUILD_BUG_ON(ref*ratio == cdclk*div) without having to hand roll
it for every table entry. Oh well.
> +
> +static const struct intel_cdclk_vals glk_cdclk_table[] = {
> + { .refclk = 19200, .cdclk = 79200, .divider = 8, .ratio = 33 },
> + { .refclk = 19200, .cdclk = 158400, .divider = 4, .ratio = 33 },
> + { .refclk = 19200, .cdclk = 316800, .divider = 2, .ratio = 33 },
> + {}
> +};
> +
> +static const struct intel_cdclk_vals cnl_cdclk_table[] = {
> + { .refclk = 19200, .cdclk = 168000, 4, 35 },
> + { .refclk = 19200, .cdclk = 336000, 2, 35 },
> + { .refclk = 19200, .cdclk = 528000, 2, 55 },
> +
> + { .refclk = 24000, .cdclk = 168000, 4, 35 },
> + { .refclk = 24000, .cdclk = 336000, 2, 35 },
> + { .refclk = 24000, .cdclk = 528000, 2, 55 },
The ratios looks wrong here. Also missing .divider= and .ratio=.
> + {}
> +};
> +
> +static const struct intel_cdclk_vals icl_cdclk_table[] = {
> + { .refclk = 19200, .cdclk = 172800, .divider = 2, .ratio = 18 },
> + { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 },
> + { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 },
> + { .refclk = 19200, .cdclk = 326400, .divider = 4, .ratio = 68 },
> + { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 },
> + { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 },
> +
> + { .refclk = 24000, .cdclk = 180000, .divider = 2, .ratio = 15 },
> + { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 },
> + { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 },
> + { .refclk = 24000, .cdclk = 324000, .divider = 4, .ratio = 54 },
> + { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 },
> + { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 },
> +
> + { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 9 },
> + { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 },
> + { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 },
> + { .refclk = 38400, .cdclk = 326400, .divider = 4, .ratio = 34 },
> + { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 },
> + { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 },
> + {}
> +};
Everything else seems to check out.
With the cnl tables fixed:
Reviewed-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> +
> +static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk)
> +{
> + const struct intel_cdclk_vals *table = dev_priv->cdclk.table;
> + int i;
> +
> + for (i = 0; table[i].refclk; i++)
> + if (table[i].refclk == dev_priv->cdclk.hw.ref &&
> + table[i].cdclk >= min_cdclk)
> + return table[i].cdclk;
> +
> + WARN(1, "Cannot satisfy minimum cdclk %d with refclk %u\n",
> + min_cdclk, dev_priv->cdclk.hw.ref);
> + return 0;
> }
>
> -static int glk_calc_cdclk(int min_cdclk)
> +static int bxt_calc_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
> {
> - if (min_cdclk > 158400)
> - return 316800;
> - else if (min_cdclk > 79200)
> - return 158400;
> - else
> - return 79200;
> + const struct intel_cdclk_vals *table = dev_priv->cdclk.table;
> + int i;
> +
> + if (cdclk == dev_priv->cdclk.hw.bypass)
> + return 0;
> +
> + for (i = 0; table[i].refclk; i++)
> + if (table[i].refclk == dev_priv->cdclk.hw.ref &&
> + table[i].cdclk == cdclk)
> + return dev_priv->cdclk.hw.ref * table[i].ratio;
> +
> + WARN(1, "cdclk %d not valid for refclk %u\n",
> + cdclk, dev_priv->cdclk.hw.ref);
> + return 0;
> }
>
> static u8 bxt_calc_voltage_level(int cdclk)
> @@ -1220,52 +1280,6 @@ static u8 ehl_calc_voltage_level(int cdclk)
> return 0;
> }
>
> -static int bxt_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
> -{
> - int ratio;
> -
> - if (cdclk == dev_priv->cdclk.hw.bypass)
> - return 0;
> -
> - switch (cdclk) {
> - default:
> - MISSING_CASE(cdclk);
> - /* fall through */
> - case 144000:
> - case 288000:
> - case 384000:
> - case 576000:
> - ratio = 60;
> - break;
> - case 624000:
> - ratio = 65;
> - break;
> - }
> -
> - return dev_priv->cdclk.hw.ref * ratio;
> -}
> -
> -static int glk_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
> -{
> - int ratio;
> -
> - if (cdclk == dev_priv->cdclk.hw.bypass)
> - return 0;
> -
> - switch (cdclk) {
> - default:
> - MISSING_CASE(cdclk);
> - /* fall through */
> - case 79200:
> - case 158400:
> - case 316800:
> - ratio = 33;
> - break;
> - }
> -
> - return dev_priv->cdclk.hw.ref * ratio;
> -}
> -
> static void cnl_readout_refclk(struct drm_i915_private *dev_priv,
> struct intel_cdclk_state *cdclk_state)
> {
> @@ -1576,13 +1590,8 @@ static void bxt_init_cdclk(struct drm_i915_private *dev_priv)
> * - The initial CDCLK needs to be read from VBT.
> * Need to make this change after VBT has changes for BXT.
> */
> - if (IS_GEMINILAKE(dev_priv)) {
> - cdclk_state.cdclk = glk_calc_cdclk(0);
> - cdclk_state.vco = glk_de_pll_vco(dev_priv, cdclk_state.cdclk);
> - } else {
> - cdclk_state.cdclk = bxt_calc_cdclk(0);
> - cdclk_state.vco = bxt_de_pll_vco(dev_priv, cdclk_state.cdclk);
> - }
> + cdclk_state.cdclk = bxt_calc_cdclk(dev_priv, 0);
> + cdclk_state.vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk_state.cdclk);
> cdclk_state.voltage_level = bxt_calc_voltage_level(cdclk_state.cdclk);
>
> bxt_set_cdclk(dev_priv, &cdclk_state, INVALID_PIPE);
> @@ -1599,16 +1608,6 @@ static void bxt_uninit_cdclk(struct drm_i915_private *dev_priv)
> bxt_set_cdclk(dev_priv, &cdclk_state, INVALID_PIPE);
> }
>
> -static int cnl_calc_cdclk(int min_cdclk)
> -{
> - if (min_cdclk > 336000)
> - return 528000;
> - else if (min_cdclk > 168000)
> - return 336000;
> - else
> - return 168000;
> -}
> -
> static void cnl_cdclk_pll_disable(struct drm_i915_private *dev_priv)
> {
> u32 val;
> @@ -1718,29 +1717,6 @@ static void cnl_set_cdclk(struct drm_i915_private *dev_priv,
> dev_priv->cdclk.hw.voltage_level = cdclk_state->voltage_level;
> }
>
> -static int cnl_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
> -{
> - int ratio;
> -
> - if (cdclk == dev_priv->cdclk.hw.bypass)
> - return 0;
> -
> - switch (cdclk) {
> - default:
> - MISSING_CASE(cdclk);
> - /* fall through */
> - case 168000:
> - case 336000:
> - ratio = dev_priv->cdclk.hw.ref == 19200 ? 35 : 28;
> - break;
> - case 528000:
> - ratio = dev_priv->cdclk.hw.ref == 19200 ? 55 : 44;
> - break;
> - }
> -
> - return dev_priv->cdclk.hw.ref * ratio;
> -}
> -
> static void cnl_sanitize_cdclk(struct drm_i915_private *dev_priv)
> {
> u32 cdctl, expected;
> @@ -1783,77 +1759,6 @@ static void cnl_sanitize_cdclk(struct drm_i915_private *dev_priv)
> dev_priv->cdclk.hw.vco = -1;
> }
>
> -static int icl_calc_cdclk(int min_cdclk, unsigned int ref)
> -{
> - static const int ranges_24[] = { 180000, 192000, 312000, 324000,
> - 552000, 648000 };
> - static const int ranges_19_38[] = { 172800, 192000, 307200, 326400,
> - 556800, 652800 };
> - const int *ranges;
> - int len, i;
> -
> - switch (ref) {
> - default:
> - MISSING_CASE(ref);
> - /* fall through */
> - case 24000:
> - ranges = ranges_24;
> - len = ARRAY_SIZE(ranges_24);
> - break;
> - case 19200:
> - case 38400:
> - ranges = ranges_19_38;
> - len = ARRAY_SIZE(ranges_19_38);
> - break;
> - }
> -
> - for (i = 0; i < len; i++) {
> - if (min_cdclk <= ranges[i])
> - return ranges[i];
> - }
> -
> - WARN_ON(min_cdclk > ranges[len - 1]);
> - return ranges[len - 1];
> -}
> -
> -static int icl_calc_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
> -{
> - int ratio;
> -
> - if (cdclk == dev_priv->cdclk.hw.bypass)
> - return 0;
> -
> - switch (cdclk) {
> - default:
> - MISSING_CASE(cdclk);
> - /* fall through */
> - case 172800:
> - case 307200:
> - case 326400:
> - case 556800:
> - case 652800:
> - WARN_ON(dev_priv->cdclk.hw.ref != 19200 &&
> - dev_priv->cdclk.hw.ref != 38400);
> - break;
> - case 180000:
> - case 312000:
> - case 324000:
> - case 552000:
> - case 648000:
> - WARN_ON(dev_priv->cdclk.hw.ref != 24000);
> - break;
> - case 192000:
> - WARN_ON(dev_priv->cdclk.hw.ref != 19200 &&
> - dev_priv->cdclk.hw.ref != 38400 &&
> - dev_priv->cdclk.hw.ref != 24000);
> - break;
> - }
> -
> - ratio = cdclk / (dev_priv->cdclk.hw.ref / 2);
> -
> - return dev_priv->cdclk.hw.ref * ratio;
> -}
> -
> static void icl_init_cdclk(struct drm_i915_private *dev_priv)
> {
> struct intel_cdclk_state sanitized_state;
> @@ -1882,8 +1787,8 @@ static void icl_init_cdclk(struct drm_i915_private *dev_priv)
> DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n");
>
> sanitized_state.ref = dev_priv->cdclk.hw.ref;
> - sanitized_state.cdclk = icl_calc_cdclk(0, sanitized_state.ref);
> - sanitized_state.vco = icl_calc_cdclk_pll_vco(dev_priv,
> + sanitized_state.cdclk = bxt_calc_cdclk(dev_priv, 0);
> + sanitized_state.vco = bxt_calc_cdclk_pll_vco(dev_priv,
> sanitized_state.cdclk);
> if (IS_ELKHARTLAKE(dev_priv))
> sanitized_state.voltage_level =
> @@ -1923,8 +1828,8 @@ static void cnl_init_cdclk(struct drm_i915_private *dev_priv)
>
> cdclk_state = dev_priv->cdclk.hw;
>
> - cdclk_state.cdclk = cnl_calc_cdclk(0);
> - cdclk_state.vco = cnl_cdclk_pll_vco(dev_priv, cdclk_state.cdclk);
> + cdclk_state.cdclk = bxt_calc_cdclk(dev_priv, 0);
> + cdclk_state.vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk_state.cdclk);
> cdclk_state.voltage_level = cnl_calc_voltage_level(cdclk_state.cdclk);
>
> cnl_set_cdclk(dev_priv, &cdclk_state, INVALID_PIPE);
> @@ -2426,13 +2331,8 @@ static int bxt_modeset_calc_cdclk(struct intel_atomic_state *state)
> if (min_cdclk < 0)
> return min_cdclk;
>
> - if (IS_GEMINILAKE(dev_priv)) {
> - cdclk = glk_calc_cdclk(min_cdclk);
> - vco = glk_de_pll_vco(dev_priv, cdclk);
> - } else {
> - cdclk = bxt_calc_cdclk(min_cdclk);
> - vco = bxt_de_pll_vco(dev_priv, cdclk);
> - }
> + cdclk = bxt_calc_cdclk(dev_priv, min_cdclk);
> + vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk);
>
> state->cdclk.logical.vco = vco;
> state->cdclk.logical.cdclk = cdclk;
> @@ -2440,13 +2340,8 @@ static int bxt_modeset_calc_cdclk(struct intel_atomic_state *state)
> bxt_calc_voltage_level(cdclk);
>
> if (!state->active_pipes) {
> - if (IS_GEMINILAKE(dev_priv)) {
> - cdclk = glk_calc_cdclk(state->cdclk.force_min_cdclk);
> - vco = glk_de_pll_vco(dev_priv, cdclk);
> - } else {
> - cdclk = bxt_calc_cdclk(state->cdclk.force_min_cdclk);
> - vco = bxt_de_pll_vco(dev_priv, cdclk);
> - }
> + cdclk = bxt_calc_cdclk(dev_priv, state->cdclk.force_min_cdclk);
> + vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk);
>
> state->cdclk.actual.vco = vco;
> state->cdclk.actual.cdclk = cdclk;
> @@ -2468,8 +2363,8 @@ static int cnl_modeset_calc_cdclk(struct intel_atomic_state *state)
> if (min_cdclk < 0)
> return min_cdclk;
>
> - cdclk = cnl_calc_cdclk(min_cdclk);
> - vco = cnl_cdclk_pll_vco(dev_priv, cdclk);
> + cdclk = bxt_calc_cdclk(dev_priv, min_cdclk);
> + vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk);
>
> state->cdclk.logical.vco = vco;
> state->cdclk.logical.cdclk = cdclk;
> @@ -2478,8 +2373,8 @@ static int cnl_modeset_calc_cdclk(struct intel_atomic_state *state)
> cnl_compute_min_voltage_level(state));
>
> if (!state->active_pipes) {
> - cdclk = cnl_calc_cdclk(state->cdclk.force_min_cdclk);
> - vco = cnl_cdclk_pll_vco(dev_priv, cdclk);
> + cdclk = bxt_calc_cdclk(dev_priv, state->cdclk.force_min_cdclk);
> + vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk);
>
> state->cdclk.actual.vco = vco;
> state->cdclk.actual.cdclk = cdclk;
> @@ -2495,15 +2390,14 @@ static int cnl_modeset_calc_cdclk(struct intel_atomic_state *state)
> static int icl_modeset_calc_cdclk(struct intel_atomic_state *state)
> {
> struct drm_i915_private *dev_priv = to_i915(state->base.dev);
> - unsigned int ref = state->cdclk.logical.ref;
> int min_cdclk, cdclk, vco;
>
> min_cdclk = intel_compute_min_cdclk(state);
> if (min_cdclk < 0)
> return min_cdclk;
>
> - cdclk = icl_calc_cdclk(min_cdclk, ref);
> - vco = icl_calc_cdclk_pll_vco(dev_priv, cdclk);
> + cdclk = bxt_calc_cdclk(dev_priv, min_cdclk);
> + vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk);
>
> state->cdclk.logical.vco = vco;
> state->cdclk.logical.cdclk = cdclk;
> @@ -2517,8 +2411,8 @@ static int icl_modeset_calc_cdclk(struct intel_atomic_state *state)
> cnl_compute_min_voltage_level(state));
>
> if (!state->active_pipes) {
> - cdclk = icl_calc_cdclk(state->cdclk.force_min_cdclk, ref);
> - vco = icl_calc_cdclk_pll_vco(dev_priv, cdclk);
> + cdclk = bxt_calc_cdclk(dev_priv, state->cdclk.force_min_cdclk);
> + vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk);
>
> state->cdclk.actual.vco = vco;
> state->cdclk.actual.cdclk = cdclk;
> @@ -2754,12 +2648,15 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
> if (INTEL_GEN(dev_priv) >= 11) {
> dev_priv->display.set_cdclk = cnl_set_cdclk;
> dev_priv->display.modeset_calc_cdclk = icl_modeset_calc_cdclk;
> + dev_priv->cdclk.table = icl_cdclk_table;
> } else if (IS_CANNONLAKE(dev_priv)) {
> dev_priv->display.set_cdclk = cnl_set_cdclk;
> dev_priv->display.modeset_calc_cdclk = cnl_modeset_calc_cdclk;
> + dev_priv->cdclk.table = cnl_cdclk_table;
> } else if (IS_GEN9_LP(dev_priv)) {
> dev_priv->display.set_cdclk = bxt_set_cdclk;
> dev_priv->display.modeset_calc_cdclk = bxt_modeset_calc_cdclk;
> + dev_priv->cdclk.table = bxt_cdclk_table;
> } else if (IS_GEN9_BC(dev_priv)) {
> dev_priv->display.set_cdclk = skl_set_cdclk;
> dev_priv->display.modeset_calc_cdclk = skl_modeset_calc_cdclk;
> diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.h b/drivers/gpu/drm/i915/display/intel_cdclk.h
> index 4d6f7f5f8930..ca6d651946b9 100644
> --- a/drivers/gpu/drm/i915/display/intel_cdclk.h
> +++ b/drivers/gpu/drm/i915/display/intel_cdclk.h
> @@ -15,6 +15,13 @@ struct intel_atomic_state;
> struct intel_cdclk_state;
> struct intel_crtc_state;
>
> +struct intel_cdclk_vals {
> + u32 refclk;
> + u32 cdclk;
> + u8 divider; /* CD2X divider * 2 */
> + u8 ratio;
> +};
> +
> int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state);
> void intel_cdclk_init(struct drm_i915_private *i915);
> void intel_cdclk_uninit(struct drm_i915_private *i915);
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index e289b4ffd34b..ff6aff2a4866 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1420,6 +1420,9 @@ struct drm_i915_private {
> /* The current hardware cdclk state */
> struct intel_cdclk_state hw;
>
> + /* cdclk, divider, and ratio table from bspec */
> + const struct intel_cdclk_vals *table;
> +
> int force_min_cdclk;
> } cdclk;
>
> --
> 2.20.1
--
Ville Syrjälä
Intel
More information about the Intel-gfx
mailing list