drm/i915: Move SKL/KLB pll selection logic to intel_dpll_mgr.c
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Tue, 8 Mar 2016 15:46:24 +0000 (17:46 +0200)
committerAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Wed, 9 Mar 2016 09:55:31 +0000 (11:55 +0200)
Move the code for selecting plls for SKL/KLB into the shared dpll code,
so that the platform specific details are hidden behind that interface.

Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1457451987-17466-11-git-send-email-ander.conselvan.de.oliveira@intel.com
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_dpll_mgr.c

index eae3ce2..2890675 100644 (file)
@@ -1005,311 +1005,15 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
        }
 }
 
-struct skl_wrpll_context {
-       uint64_t min_deviation;         /* current minimal deviation */
-       uint64_t central_freq;          /* chosen central freq */
-       uint64_t dco_freq;              /* chosen dco freq */
-       unsigned int p;                 /* chosen divider */
-};
-
-static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
-{
-       memset(ctx, 0, sizeof(*ctx));
-
-       ctx->min_deviation = U64_MAX;
-}
-
-/* DCO freq must be within +1%/-6%  of the DCO central freq */
-#define SKL_DCO_MAX_PDEVIATION 100
-#define SKL_DCO_MAX_NDEVIATION 600
-
-static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
-                                 uint64_t central_freq,
-                                 uint64_t dco_freq,
-                                 unsigned int divider)
-{
-       uint64_t deviation;
-
-       deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
-                             central_freq);
-
-       /* positive deviation */
-       if (dco_freq >= central_freq) {
-               if (deviation < SKL_DCO_MAX_PDEVIATION &&
-                   deviation < ctx->min_deviation) {
-                       ctx->min_deviation = deviation;
-                       ctx->central_freq = central_freq;
-                       ctx->dco_freq = dco_freq;
-                       ctx->p = divider;
-               }
-       /* negative deviation */
-       } else if (deviation < SKL_DCO_MAX_NDEVIATION &&
-                  deviation < ctx->min_deviation) {
-               ctx->min_deviation = deviation;
-               ctx->central_freq = central_freq;
-               ctx->dco_freq = dco_freq;
-               ctx->p = divider;
-       }
-}
-
-static void skl_wrpll_get_multipliers(unsigned int p,
-                                     unsigned int *p0 /* out */,
-                                     unsigned int *p1 /* out */,
-                                     unsigned int *p2 /* out */)
-{
-       /* even dividers */
-       if (p % 2 == 0) {
-               unsigned int half = p / 2;
-
-               if (half == 1 || half == 2 || half == 3 || half == 5) {
-                       *p0 = 2;
-                       *p1 = 1;
-                       *p2 = half;
-               } else if (half % 2 == 0) {
-                       *p0 = 2;
-                       *p1 = half / 2;
-                       *p2 = 2;
-               } else if (half % 3 == 0) {
-                       *p0 = 3;
-                       *p1 = half / 3;
-                       *p2 = 2;
-               } else if (half % 7 == 0) {
-                       *p0 = 7;
-                       *p1 = half / 7;
-                       *p2 = 2;
-               }
-       } else if (p == 3 || p == 9) {  /* 3, 5, 7, 9, 15, 21, 35 */
-               *p0 = 3;
-               *p1 = 1;
-               *p2 = p / 3;
-       } else if (p == 5 || p == 7) {
-               *p0 = p;
-               *p1 = 1;
-               *p2 = 1;
-       } else if (p == 15) {
-               *p0 = 3;
-               *p1 = 1;
-               *p2 = 5;
-       } else if (p == 21) {
-               *p0 = 7;
-               *p1 = 1;
-               *p2 = 3;
-       } else if (p == 35) {
-               *p0 = 7;
-               *p1 = 1;
-               *p2 = 5;
-       }
-}
-
-struct skl_wrpll_params {
-       uint32_t        dco_fraction;
-       uint32_t        dco_integer;
-       uint32_t        qdiv_ratio;
-       uint32_t        qdiv_mode;
-       uint32_t        kdiv;
-       uint32_t        pdiv;
-       uint32_t        central_freq;
-};
-
-static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
-                                     uint64_t afe_clock,
-                                     uint64_t central_freq,
-                                     uint32_t p0, uint32_t p1, uint32_t p2)
-{
-       uint64_t dco_freq;
-
-       switch (central_freq) {
-       case 9600000000ULL:
-               params->central_freq = 0;
-               break;
-       case 9000000000ULL:
-               params->central_freq = 1;
-               break;
-       case 8400000000ULL:
-               params->central_freq = 3;
-       }
-
-       switch (p0) {
-       case 1:
-               params->pdiv = 0;
-               break;
-       case 2:
-               params->pdiv = 1;
-               break;
-       case 3:
-               params->pdiv = 2;
-               break;
-       case 7:
-               params->pdiv = 4;
-               break;
-       default:
-               WARN(1, "Incorrect PDiv\n");
-       }
-
-       switch (p2) {
-       case 5:
-               params->kdiv = 0;
-               break;
-       case 2:
-               params->kdiv = 1;
-               break;
-       case 3:
-               params->kdiv = 2;
-               break;
-       case 1:
-               params->kdiv = 3;
-               break;
-       default:
-               WARN(1, "Incorrect KDiv\n");
-       }
-
-       params->qdiv_ratio = p1;
-       params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
-
-       dco_freq = p0 * p1 * p2 * afe_clock;
-
-       /*
-        * Intermediate values are in Hz.
-        * Divide by MHz to match bsepc
-        */
-       params->dco_integer = div_u64(dco_freq, 24 * MHz(1));
-       params->dco_fraction =
-               div_u64((div_u64(dco_freq, 24) -
-                        params->dco_integer * MHz(1)) * 0x8000, MHz(1));
-}
-
-static bool
-skl_ddi_calculate_wrpll(int clock /* in Hz */,
-                       struct skl_wrpll_params *wrpll_params)
-{
-       uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
-       uint64_t dco_central_freq[3] = {8400000000ULL,
-                                       9000000000ULL,
-                                       9600000000ULL};
-       static const int even_dividers[] = {  4,  6,  8, 10, 12, 14, 16, 18, 20,
-                                            24, 28, 30, 32, 36, 40, 42, 44,
-                                            48, 52, 54, 56, 60, 64, 66, 68,
-                                            70, 72, 76, 78, 80, 84, 88, 90,
-                                            92, 96, 98 };
-       static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
-       static const struct {
-               const int *list;
-               int n_dividers;
-       } dividers[] = {
-               { even_dividers, ARRAY_SIZE(even_dividers) },
-               { odd_dividers, ARRAY_SIZE(odd_dividers) },
-       };
-       struct skl_wrpll_context ctx;
-       unsigned int dco, d, i;
-       unsigned int p0, p1, p2;
-
-       skl_wrpll_context_init(&ctx);
-
-       for (d = 0; d < ARRAY_SIZE(dividers); d++) {
-               for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
-                       for (i = 0; i < dividers[d].n_dividers; i++) {
-                               unsigned int p = dividers[d].list[i];
-                               uint64_t dco_freq = p * afe_clock;
-
-                               skl_wrpll_try_divider(&ctx,
-                                                     dco_central_freq[dco],
-                                                     dco_freq,
-                                                     p);
-                               /*
-                                * Skip the remaining dividers if we're sure to
-                                * have found the definitive divider, we can't
-                                * improve a 0 deviation.
-                                */
-                               if (ctx.min_deviation == 0)
-                                       goto skip_remaining_dividers;
-                       }
-               }
-
-skip_remaining_dividers:
-               /*
-                * If a solution is found with an even divider, prefer
-                * this one.
-                */
-               if (d == 0 && ctx.p)
-                       break;
-       }
-
-       if (!ctx.p) {
-               DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
-               return false;
-       }
-
-       /*
-        * gcc incorrectly analyses that these can be used without being
-        * initialized. To be fair, it's hard to guess.
-        */
-       p0 = p1 = p2 = 0;
-       skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
-       skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq,
-                                 p0, p1, p2);
-
-       return true;
-}
-
 static bool
 skl_ddi_pll_select(struct intel_crtc *intel_crtc,
                   struct intel_crtc_state *crtc_state,
                   struct intel_encoder *intel_encoder)
 {
        struct intel_shared_dpll *pll;
-       uint32_t ctrl1, cfgcr1, cfgcr2;
-       int clock = crtc_state->port_clock;
 
-       /*
-        * See comment in intel_dpll_hw_state to understand why we always use 0
-        * as the DPLL id in this function.
-        */
-
-       ctrl1 = DPLL_CTRL1_OVERRIDE(0);
-
-       if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
-               struct skl_wrpll_params wrpll_params = { 0, };
-
-               ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
-
-               if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
-                       return false;
-
-               cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
-                        DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
-                        wrpll_params.dco_integer;
-
-               cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
-                        DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
-                        DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
-                        DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
-                        wrpll_params.central_freq;
-       } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
-                  intel_encoder->type == INTEL_OUTPUT_DP_MST) {
-               switch (crtc_state->port_clock / 2) {
-               case 81000:
-                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
-                       break;
-               case 135000:
-                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
-                       break;
-               case 270000:
-                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
-                       break;
-               }
-
-               cfgcr1 = cfgcr2 = 0;
-       } else if (intel_encoder->type == INTEL_OUTPUT_EDP) {
+       if (intel_encoder->type == INTEL_OUTPUT_EDP)
                return true;
-       } else
-               return false;
-
-       memset(&crtc_state->dpll_hw_state, 0,
-              sizeof(crtc_state->dpll_hw_state));
-
-       crtc_state->dpll_hw_state.ctrl1 = ctrl1;
-       crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
-       crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
 
        pll = intel_get_shared_dpll(intel_crtc, crtc_state, intel_encoder);
        if (pll == NULL) {
@@ -1318,9 +1022,6 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
                return false;
        }
 
-       /* shared DPLL id 0 is DPLL 1 */
-       crtc_state->ddi_pll_sel = pll->id + 1;
-
        return true;
 }
 
index 224c896..61887ae 100644 (file)
@@ -837,16 +837,319 @@ out:
        return ret;
 }
 
+struct skl_wrpll_context {
+       uint64_t min_deviation;         /* current minimal deviation */
+       uint64_t central_freq;          /* chosen central freq */
+       uint64_t dco_freq;              /* chosen dco freq */
+       unsigned int p;                 /* chosen divider */
+};
+
+static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
+{
+       memset(ctx, 0, sizeof(*ctx));
+
+       ctx->min_deviation = U64_MAX;
+}
+
+/* DCO freq must be within +1%/-6%  of the DCO central freq */
+#define SKL_DCO_MAX_PDEVIATION 100
+#define SKL_DCO_MAX_NDEVIATION 600
+
+static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
+                                 uint64_t central_freq,
+                                 uint64_t dco_freq,
+                                 unsigned int divider)
+{
+       uint64_t deviation;
+
+       deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
+                             central_freq);
+
+       /* positive deviation */
+       if (dco_freq >= central_freq) {
+               if (deviation < SKL_DCO_MAX_PDEVIATION &&
+                   deviation < ctx->min_deviation) {
+                       ctx->min_deviation = deviation;
+                       ctx->central_freq = central_freq;
+                       ctx->dco_freq = dco_freq;
+                       ctx->p = divider;
+               }
+       /* negative deviation */
+       } else if (deviation < SKL_DCO_MAX_NDEVIATION &&
+                  deviation < ctx->min_deviation) {
+               ctx->min_deviation = deviation;
+               ctx->central_freq = central_freq;
+               ctx->dco_freq = dco_freq;
+               ctx->p = divider;
+       }
+}
+
+static void skl_wrpll_get_multipliers(unsigned int p,
+                                     unsigned int *p0 /* out */,
+                                     unsigned int *p1 /* out */,
+                                     unsigned int *p2 /* out */)
+{
+       /* even dividers */
+       if (p % 2 == 0) {
+               unsigned int half = p / 2;
+
+               if (half == 1 || half == 2 || half == 3 || half == 5) {
+                       *p0 = 2;
+                       *p1 = 1;
+                       *p2 = half;
+               } else if (half % 2 == 0) {
+                       *p0 = 2;
+                       *p1 = half / 2;
+                       *p2 = 2;
+               } else if (half % 3 == 0) {
+                       *p0 = 3;
+                       *p1 = half / 3;
+                       *p2 = 2;
+               } else if (half % 7 == 0) {
+                       *p0 = 7;
+                       *p1 = half / 7;
+                       *p2 = 2;
+               }
+       } else if (p == 3 || p == 9) {  /* 3, 5, 7, 9, 15, 21, 35 */
+               *p0 = 3;
+               *p1 = 1;
+               *p2 = p / 3;
+       } else if (p == 5 || p == 7) {
+               *p0 = p;
+               *p1 = 1;
+               *p2 = 1;
+       } else if (p == 15) {
+               *p0 = 3;
+               *p1 = 1;
+               *p2 = 5;
+       } else if (p == 21) {
+               *p0 = 7;
+               *p1 = 1;
+               *p2 = 3;
+       } else if (p == 35) {
+               *p0 = 7;
+               *p1 = 1;
+               *p2 = 5;
+       }
+}
+
+struct skl_wrpll_params {
+       uint32_t        dco_fraction;
+       uint32_t        dco_integer;
+       uint32_t        qdiv_ratio;
+       uint32_t        qdiv_mode;
+       uint32_t        kdiv;
+       uint32_t        pdiv;
+       uint32_t        central_freq;
+};
+
+static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
+                                     uint64_t afe_clock,
+                                     uint64_t central_freq,
+                                     uint32_t p0, uint32_t p1, uint32_t p2)
+{
+       uint64_t dco_freq;
+
+       switch (central_freq) {
+       case 9600000000ULL:
+               params->central_freq = 0;
+               break;
+       case 9000000000ULL:
+               params->central_freq = 1;
+               break;
+       case 8400000000ULL:
+               params->central_freq = 3;
+       }
+
+       switch (p0) {
+       case 1:
+               params->pdiv = 0;
+               break;
+       case 2:
+               params->pdiv = 1;
+               break;
+       case 3:
+               params->pdiv = 2;
+               break;
+       case 7:
+               params->pdiv = 4;
+               break;
+       default:
+               WARN(1, "Incorrect PDiv\n");
+       }
+
+       switch (p2) {
+       case 5:
+               params->kdiv = 0;
+               break;
+       case 2:
+               params->kdiv = 1;
+               break;
+       case 3:
+               params->kdiv = 2;
+               break;
+       case 1:
+               params->kdiv = 3;
+               break;
+       default:
+               WARN(1, "Incorrect KDiv\n");
+       }
+
+       params->qdiv_ratio = p1;
+       params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
+
+       dco_freq = p0 * p1 * p2 * afe_clock;
+
+       /*
+        * Intermediate values are in Hz.
+        * Divide by MHz to match bsepc
+        */
+       params->dco_integer = div_u64(dco_freq, 24 * MHz(1));
+       params->dco_fraction =
+               div_u64((div_u64(dco_freq, 24) -
+                        params->dco_integer * MHz(1)) * 0x8000, MHz(1));
+}
+
+static bool
+skl_ddi_calculate_wrpll(int clock /* in Hz */,
+                       struct skl_wrpll_params *wrpll_params)
+{
+       uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
+       uint64_t dco_central_freq[3] = {8400000000ULL,
+                                       9000000000ULL,
+                                       9600000000ULL};
+       static const int even_dividers[] = {  4,  6,  8, 10, 12, 14, 16, 18, 20,
+                                            24, 28, 30, 32, 36, 40, 42, 44,
+                                            48, 52, 54, 56, 60, 64, 66, 68,
+                                            70, 72, 76, 78, 80, 84, 88, 90,
+                                            92, 96, 98 };
+       static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
+       static const struct {
+               const int *list;
+               int n_dividers;
+       } dividers[] = {
+               { even_dividers, ARRAY_SIZE(even_dividers) },
+               { odd_dividers, ARRAY_SIZE(odd_dividers) },
+       };
+       struct skl_wrpll_context ctx;
+       unsigned int dco, d, i;
+       unsigned int p0, p1, p2;
+
+       skl_wrpll_context_init(&ctx);
+
+       for (d = 0; d < ARRAY_SIZE(dividers); d++) {
+               for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
+                       for (i = 0; i < dividers[d].n_dividers; i++) {
+                               unsigned int p = dividers[d].list[i];
+                               uint64_t dco_freq = p * afe_clock;
+
+                               skl_wrpll_try_divider(&ctx,
+                                                     dco_central_freq[dco],
+                                                     dco_freq,
+                                                     p);
+                               /*
+                                * Skip the remaining dividers if we're sure to
+                                * have found the definitive divider, we can't
+                                * improve a 0 deviation.
+                                */
+                               if (ctx.min_deviation == 0)
+                                       goto skip_remaining_dividers;
+                       }
+               }
+
+skip_remaining_dividers:
+               /*
+                * If a solution is found with an even divider, prefer
+                * this one.
+                */
+               if (d == 0 && ctx.p)
+                       break;
+       }
+
+       if (!ctx.p) {
+               DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
+               return false;
+       }
+
+       /*
+        * gcc incorrectly analyses that these can be used without being
+        * initialized. To be fair, it's hard to guess.
+        */
+       p0 = p1 = p2 = 0;
+       skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
+       skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq,
+                                 p0, p1, p2);
+
+       return true;
+}
+
 static struct intel_shared_dpll *
 skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
             struct intel_encoder *encoder)
 {
        struct intel_shared_dpll *pll;
+       uint32_t ctrl1, cfgcr1, cfgcr2;
+       int clock = crtc_state->port_clock;
+
+       /*
+        * See comment in intel_dpll_hw_state to understand why we always use 0
+        * as the DPLL id in this function.
+        */
+
+       ctrl1 = DPLL_CTRL1_OVERRIDE(0);
+
+       if (encoder->type == INTEL_OUTPUT_HDMI) {
+               struct skl_wrpll_params wrpll_params = { 0, };
+
+               ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
+
+               if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
+                       return false;
+
+               cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
+                        DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
+                        wrpll_params.dco_integer;
+
+               cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
+                        DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
+                        DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
+                        DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
+                        wrpll_params.central_freq;
+       } else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+                  encoder->type == INTEL_OUTPUT_DP_MST) {
+               switch (crtc_state->port_clock / 2) {
+               case 81000:
+                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
+                       break;
+               case 135000:
+                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
+                       break;
+               case 270000:
+                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
+                       break;
+               }
+
+               cfgcr1 = cfgcr2 = 0;
+       } else {
+               return NULL;
+       }
+
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
+
+       crtc_state->dpll_hw_state.ctrl1 = ctrl1;
+       crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
+       crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
 
        pll = intel_find_shared_dpll(crtc, crtc_state,
                                     DPLL_ID_SKL_DPLL1, DPLL_ID_SKL_DPLL3);
-       if (pll)
-               intel_reference_shared_dpll(pll, crtc_state);
+       if (!pll)
+               return NULL;
+
+       /* shared DPLL id 0 is DPLL 1 */
+       crtc_state->ddi_pll_sel = pll->id + 1;
+
+       intel_reference_shared_dpll(pll, crtc_state);
 
        return pll;
 }