drm/i915: Unify the DPLL ref clock frequency tracking
authorImre Deak <imre.deak@intel.com>
Fri, 28 Feb 2020 15:33:28 +0000 (17:33 +0200)
committerImre Deak <imre.deak@intel.com>
Mon, 2 Mar 2020 17:36:22 +0000 (19:36 +0200)
All platforms using the shared DPLL framework use 3 reference clocks for
their DPLLs: SSC, non-SSC and DSI. For a more unified way across
platforms store the frequency of these ref clocks as part of the DPLL
global state. This also allows us to keep the HW access reading out the
ref clock value separate from the DPLL frequency calculation that
depends on the ref clock.

For now add only the SSC and non-SSC ref clocks, as the pre-ICL DSI code
has its own logic for calculating DPLL parameters instead of the shared
DPLL framework.

v2:
- Apply the ICL combo PHY PLL ref_clock/2 adjustment during the
  frequency->PLL param conversion direction as well. (CI shards)
- s/kHZ/kHz/ (Ville)

Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200228153328.17842-1-imre.deak@intel.com
drivers/gpu/drm/i915/display/intel_display_debugfs.c
drivers/gpu/drm/i915/display/intel_dpll_mgr.c
drivers/gpu/drm/i915/i915_drv.h

index d2461d7946bfb153c9ddf4dca5591f19bb506731..1e6eb7f2f72dbf7afa3d0be9a466c38b8cce0225 100644 (file)
@@ -920,6 +920,11 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused)
        int i;
 
        drm_modeset_lock_all(dev);
+
+       seq_printf(m, "PLL refclks: non-SSC: %d kHz, SSC: %d kHz\n",
+                  dev_priv->dpll.ref_clks.nssc,
+                  dev_priv->dpll.ref_clks.ssc);
+
        for (i = 0; i < dev_priv->dpll.num_shared_dpll; i++) {
                struct intel_shared_dpll *pll = &dev_priv->dpll.shared_dplls[i];
 
index 7e6da58a47c996f5efbf6372f8042e34d3a70713..76d14486b3a5985aa4d0e00d1b21e51d68d80ac8 100644 (file)
@@ -56,6 +56,7 @@ struct intel_dpll_mgr {
        void (*update_active_dpll)(struct intel_atomic_state *state,
                                   struct intel_crtc *crtc,
                                   struct intel_encoder *encoder);
+       void (*update_ref_clks)(struct drm_i915_private *i915);
        void (*dump_hw_state)(struct drm_i915_private *dev_priv,
                              const struct intel_dpll_hw_state *hw_state);
 };
@@ -886,16 +887,9 @@ static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
 
        switch (wrpll & WRPLL_REF_MASK) {
        case WRPLL_REF_SPECIAL_HSW:
-               /*
-                * muxed-SSC for BDW.
-                * non-SSC for non-ULT HSW. Check FUSE_STRAP3
-                * for the non-SSC reference frequency.
-                */
+               /* Muxed-SSC for BDW, non-SSC for non-ULT HSW. */
                if (IS_HASWELL(dev_priv) && !IS_HSW_ULT(dev_priv)) {
-                       if (intel_de_read(dev_priv, FUSE_STRAP3) & HSW_REF_CLK_SELECT)
-                               refclk = 24;
-                       else
-                               refclk = 135;
+                       refclk = dev_priv->dpll.ref_clks.nssc;
                        break;
                }
                /* fall through */
@@ -905,10 +899,10 @@ static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
                 * code only cares about 5% accuracy, and spread is a max of
                 * 0.5% downspread.
                 */
-               refclk = 135;
+               refclk = dev_priv->dpll.ref_clks.ssc;
                break;
        case WRPLL_REF_LCPLL:
-               refclk = 2700;
+               refclk = 2700000;
                break;
        default:
                MISSING_CASE(wrpll);
@@ -920,7 +914,7 @@ static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
        n = (wrpll & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT;
 
        /* Convert to KHz, p & r have a fixed point portion */
-       return (refclk * n * 100) / (p * r) * 2;
+       return (refclk * n / 10) / (p * r) * 2;
 }
 
 static struct intel_shared_dpll *
@@ -1049,6 +1043,16 @@ static bool hsw_get_dpll(struct intel_atomic_state *state,
        return true;
 }
 
+static void hsw_update_dpll_ref_clks(struct drm_i915_private *i915)
+{
+       i915->dpll.ref_clks.ssc = 135000;
+       /* Non-SSC is only used on non-ULT HSW. */
+       if (intel_de_read(i915, FUSE_STRAP3) & HSW_REF_CLK_SELECT)
+               i915->dpll.ref_clks.nssc = 24000;
+       else
+               i915->dpll.ref_clks.nssc = 135000;
+}
+
 static void hsw_dump_hw_state(struct drm_i915_private *dev_priv,
                              const struct intel_dpll_hw_state *hw_state)
 {
@@ -1108,6 +1112,7 @@ static const struct intel_dpll_mgr hsw_pll_mgr = {
        .dpll_info = hsw_plls,
        .get_dplls = hsw_get_dpll,
        .put_dplls = intel_put_dpll,
+       .update_ref_clks = hsw_update_dpll_ref_clks,
        .dump_hw_state = hsw_dump_hw_state,
 };
 
@@ -1523,6 +1528,7 @@ skip_remaining_dividers:
 
 static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
 {
+       struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
        u32 ctrl1, cfgcr1, cfgcr2;
        struct skl_wrpll_params wrpll_params = { 0, };
 
@@ -1534,7 +1540,8 @@ static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
 
        ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
 
-       if (!skl_ddi_calculate_wrpll(crtc_state->port_clock * 1000, 24000,
+       if (!skl_ddi_calculate_wrpll(crtc_state->port_clock * 1000,
+                                    i915->dpll.ref_clks.nssc,
                                     &wrpll_params))
                return false;
 
@@ -1561,7 +1568,7 @@ static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
                                  const struct intel_shared_dpll *pll)
 {
        const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
-       int ref_clock = 24000;
+       int ref_clock = i915->dpll.ref_clks.nssc;
        u32 p0, p1, p2, dco_freq;
 
        p0 = pll_state->cfgcr2 & DPLL_CFGCR2_PDIV_MASK;
@@ -1751,6 +1758,12 @@ static int skl_ddi_pll_get_freq(struct drm_i915_private *i915,
                return skl_ddi_lcpll_get_freq(i915, pll);
 }
 
+static void skl_update_dpll_ref_clks(struct drm_i915_private *i915)
+{
+       /* No SSC ref */
+       i915->dpll.ref_clks.nssc = i915->cdclk.hw.ref;
+}
+
 static void skl_dump_hw_state(struct drm_i915_private *dev_priv,
                              const struct intel_dpll_hw_state *hw_state)
 {
@@ -1787,6 +1800,7 @@ static const struct intel_dpll_mgr skl_pll_mgr = {
        .dpll_info = skl_plls,
        .get_dplls = skl_get_dpll,
        .put_dplls = intel_put_dpll,
+       .update_ref_clks = skl_update_dpll_ref_clks,
        .dump_hw_state = skl_dump_hw_state,
 };
 
@@ -2192,7 +2206,7 @@ static int bxt_ddi_pll_get_freq(struct drm_i915_private *i915,
        clock.p1 = (pll_state->ebb0 & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT;
        clock.p2 = (pll_state->ebb0 & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT;
 
-       return chv_calc_dpll_params(100000, &clock);
+       return chv_calc_dpll_params(i915->dpll.ref_clks.nssc, &clock);
 }
 
 static bool bxt_get_dpll(struct intel_atomic_state *state,
@@ -2228,6 +2242,13 @@ static bool bxt_get_dpll(struct intel_atomic_state *state,
        return true;
 }
 
+static void bxt_update_dpll_ref_clks(struct drm_i915_private *i915)
+{
+       i915->dpll.ref_clks.ssc = 100000;
+       i915->dpll.ref_clks.nssc = 100000;
+       /* DSI non-SSC ref 19.2MHz */
+}
+
 static void bxt_dump_hw_state(struct drm_i915_private *dev_priv,
                              const struct intel_dpll_hw_state *hw_state)
 {
@@ -2265,6 +2286,7 @@ static const struct intel_dpll_mgr bxt_pll_mgr = {
        .dpll_info = bxt_plls,
        .get_dplls = bxt_get_dpll,
        .put_dplls = intel_put_dpll,
+       .update_ref_clks = bxt_update_dpll_ref_clks,
        .dump_hw_state = bxt_dump_hw_state,
 };
 
@@ -2508,27 +2530,12 @@ static void cnl_wrpll_params_populate(struct skl_wrpll_params *params,
        params->dco_fraction = dco & 0x7fff;
 }
 
-int cnl_hdmi_pll_ref_clock(struct drm_i915_private *dev_priv)
-{
-       int ref_clock = dev_priv->cdclk.hw.ref;
-
-       /*
-        * For ICL+, the spec states: if reference frequency is 38.4,
-        * use 19.2 because the DPLL automatically divides that by 2.
-        */
-       if (INTEL_GEN(dev_priv) >= 11 && ref_clock == 38400)
-               ref_clock = 19200;
-
-       return ref_clock;
-}
-
 static bool
-cnl_ddi_calculate_wrpll(struct intel_crtc_state *crtc_state,
-                       struct skl_wrpll_params *wrpll_params)
+__cnl_ddi_calculate_wrpll(struct intel_crtc_state *crtc_state,
+                         struct skl_wrpll_params *wrpll_params,
+                         int ref_clock)
 {
-       struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
        u32 afe_clock = crtc_state->port_clock * 5;
-       u32 ref_clock;
        u32 dco_min = 7998000;
        u32 dco_max = 10000000;
        u32 dco_mid = (dco_min + dco_max) / 2;
@@ -2560,15 +2567,22 @@ cnl_ddi_calculate_wrpll(struct intel_crtc_state *crtc_state,
                return false;
 
        cnl_wrpll_get_multipliers(best_div, &pdiv, &qdiv, &kdiv);
-
-       ref_clock = cnl_hdmi_pll_ref_clock(dev_priv);
-
        cnl_wrpll_params_populate(wrpll_params, best_dco, ref_clock,
                                  pdiv, qdiv, kdiv);
 
        return true;
 }
 
+static bool
+cnl_ddi_calculate_wrpll(struct intel_crtc_state *crtc_state,
+                       struct skl_wrpll_params *wrpll_params)
+{
+       struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+       return __cnl_ddi_calculate_wrpll(crtc_state, wrpll_params,
+                                        i915->dpll.ref_clks.nssc);
+}
+
 static bool cnl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
 {
        u32 cfgcr0, cfgcr1;
@@ -2596,11 +2610,12 @@ static bool cnl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
        return true;
 }
 
-static int cnl_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
-                                 const struct intel_shared_dpll *pll)
+static int __cnl_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
+                                   const struct intel_shared_dpll *pll,
+                                   int ref_clock)
 {
        const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
-       u32 p0, p1, p2, dco_freq, ref_clock;
+       u32 p0, p1, p2, dco_freq;
 
        p0 = pll_state->cfgcr1 & DPLL_CFGCR1_PDIV_MASK;
        p2 = pll_state->cfgcr1 & DPLL_CFGCR1_KDIV_MASK;
@@ -2639,8 +2654,6 @@ static int cnl_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
                break;
        }
 
-       ref_clock = cnl_hdmi_pll_ref_clock(dev_priv);
-
        dco_freq = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK) *
                   ref_clock;
 
@@ -2653,6 +2666,12 @@ static int cnl_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
        return dco_freq / (p0 * p1 * p2 * 5);
 }
 
+static int cnl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
+                                 const struct intel_shared_dpll *pll)
+{
+       return __cnl_ddi_wrpll_get_freq(i915, pll, i915->dpll.ref_clks.nssc);
+}
+
 static bool
 cnl_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state)
 {
@@ -2794,6 +2813,12 @@ static int cnl_ddi_pll_get_freq(struct drm_i915_private *i915,
                return cnl_ddi_lcpll_get_freq(i915, pll);
 }
 
+static void cnl_update_dpll_ref_clks(struct drm_i915_private *i915)
+{
+       /* No SSC reference */
+       i915->dpll.ref_clks.nssc = i915->cdclk.hw.ref;
+}
+
 static void cnl_dump_hw_state(struct drm_i915_private *dev_priv,
                              const struct intel_dpll_hw_state *hw_state)
 {
@@ -2821,6 +2846,7 @@ static const struct intel_dpll_mgr cnl_pll_mgr = {
        .dpll_info = cnl_plls,
        .get_dplls = cnl_get_dpll,
        .put_dplls = intel_put_dpll,
+       .update_ref_clks = cnl_update_dpll_ref_clks,
        .dump_hw_state = cnl_dump_hw_state,
 };
 
@@ -2916,7 +2942,7 @@ static bool icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state,
 {
        struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
        const struct icl_combo_pll_params *params =
-               dev_priv->cdclk.hw.ref == 24000 ?
+               dev_priv->dpll.ref_clks.nssc == 24000 ?
                icl_dp_combo_pll_24MHz_values :
                icl_dp_combo_pll_19_2MHz_values;
        int clock = crtc_state->port_clock;
@@ -2939,9 +2965,9 @@ static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
        struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
 
        if (INTEL_GEN(dev_priv) >= 12) {
-               switch (dev_priv->cdclk.hw.ref) {
+               switch (dev_priv->dpll.ref_clks.nssc) {
                default:
-                       MISSING_CASE(dev_priv->cdclk.hw.ref);
+                       MISSING_CASE(dev_priv->dpll.ref_clks.nssc);
                        /* fall-through */
                case 19200:
                case 38400:
@@ -2952,9 +2978,9 @@ static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
                        break;
                }
        } else {
-               switch (dev_priv->cdclk.hw.ref) {
+               switch (dev_priv->dpll.ref_clks.nssc) {
                default:
-                       MISSING_CASE(dev_priv->cdclk.hw.ref);
+                       MISSING_CASE(dev_priv->dpll.ref_clks.nssc);
                        /* fall-through */
                case 19200:
                case 38400:
@@ -2981,6 +3007,37 @@ static int icl_ddi_tbt_pll_get_freq(struct drm_i915_private *i915,
        return 0;
 }
 
+static int icl_wrpll_ref_clock(struct drm_i915_private *i915)
+{
+       int ref_clock = i915->dpll.ref_clks.nssc;
+
+       /*
+        * For ICL+, the spec states: if reference frequency is 38.4,
+        * use 19.2 because the DPLL automatically divides that by 2.
+        */
+       if (ref_clock == 38400)
+               ref_clock = 19200;
+
+       return ref_clock;
+}
+
+static bool
+icl_calc_wrpll(struct intel_crtc_state *crtc_state,
+              struct skl_wrpll_params *wrpll_params)
+{
+       struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+       return __cnl_ddi_calculate_wrpll(crtc_state, wrpll_params,
+                                        icl_wrpll_ref_clock(i915));
+}
+
+static int icl_ddi_combo_pll_get_freq(struct drm_i915_private *i915,
+                                     const struct intel_shared_dpll *pll)
+{
+       return __cnl_ddi_wrpll_get_freq(i915, pll,
+                                       icl_wrpll_ref_clock(i915));
+}
+
 static bool icl_calc_dpll_state(struct intel_crtc_state *crtc_state,
                                struct intel_encoder *encoder,
                                struct intel_dpll_hw_state *pll_state)
@@ -2995,7 +3052,7 @@ static bool icl_calc_dpll_state(struct intel_crtc_state *crtc_state,
                ret = icl_calc_tbt_pll(crtc_state, &pll_params);
        else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) ||
                 intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
-               ret = cnl_ddi_calculate_wrpll(crtc_state, &pll_params);
+               ret = icl_calc_wrpll(crtc_state, &pll_params);
        else
                ret = icl_calc_dp_combo_pll(crtc_state, &pll_params);
 
@@ -3118,7 +3175,7 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
                                  struct intel_dpll_hw_state *pll_state)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
-       int refclk_khz = dev_priv->cdclk.hw.ref;
+       int refclk_khz = dev_priv->dpll.ref_clks.nssc;
        int clock = crtc_state->port_clock;
        u32 dco_khz, m1div, m2div_int, m2div_rem, m2div_frac;
        u32 iref_ndiv, iref_trim, iref_pulse_w;
@@ -3326,7 +3383,7 @@ static int icl_ddi_mg_pll_get_freq(struct drm_i915_private *dev_priv,
        u32 m1, m2_int, m2_frac, div1, div2, ref_clock;
        u64 tmp;
 
-       ref_clock = dev_priv->cdclk.hw.ref;
+       ref_clock = dev_priv->dpll.ref_clks.nssc;
 
        if (INTEL_GEN(dev_priv) >= 12) {
                m1 = pll_state->mg_pll_div0 & DKL_PLL_DIV0_FBPREDIV_MASK;
@@ -3475,12 +3532,6 @@ static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state,
        return true;
 }
 
-static int icl_ddi_combo_pll_get_freq(struct drm_i915_private *i915,
-                                     const struct intel_shared_dpll *pll)
-{
-       return cnl_ddi_wrpll_get_freq(i915, pll);
-}
-
 static bool icl_get_tc_phy_dplls(struct intel_atomic_state *state,
                                 struct intel_crtc *crtc,
                                 struct intel_encoder *encoder)
@@ -3629,7 +3680,7 @@ static bool mg_pll_get_hw_state(struct drm_i915_private *dev_priv,
        hw_state->mg_pll_tdc_coldst_bias =
                intel_de_read(dev_priv, MG_PLL_TDC_COLDST_BIAS(tc_port));
 
-       if (dev_priv->cdclk.hw.ref == 38400) {
+       if (dev_priv->dpll.ref_clks.nssc == 38400) {
                hw_state->mg_pll_tdc_coldst_bias_mask = MG_PLL_TDC_COLDST_COLDSTART;
                hw_state->mg_pll_bias_mask = 0;
        } else {
@@ -4110,6 +4161,12 @@ static void mg_pll_disable(struct drm_i915_private *dev_priv,
        icl_pll_disable(dev_priv, pll, enable_reg);
 }
 
+static void icl_update_dpll_ref_clks(struct drm_i915_private *i915)
+{
+       /* No SSC ref */
+       i915->dpll.ref_clks.nssc = i915->cdclk.hw.ref;
+}
+
 static void icl_dump_hw_state(struct drm_i915_private *dev_priv,
                              const struct intel_dpll_hw_state *hw_state)
 {
@@ -4170,6 +4227,7 @@ static const struct intel_dpll_mgr icl_pll_mgr = {
        .get_dplls = icl_get_dplls,
        .put_dplls = icl_put_dplls,
        .update_active_dpll = icl_update_active_dpll,
+       .update_ref_clks = icl_update_dpll_ref_clks,
        .dump_hw_state = icl_dump_hw_state,
 };
 
@@ -4184,6 +4242,7 @@ static const struct intel_dpll_mgr ehl_pll_mgr = {
        .dpll_info = ehl_plls,
        .get_dplls = icl_get_dplls,
        .put_dplls = icl_put_dplls,
+       .update_ref_clks = icl_update_dpll_ref_clks,
        .dump_hw_state = icl_dump_hw_state,
 };
 
@@ -4212,6 +4271,7 @@ static const struct intel_dpll_mgr tgl_pll_mgr = {
        .get_dplls = icl_get_dplls,
        .put_dplls = icl_put_dplls,
        .update_active_dpll = icl_update_active_dpll,
+       .update_ref_clks = icl_update_dpll_ref_clks,
        .dump_hw_state = icl_dump_hw_state,
 };
 
@@ -4390,6 +4450,9 @@ void intel_dpll_readout_hw_state(struct drm_i915_private *i915)
 {
        int i;
 
+       if (i915->dpll.mgr && i915->dpll.mgr->update_ref_clks)
+               i915->dpll.mgr->update_ref_clks(i915);
+
        for (i = 0; i < i915->dpll.num_shared_dpll; i++)
                readout_dpll_hw_state(i915, &i915->dpll.shared_dplls[i]);
 }
index 43a47b7deaa0d7734256f521443e29bad85bce0d..b5134ff66f03923e9caf6be9b96ea61af532fb8b 100644 (file)
@@ -1029,6 +1029,11 @@ struct drm_i915_private {
                int num_shared_dpll;
                struct intel_shared_dpll shared_dplls[I915_NUM_PLLS];
                const struct intel_dpll_mgr *mgr;
+
+               struct {
+                       int nssc;
+                       int ssc;
+               } ref_clks;
        } dpll;
 
        struct list_head global_obj_list;