diff mbox series

[2/5] drm/i915: Factor out skl_wrpll_calc_freq()

Message ID 20200929002929.783620-3-imre.deak@intel.com (mailing list archive)
State New, archived
Headers show
Series drm/i915/tgl: Fix Combo PHY DPLL fractional divider for 38.4MHz ref clock | expand

Commit Message

Imre Deak Sept. 29, 2020, 12:29 a.m. UTC
The WRPLL parameter -> frequency formula is the same for all platforms
starting with SKL. Factor out the helper for this for clarity and so
that we can use the same formula when selecting the ICL WRPLL dividers
for DP mode in an upcoming patch (to cross-check the frequency
calculated using the formula wrt. hard-coded freq values in the ICL DP
PLL tables).

While at it add the MISSING_CASE() for incorrect divider encodings.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 160 +++++++++++-------
 drivers/gpu/drm/i915/i915_reg.h               |   3 +
 2 files changed, 101 insertions(+), 62 deletions(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index 095b53fe3a21..e3370c8dccc8 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -1576,31 +1576,31 @@  static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
 	return true;
 }
 
-static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
-				  const struct intel_shared_dpll *pll)
+static int skl_wrpll_calc_freq(int ref_clock,
+			       u32 dco_integer, u32 dco_fraction,
+			       u32 pdiv, u32 qdiv, u32 kdiv)
 {
-	const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
-	int ref_clock = i915->dpll.ref_clks.nssc;
-	u32 p0, p1, p2, dco_freq;
+	u32 dco_freq;
 
-	p0 = pll_state->cfgcr2 & DPLL_CFGCR2_PDIV_MASK;
-	p2 = pll_state->cfgcr2 & DPLL_CFGCR2_KDIV_MASK;
+	dco_freq = ref_clock * dco_integer;
+	dco_freq += dco_fraction * ref_clock / 0x8000;
 
-	if (pll_state->cfgcr2 &  DPLL_CFGCR2_QDIV_MODE(1))
-		p1 = (pll_state->cfgcr2 & DPLL_CFGCR2_QDIV_RATIO_MASK) >> 8;
-	else
-		p1 = 1;
+	return dco_freq / (pdiv * qdiv * kdiv * 5);
+}
 
-
-	switch (p0) {
+static void skl_wrpll_decode_divs(struct drm_i915_private *i915,
+				  const struct skl_wrpll_params *wrpll_params,
+				  u32 *pdiv, u32 *qdiv, u32 *kdiv)
+{
+	switch (DPLL_CFGCR2_PDIV(wrpll_params->pdiv)) {
 	case DPLL_CFGCR2_PDIV_1:
-		p0 = 1;
+		*pdiv = 1;
 		break;
 	case DPLL_CFGCR2_PDIV_2:
-		p0 = 2;
+		*pdiv = 2;
 		break;
 	case DPLL_CFGCR2_PDIV_3:
-		p0 = 3;
+		*pdiv = 3;
 		break;
 	case DPLL_CFGCR2_PDIV_7 | (1 << DPLL_CFGCR2_PDIV_SHIFT):
 		/*
@@ -1608,38 +1608,63 @@  static int skl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
 		 * handling it the same way as PDIV_7.
 		 */
 		drm_err(&i915->drm, "Invalid WRPLL PDIV divider value, fixing it.\n");
-		p0 = 7;
+		*pdiv = 7;
 		break;
+	default:
+		MISSING_CASE(wrpll_params->pdiv);
+		fallthrough;
 	case DPLL_CFGCR2_PDIV_7:
-		p0 = 7;
+		*pdiv = 7;
 		break;
 	}
 
-	switch (p2) {
+	*qdiv = wrpll_params->qdiv_mode ? wrpll_params->qdiv_ratio : 1;
+
+	switch (DPLL_CFGCR2_KDIV(wrpll_params->kdiv)) {
+	default:
+		MISSING_CASE(wrpll_params->kdiv);
+		fallthrough;
 	case DPLL_CFGCR2_KDIV_5:
-		p2 = 5;
+		*kdiv = 5;
 		break;
 	case DPLL_CFGCR2_KDIV_2:
-		p2 = 2;
+		*kdiv = 2;
 		break;
 	case DPLL_CFGCR2_KDIV_3:
-		p2 = 3;
+		*kdiv = 3;
 		break;
 	case DPLL_CFGCR2_KDIV_1:
-		p2 = 1;
+		*kdiv = 1;
 		break;
 	}
+}
 
-	dco_freq = (pll_state->cfgcr1 & DPLL_CFGCR1_DCO_INTEGER_MASK) *
-		   ref_clock;
+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;
+	struct skl_wrpll_params wrpll_params = { };
+	int ref_clock = i915->dpll.ref_clks.nssc;
+	u32 pdiv;
+	u32 qdiv;
+	u32 kdiv;
+	u32 dco_integer;
+	u32 dco_fraction;
 
-	dco_freq += ((pll_state->cfgcr1 & DPLL_CFGCR1_DCO_FRACTION_MASK) >> 9) *
-		    ref_clock / 0x8000;
+	wrpll_params.pdiv = (pll_state->cfgcr2 & DPLL_CFGCR2_PDIV_MASK) >> DPLL_CFGCR2_PDIV_SHIFT;
+	wrpll_params.kdiv = (pll_state->cfgcr2 & DPLL_CFGCR2_KDIV_MASK) >> DPLL_CFGCR2_KDIV_SHIFT;
 
-	if (drm_WARN_ON(&i915->drm, p0 == 0 || p1 == 0 || p2 == 0))
-		return 0;
+	wrpll_params.qdiv_mode = !!(pll_state->cfgcr2 &  DPLL_CFGCR2_QDIV_MODE(1));
+	wrpll_params.qdiv_ratio = (pll_state->cfgcr2 & DPLL_CFGCR2_QDIV_RATIO_MASK) >>
+				  DPLL_CFGCR2_QDIV_RATIO_SHIFT;
 
-	return dco_freq / (p0 * p1 * p2 * 5);
+	skl_wrpll_decode_divs(i915, &wrpll_params, &pdiv, &qdiv, &kdiv);
+
+	dco_integer = pll_state->cfgcr1 & DPLL_CFGCR1_DCO_INTEGER_MASK;
+	dco_fraction = (pll_state->cfgcr1 & DPLL_CFGCR1_DCO_FRACTION_MASK) >>
+			DPLL_CFGCR1_DCO_FRACTION_SHIFT;
+
+	return skl_wrpll_calc_freq(ref_clock, dco_integer, dco_fraction, pdiv, qdiv, kdiv);
 }
 
 static bool
@@ -2630,60 +2655,71 @@  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,
-				    int ref_clock)
+static void cnl_wrpll_decode_divs(const struct skl_wrpll_params *wrpll_params,
+				  u32 *pdiv, u32 *qdiv, u32 *kdiv)
 {
-	const struct intel_dpll_hw_state *pll_state = &pll->state.hw_state;
-	u32 p0, p1, p2, dco_freq;
-
-	p0 = pll_state->cfgcr1 & DPLL_CFGCR1_PDIV_MASK;
-	p2 = pll_state->cfgcr1 & DPLL_CFGCR1_KDIV_MASK;
-
-	if (pll_state->cfgcr1 & DPLL_CFGCR1_QDIV_MODE(1))
-		p1 = (pll_state->cfgcr1 & DPLL_CFGCR1_QDIV_RATIO_MASK) >>
-			DPLL_CFGCR1_QDIV_RATIO_SHIFT;
-	else
-		p1 = 1;
-
-
-	switch (p0) {
+	switch (DPLL_CFGCR1_PDIV(wrpll_params->pdiv)) {
 	case DPLL_CFGCR1_PDIV_2:
-		p0 = 2;
+		*pdiv = 2;
 		break;
 	case DPLL_CFGCR1_PDIV_3:
-		p0 = 3;
+		*pdiv = 3;
 		break;
 	case DPLL_CFGCR1_PDIV_5:
-		p0 = 5;
+		*pdiv = 5;
 		break;
+	default:
+		MISSING_CASE(wrpll_params->pdiv);
+		fallthrough;
 	case DPLL_CFGCR1_PDIV_7:
-		p0 = 7;
+		*pdiv = 7;
 		break;
 	}
 
-	switch (p2) {
+	*qdiv = wrpll_params->qdiv_mode ? wrpll_params->qdiv_ratio : 1;
+
+	switch (DPLL_CFGCR1_KDIV(wrpll_params->kdiv)) {
 	case DPLL_CFGCR1_KDIV_1:
-		p2 = 1;
+		*kdiv = 1;
 		break;
 	case DPLL_CFGCR1_KDIV_2:
-		p2 = 2;
+		*kdiv = 2;
 		break;
+	default:
+		MISSING_CASE(wrpll_params->kdiv);
+		fallthrough;
 	case DPLL_CFGCR1_KDIV_3:
-		p2 = 3;
+		*kdiv = 3;
 		break;
 	}
+}
 
-	dco_freq = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK) *
-		   ref_clock;
+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;
+	struct skl_wrpll_params wrpll_params = { };
+	u32 pdiv;
+	u32 qdiv;
+	u32 kdiv;
+	u32 dco_integer;
+	u32 dco_fraction;
 
-	dco_freq += (((pll_state->cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >>
-		      DPLL_CFGCR0_DCO_FRACTION_SHIFT) * ref_clock) / 0x8000;
+	wrpll_params.pdiv = (pll_state->cfgcr1 & DPLL_CFGCR1_PDIV_MASK) >> DPLL_CFGCR1_PDIV_SHIFT;
+	wrpll_params.kdiv = (pll_state->cfgcr1 & DPLL_CFGCR1_KDIV_MASK) >> DPLL_CFGCR1_KDIV_SHIFT;
 
-	if (drm_WARN_ON(&dev_priv->drm, p0 == 0 || p1 == 0 || p2 == 0))
-		return 0;
+	wrpll_params.qdiv_mode = !!(pll_state->cfgcr1 & DPLL_CFGCR1_QDIV_MODE(1));
+	wrpll_params.qdiv_ratio = (pll_state->cfgcr1 & DPLL_CFGCR1_QDIV_RATIO_MASK) >>
+				  DPLL_CFGCR1_QDIV_RATIO_SHIFT;
 
-	return dco_freq / (p0 * p1 * p2 * 5);
+	cnl_wrpll_decode_divs(&wrpll_params, &pdiv, &qdiv, &kdiv);
+
+	dco_integer = pll_state->cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK;
+	dco_fraction = (pll_state->cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >>
+		       DPLL_CFGCR0_DCO_FRACTION_SHIFT;
+
+	return skl_wrpll_calc_freq(ref_clock, dco_integer, dco_fraction, pdiv, qdiv, kdiv);
 }
 
 static int cnl_ddi_wrpll_get_freq(struct drm_i915_private *i915,
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index f70e45bd3810..4409c712030c 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -10237,6 +10237,7 @@  enum skl_power_gate {
 #define _DPLL3_CFGCR1	0x6C050
 #define  DPLL_CFGCR1_FREQ_ENABLE	(1 << 31)
 #define  DPLL_CFGCR1_DCO_FRACTION_MASK	(0x7fff << 9)
+#define  DPLL_CFGCR1_DCO_FRACTION_SHIFT	9
 #define  DPLL_CFGCR1_DCO_FRACTION(x)	((x) << 9)
 #define  DPLL_CFGCR1_DCO_INTEGER_MASK	(0x1ff)
 
@@ -10244,9 +10245,11 @@  enum skl_power_gate {
 #define _DPLL2_CFGCR2	0x6C04C
 #define _DPLL3_CFGCR2	0x6C054
 #define  DPLL_CFGCR2_QDIV_RATIO_MASK	(0xff << 8)
+#define  DPLL_CFGCR2_QDIV_RATIO_SHIFT	8
 #define  DPLL_CFGCR2_QDIV_RATIO(x)	((x) << 8)
 #define  DPLL_CFGCR2_QDIV_MODE(x)	((x) << 7)
 #define  DPLL_CFGCR2_KDIV_MASK		(3 << 5)
+#define  DPLL_CFGCR2_KDIV_SHIFT		5
 #define  DPLL_CFGCR2_KDIV(x)		((x) << 5)
 #define  DPLL_CFGCR2_KDIV_5 (0 << 5)
 #define  DPLL_CFGCR2_KDIV_2 (1 << 5)