drm/i915: Make SKL/KBL DPLL0 managed by the shared dpll code
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Tue, 8 Mar 2016 15:46:27 +0000 (17:46 +0200)
committerAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Wed, 9 Mar 2016 09:55:32 +0000 (11:55 +0200)
Include DPLL0 in the managed dplls for SKL/KBL. While it has to be kept
enabled because of it driving CDCLK, it is better to special case that
inside the DPLL code than in the higher level.

v2: Use INTEL_DPLL_ALWAYS_ON flag. (Ander)

v3: Remove extremely paranoid WARN_ONs. (Maarten)
    Handle DPLL0 in skylake_get_ddi_pll() properly. (Ander)

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-14-git-send-email-ander.conselvan.de.oliveira@intel.com
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dpll_mgr.c
drivers/gpu/drm/i915/intel_dpll_mgr.h

index 31f9aa0..91654ff 100644 (file)
@@ -1008,9 +1008,6 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
 {
        struct intel_shared_dpll *pll;
 
-       if (intel_encoder->type == INTEL_OUTPUT_EDP)
-               return true;
-
        pll = intel_get_shared_dpll(intel_crtc, crtc_state, intel_encoder);
        if (pll == NULL) {
                DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
@@ -1570,24 +1567,6 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
                uint32_t dpll = pipe_config->ddi_pll_sel;
                uint32_t val;
 
-               /*
-                * DPLL0 is used for eDP and is the only "private" DPLL (as
-                * opposed to shared) on SKL
-                */
-               if (encoder->type == INTEL_OUTPUT_EDP) {
-                       WARN_ON(dpll != SKL_DPLL0);
-
-                       val = I915_READ(DPLL_CTRL1);
-
-                       val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) |
-                                DPLL_CTRL1_SSC(dpll) |
-                                DPLL_CTRL1_LINK_RATE_MASK(dpll));
-                       val |= pipe_config->dpll_hw_state.ctrl1 << (dpll * 6);
-
-                       I915_WRITE(DPLL_CTRL1, val);
-                       POSTING_READ(DPLL_CTRL1);
-               }
-
                /* DDI -> PLL mapping  */
                val = I915_READ(DPLL_CTRL2);
 
index 7e00ee5..28556a8 100644 (file)
@@ -9771,21 +9771,15 @@ static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
                                struct intel_crtc_state *pipe_config)
 {
        enum intel_dpll_id id;
-       u32 temp, dpll_ctl1;
+       u32 temp;
 
        temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
        pipe_config->ddi_pll_sel = temp >> (port * 3 + 1);
 
        switch (pipe_config->ddi_pll_sel) {
        case SKL_DPLL0:
-               /*
-                * On SKL the eDP DPLL (DPLL0 as we don't use SSC) is not part
-                * of the shared DPLL framework and thus needs to be read out
-                * separately
-                */
-               dpll_ctl1 = I915_READ(DPLL_CTRL1);
-               pipe_config->dpll_hw_state.ctrl1 = dpll_ctl1 & 0x3f;
-               return;
+               id = DPLL_ID_SKL_DPLL0;
+               break;
        case SKL_DPLL1:
                id = DPLL_ID_SKL_DPLL1;
                break;
index 4f0fad3..13e1cc8 100644 (file)
@@ -1237,52 +1237,6 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector)
        intel_connector_unregister(intel_connector);
 }
 
-static void
-skl_edp_set_pll_config(struct intel_crtc_state *pipe_config)
-{
-       u32 ctrl1;
-
-       memset(&pipe_config->dpll_hw_state, 0,
-              sizeof(pipe_config->dpll_hw_state));
-
-       pipe_config->ddi_pll_sel = SKL_DPLL0;
-       pipe_config->dpll_hw_state.cfgcr1 = 0;
-       pipe_config->dpll_hw_state.cfgcr2 = 0;
-
-       ctrl1 = DPLL_CTRL1_OVERRIDE(SKL_DPLL0);
-       switch (pipe_config->port_clock / 2) {
-       case 81000:
-               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810,
-                                             SKL_DPLL0);
-               break;
-       case 135000:
-               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350,
-                                             SKL_DPLL0);
-               break;
-       case 270000:
-               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700,
-                                             SKL_DPLL0);
-               break;
-       case 162000:
-               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620,
-                                             SKL_DPLL0);
-               break;
-       /* TBD: For DP link rates 2.16 GHz and 4.32 GHz, VCO is 8640 which
-       results in CDCLK change. Need to handle the change of CDCLK by
-       disabling pipes and re-enabling them */
-       case 108000:
-               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080,
-                                             SKL_DPLL0);
-               break;
-       case 216000:
-               ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160,
-                                             SKL_DPLL0);
-               break;
-
-       }
-       pipe_config->dpll_hw_state.ctrl1 = ctrl1;
-}
-
 static int
 intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
 {
@@ -1640,11 +1594,7 @@ found:
                                &pipe_config->dp_m2_n2);
        }
 
-       if ((IS_SKYLAKE(dev)  || IS_KABYLAKE(dev)) && is_edp(intel_dp))
-               skl_edp_set_pll_config(pipe_config);
-       else if (IS_BROXTON(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
-               /* handled in ddi */;
-       else
+       if (!HAS_DDI(dev))
                intel_dp_set_clock(encoder, pipe_config);
 
        return true;
index a83af07..4b636c4 100644 (file)
@@ -785,7 +785,12 @@ struct skl_dpll_regs {
 };
 
 /* this array is indexed by the *shared* pll id */
-static const struct skl_dpll_regs skl_dpll_regs[3] = {
+static const struct skl_dpll_regs skl_dpll_regs[4] = {
+       {
+               /* DPLL 0 */
+               .ctl = LCPLL1_CTL,
+               /* DPLL 0 doesn't support HDMI mode */
+       },
        {
                /* DPLL 1 */
                .ctl = LCPLL2_CTL,
@@ -806,24 +811,27 @@ static const struct skl_dpll_regs skl_dpll_regs[3] = {
        },
 };
 
-static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
-                              struct intel_shared_dpll *pll)
+static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *dev_priv,
+                                   struct intel_shared_dpll *pll)
 {
        uint32_t val;
-       unsigned int dpll;
-       const struct skl_dpll_regs *regs = skl_dpll_regs;
-
-       /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
-       dpll = pll->id + 1;
 
        val = I915_READ(DPLL_CTRL1);
 
-       val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) |
-                DPLL_CTRL1_LINK_RATE_MASK(dpll));
-       val |= pll->config.hw_state.ctrl1 << (dpll * 6);
+       val &= ~(DPLL_CTRL1_HDMI_MODE(pll->id) | DPLL_CTRL1_SSC(pll->id) |
+                DPLL_CTRL1_LINK_RATE_MASK(pll->id));
+       val |= pll->config.hw_state.ctrl1 << (pll->id * 6);
 
        I915_WRITE(DPLL_CTRL1, val);
        POSTING_READ(DPLL_CTRL1);
+}
+
+static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
+                              struct intel_shared_dpll *pll)
+{
+       const struct skl_dpll_regs *regs = skl_dpll_regs;
+
+       skl_ddi_pll_write_ctrl1(dev_priv, pll);
 
        I915_WRITE(regs[pll->id].cfgcr1, pll->config.hw_state.cfgcr1);
        I915_WRITE(regs[pll->id].cfgcr2, pll->config.hw_state.cfgcr2);
@@ -834,8 +842,14 @@ static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
        I915_WRITE(regs[pll->id].ctl,
                   I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE);
 
-       if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(dpll), 5))
-               DRM_ERROR("DPLL %d not locked\n", dpll);
+       if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(pll->id), 5))
+               DRM_ERROR("DPLL %d not locked\n", pll->id);
+}
+
+static void skl_ddi_dpll0_enable(struct drm_i915_private *dev_priv,
+                                struct intel_shared_dpll *pll)
+{
+       skl_ddi_pll_write_ctrl1(dev_priv, pll);
 }
 
 static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
@@ -849,12 +863,16 @@ static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
        POSTING_READ(regs[pll->id].ctl);
 }
 
+static void skl_ddi_dpll0_disable(struct drm_i915_private *dev_priv,
+                                 struct intel_shared_dpll *pll)
+{
+}
+
 static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
                                     struct intel_shared_dpll *pll,
                                     struct intel_dpll_hw_state *hw_state)
 {
        uint32_t val;
-       unsigned int dpll;
        const struct skl_dpll_regs *regs = skl_dpll_regs;
        bool ret;
 
@@ -863,18 +881,15 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
 
        ret = false;
 
-       /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
-       dpll = pll->id + 1;
-
        val = I915_READ(regs[pll->id].ctl);
        if (!(val & LCPLL_PLL_ENABLE))
                goto out;
 
        val = I915_READ(DPLL_CTRL1);
-       hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f;
+       hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
 
        /* avoid reading back stale values if HDMI mode is not enabled */
-       if (val & DPLL_CTRL1_HDMI_MODE(dpll)) {
+       if (val & DPLL_CTRL1_HDMI_MODE(pll->id)) {
                hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
                hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
        }
@@ -886,6 +901,35 @@ out:
        return ret;
 }
 
+static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
+                                      struct intel_shared_dpll *pll,
+                                      struct intel_dpll_hw_state *hw_state)
+{
+       uint32_t val;
+       const struct skl_dpll_regs *regs = skl_dpll_regs;
+       bool ret;
+
+       if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+               return false;
+
+       ret = false;
+
+       /* DPLL0 is always enabled since it drives CDCLK */
+       val = I915_READ(regs[pll->id].ctl);
+       if (WARN_ON(!(val & LCPLL_PLL_ENABLE)))
+               goto out;
+
+       val = I915_READ(DPLL_CTRL1);
+       hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
+
+       ret = true;
+
+out:
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+       return ret;
+}
+
 struct skl_wrpll_context {
        uint64_t min_deviation;         /* current minimal deviation */
        uint64_t central_freq;          /* chosen central freq */
@@ -1165,7 +1209,8 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
                         DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
                         wrpll_params.central_freq;
        } else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
-                  encoder->type == INTEL_OUTPUT_DP_MST) {
+                  encoder->type == INTEL_OUTPUT_DP_MST ||
+                  encoder->type == INTEL_OUTPUT_EDP) {
                switch (crtc_state->port_clock / 2) {
                case 81000:
                        ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
@@ -1176,6 +1221,19 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
                case 270000:
                        ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
                        break;
+               /* eDP 1.4 rates */
+               case 162000:
+                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
+                       break;
+               /* TBD: For DP link rates 2.16 GHz and 4.32 GHz, VCO is 8640 which
+               results in CDCLK change. Need to handle the change of CDCLK by
+               disabling pipes and re-enabling them */
+               case 108000:
+                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
+                       break;
+               case 216000:
+                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
+                       break;
                }
 
                cfgcr1 = cfgcr2 = 0;
@@ -1190,13 +1248,18 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
        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 (encoder->type == INTEL_OUTPUT_EDP)
+               pll = intel_find_shared_dpll(crtc, crtc_state,
+                                            DPLL_ID_SKL_DPLL0,
+                                            DPLL_ID_SKL_DPLL0);
+       else
+               pll = intel_find_shared_dpll(crtc, crtc_state,
+                                            DPLL_ID_SKL_DPLL1,
+                                            DPLL_ID_SKL_DPLL3);
        if (!pll)
                return NULL;
 
-       /* shared DPLL id 0 is DPLL 1 */
-       crtc_state->ddi_pll_sel = pll->id + 1;
+       crtc_state->ddi_pll_sel = pll->id;
 
        intel_reference_shared_dpll(pll, crtc_state);
 
@@ -1209,6 +1272,12 @@ static const struct intel_shared_dpll_funcs skl_ddi_pll_funcs = {
        .get_hw_state = skl_ddi_pll_get_hw_state,
 };
 
+static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = {
+       .enable = skl_ddi_dpll0_enable,
+       .disable = skl_ddi_dpll0_disable,
+       .get_hw_state = skl_ddi_dpll0_get_hw_state,
+};
+
 static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
                                struct intel_shared_dpll *pll)
 {
@@ -1624,9 +1693,10 @@ static const struct intel_dpll_mgr hsw_pll_mgr = {
 };
 
 static const struct dpll_info skl_plls[] = {
-       { "DPPL 1", DPLL_ID_SKL_DPLL1, &skl_ddi_pll_funcs, 0 },
-       { "DPPL 2", DPLL_ID_SKL_DPLL2, &skl_ddi_pll_funcs, 0 },
-       { "DPPL 3", DPLL_ID_SKL_DPLL3, &skl_ddi_pll_funcs, 0 },
+       { "DPLL 0", DPLL_ID_SKL_DPLL0, &skl_ddi_dpll0_funcs, INTEL_DPLL_ALWAYS_ON },
+       { "DPPL 1", DPLL_ID_SKL_DPLL1, &skl_ddi_pll_funcs,   0 },
+       { "DPPL 2", DPLL_ID_SKL_DPLL2, &skl_ddi_pll_funcs,   0 },
+       { "DPPL 3", DPLL_ID_SKL_DPLL3, &skl_ddi_pll_funcs,   0 },
        { NULL, -1, NULL, },
 };
 
index adf4706..1d34147 100644 (file)
@@ -54,9 +54,10 @@ enum intel_dpll_id {
        DPLL_ID_LCPLL_2700 = 5,
 
        /* skl */
-       DPLL_ID_SKL_DPLL1 = 0,
-       DPLL_ID_SKL_DPLL2 = 1,
-       DPLL_ID_SKL_DPLL3 = 2,
+       DPLL_ID_SKL_DPLL0 = 0,
+       DPLL_ID_SKL_DPLL1 = 1,
+       DPLL_ID_SKL_DPLL2 = 2,
+       DPLL_ID_SKL_DPLL3 = 3,
 };
 #define I915_NUM_PLLS 6