Patches merged to dinq, thanks for the patches and reviews!<br><br><div class="gmail_quote"><div dir="ltr">On Fri, Jun 9, 2017 at 3:27 PM Rodrigo Vivi <<a href="mailto:rodrigo.vivi@intel.com">rodrigo.vivi@intel.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: "Kahola, Mika" <<a href="mailto:mika.kahola@intel.com" target="_blank">mika.kahola@intel.com</a>><br>
<br>
Enable wrpll computation for Cannonlake platform to support<br>
pll's required for HDMI output. The patch contains the following features<br>
<br>
- compute Cannonlake port clock programming<br>
  dividers P, Q, and K.<br>
- compute PLL parameters for Cannonlake. These parameters<br>
  set the values on DPLL registers.<br>
- find the register values to program wrpll for Cannonlake.<br>
  The reference clock can be either 19.2MHz or 24MHz.<br>
<br>
v2: rebase<br>
v3: squash wrpll patches into one (Rodrigo)<br>
v4: switch order of getting even dividers (Paulo)<br>
    update divider register values for PDiv and KDiv (Paulo)<br>
    update wrpll computation algorithm (Paulo)<br>
v5: Remove ref clock division by 1000. (Rodrigo)<br>
v6: Rodrigo rebasing on top of latest code.<br>
<br>
Signed-off-by: Kahola, Mika <<a href="mailto:mika.kahola@intel.com" target="_blank">mika.kahola@intel.com</a>><br>
Signed-off-by: Rodrigo Vivi <<a href="mailto:rodrigo.vivi@intel.com" target="_blank">rodrigo.vivi@intel.com</a>><br>
Reviewed-by: Clint Taylor <<a href="mailto:Clinton.A.Taylor@intel.com" target="_blank">Clinton.A.Taylor@intel.com</a>><br>
---<br>
 drivers/gpu/drm/i915/intel_dpll_mgr.c | 140 +++++++++++++++++++++++++++++++++-<br>
 1 file changed, 138 insertions(+), 2 deletions(-)<br>
<br>
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c<br>
index 903c38d..8e669b6 100644<br>
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c<br>
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c<br>
@@ -2126,17 +2126,153 @@ static bool cnl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,<br>
        return ret;<br>
 }<br>
<br>
+static void cnl_wrpll_get_multipliers(unsigned int bestdiv,<br>
+                                     unsigned int *pdiv,<br>
+                                     unsigned int *qdiv,<br>
+                                     unsigned int *kdiv)<br>
+{<br>
+       /* even dividers */<br>
+       if (bestdiv % 2 == 0) {<br>
+               if (bestdiv == 2) {<br>
+                       *pdiv = 2;<br>
+                       *qdiv = 1;<br>
+                       *kdiv = 1;<br>
+               } else if (bestdiv % 4 == 0) {<br>
+                       *pdiv = 2;<br>
+                       *qdiv = bestdiv / 4;<br>
+                       *kdiv = 2;<br>
+               } else if (bestdiv % 6 == 0) {<br>
+                       *pdiv = 3;<br>
+                       *qdiv = bestdiv / 6;<br>
+                       *kdiv = 2;<br>
+               } else if (bestdiv % 5 == 0) {<br>
+                       *pdiv = 5;<br>
+                       *qdiv = bestdiv / 10;<br>
+                       *kdiv = 2;<br>
+               } else if (bestdiv % 14 == 0) {<br>
+                       *pdiv = 7;<br>
+                       *qdiv = bestdiv / 14;<br>
+                       *kdiv = 2;<br>
+               }<br>
+       } else {<br>
+               if (bestdiv == 3 || bestdiv == 5 || bestdiv == 7) {<br>
+                       *pdiv = bestdiv;<br>
+                       *qdiv = 1;<br>
+                       *kdiv = 1;<br>
+               } else { /* 9, 15, 21 */<br>
+                       *pdiv = bestdiv / 3;<br>
+                       *qdiv = 1;<br>
+                       *kdiv = 3;<br>
+               }<br>
+       }<br>
+}<br>
+<br>
+static void cnl_wrpll_params_populate(struct skl_wrpll_params *params, uint32_t dco_freq,<br>
+                                     uint32_t ref_freq, uint32_t pdiv, uint32_t qdiv,<br>
+                                     uint32_t kdiv)<br>
+{<br>
+       switch (kdiv) {<br>
+       case 1:<br>
+               params->kdiv = 1;<br>
+               break;<br>
+       case 2:<br>
+               params->kdiv = 2;<br>
+               break;<br>
+       case 3:<br>
+               params->kdiv = 4;<br>
+               break;<br>
+       default:<br>
+               WARN(1, "Incorrect KDiv\n");<br>
+       }<br>
+<br>
+       switch (pdiv) {<br>
+       case 2:<br>
+               params->pdiv = 1;<br>
+               break;<br>
+       case 3:<br>
+               params->pdiv = 2;<br>
+               break;<br>
+       case 5:<br>
+               params->pdiv = 4;<br>
+               break;<br>
+       case 7:<br>
+               params->pdiv = 8;<br>
+               break;<br>
+       default:<br>
+               WARN(1, "Incorrect PDiv\n");<br>
+       }<br>
+<br>
+       if (kdiv != 2)<br>
+               qdiv = 1;<br>
+<br>
+       params->qdiv_ratio = qdiv;<br>
+       params->qdiv_mode = (qdiv == 1) ? 0 : 1;<br>
+<br>
+       params->dco_integer = div_u64(dco_freq, ref_freq);<br>
+       params->dco_fraction = div_u64((div_u64((uint64_t)dco_freq<<15, (uint64_t)ref_freq) -<br>
+                                       ((uint64_t)params->dco_integer<<15)) * 0x8000, 0x8000);<br>
+}<br>
+<br>
+static bool<br>
+cnl_ddi_calculate_wrpll(int clock /* in Hz */,<br>
+                       struct drm_i915_private *dev_priv,<br>
+                       struct skl_wrpll_params *wrpll_params)<br>
+{<br>
+       uint64_t afe_clock = clock * 5 / KHz(1); /* clocks in kHz */<br>
+       unsigned int dco_min = 7998 * KHz(1);<br>
+       unsigned int dco_max = 10000 * KHz(1);<br>
+       unsigned int dco_mid = (dco_min + dco_max) / 2;<br>
+<br>
+       static const int dividers[] = {  2,  4,  6,  8, 10, 12,  14,  16,<br>
+                                        18, 20, 24, 28, 30, 32,  36,  40,<br>
+                                        42, 44, 48, 50, 52, 54,  56,  60,<br>
+                                        64, 66, 68, 70, 72, 76,  78,  80,<br>
+                                        84, 88, 90, 92, 96, 98, 100, 102,<br>
+                                         3,  5,  7,  9, 15, 21 };<br>
+       unsigned int d, dco;<br>
+       unsigned int dco_centrality = 0;<br>
+       unsigned int best_dco_centrality = 999999;<br>
+       unsigned int best_div = 0;<br>
+       unsigned int best_dco = 0;<br>
+       unsigned int pdiv = 0, qdiv = 0, kdiv = 0;<br>
+<br>
+       for (d = 0; d < ARRAY_SIZE(dividers); d++) {<br>
+               dco = afe_clock * dividers[d];<br>
+<br>
+               if ((dco <= dco_max) && (dco >= dco_min)) {<br>
+                       dco_centrality = abs(dco - dco_mid);<br>
+<br>
+                       if (dco_centrality < best_dco_centrality) {<br>
+                               best_dco_centrality = dco_centrality;<br>
+                               best_div = dividers[d];<br>
+                               best_dco = dco;<br>
+                       }<br>
+               }<br>
+       }<br>
+<br>
+       if (best_div == 0)<br>
+               return false;<br>
+<br>
+       cnl_wrpll_get_multipliers(best_div, &pdiv, &qdiv, &kdiv);<br>
+<br>
+       cnl_wrpll_params_populate(wrpll_params, best_dco,<br>
+                                 dev_priv->cdclk.hw.ref, pdiv, qdiv, kdiv);<br>
+<br>
+       return true;<br>
+}<br>
+<br>
 static bool cnl_ddi_hdmi_pll_dividers(struct intel_crtc *crtc,<br>
                                      struct intel_crtc_state *crtc_state,<br>
                                      int clock)<br>
 {<br>
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);<br>
        uint32_t cfgcr0, cfgcr1;<br>
        struct skl_wrpll_params wrpll_params = { 0, };<br>
<br>
        cfgcr0 = DPLL_CFGCR0_HDMI_MODE;<br>
<br>
-       /* FIXME: Proper wrpll calculation done in a following patch */<br>
-       return false;<br>
+       if (!cnl_ddi_calculate_wrpll(clock * 1000, dev_priv, &wrpll_params))<br>
+               return false;<br>
<br>
        cfgcr0 |= DPLL_CFGCR0_DCO_FRACTION(wrpll_params.dco_fraction) |<br>
                wrpll_params.dco_integer;<br>
--<br>
1.9.1<br>
<br>
_______________________________________________<br>
Intel-gfx mailing list<br>
<a href="mailto:Intel-gfx@lists.freedesktop.org" target="_blank">Intel-gfx@lists.freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/intel-gfx" rel="noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/intel-gfx</a><br>
</blockquote></div>