drm/i915: Manage HSW/BDW LCPLLs with the shared dpll interface
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Tue, 8 Mar 2016 15:46:26 +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)
Manage the LCPLLs used with DisplayPort, so that all the HSW/BDW DPLLs
are managed by the shared dpll code.

v2: Introduce INTEL_DPLL_ALWAYS_ON flag to please state checker. (Ander)

v3: Initialize pll->flags in intel_shared_dpll_init(). (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-13-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_dp_mst.c
drivers/gpu/drm/i915/intel_dpll_mgr.c
drivers/gpu/drm/i915/intel_dpll_mgr.h
drivers/gpu/drm/i915/intel_drv.h

index 50cc264355953d0b76c35700694623910a234973..31f9aa0c2b516bdbef6d02ce62a9c812386a8fe2 100644 (file)
@@ -992,17 +992,13 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
 {
        struct intel_shared_dpll *pll;
 
-       if (intel_encoder->type == INTEL_OUTPUT_HDMI ||
-           intel_encoder->type == INTEL_OUTPUT_ANALOG) {
-               pll = intel_get_shared_dpll(intel_crtc, crtc_state,
-                                           intel_encoder);
-               if (!pll)
-                       DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
-                                        pipe_name(intel_crtc->pipe));
-               return pll;
-       } else {
-               return true;
-       }
+       pll = intel_get_shared_dpll(intel_crtc, crtc_state,
+                                   intel_encoder);
+       if (!pll)
+               DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
+                                pipe_name(intel_crtc->pipe));
+
+       return pll;
 }
 
 static bool
index 9d2f494c0e6583345be55e521fc1d723e63fb153..7e00ee51b2c9198094e04ed5a84676763b756a07 100644 (file)
@@ -9821,13 +9821,19 @@ static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
        case PORT_CLK_SEL_SPLL:
                id = DPLL_ID_SPLL;
                break;
+       case PORT_CLK_SEL_LCPLL_810:
+               id = DPLL_ID_LCPLL_810;
+               break;
+       case PORT_CLK_SEL_LCPLL_1350:
+               id = DPLL_ID_LCPLL_1350;
+               break;
+       case PORT_CLK_SEL_LCPLL_2700:
+               id = DPLL_ID_LCPLL_2700;
+               break;
        default:
                MISSING_CASE(pipe_config->ddi_pll_sel);
                /* fall through */
        case PORT_CLK_SEL_NONE:
-       case PORT_CLK_SEL_LCPLL_810:
-       case PORT_CLK_SEL_LCPLL_1350:
-       case PORT_CLK_SEL_LCPLL_2700:
                return;
        }
 
@@ -12942,11 +12948,14 @@ check_shared_dpll_state(struct drm_device *dev)
                     pll->active, hweight32(pll->config.crtc_mask));
                I915_STATE_WARN(pll->active && !pll->on,
                     "pll in active use but not on in sw tracking\n");
-               I915_STATE_WARN(pll->on && !pll->active,
-                    "pll in on but not on in use in sw tracking\n");
-               I915_STATE_WARN(pll->on != active,
-                    "pll on state mismatch (expected %i, found %i)\n",
-                    pll->on, active);
+
+               if (!(pll->flags & INTEL_DPLL_ALWAYS_ON)) {
+                       I915_STATE_WARN(pll->on && !pll->active,
+                            "pll in on but not on in use in sw tracking\n");
+                       I915_STATE_WARN(pll->on != active,
+                            "pll on state mismatch (expected %i, found %i)\n",
+                            pll->on, active);
+               }
 
                for_each_intel_crtc(dev, crtc) {
                        if (crtc->base.state->enable && crtc->config->shared_dpll == pll)
index 109ae6166db11c8b9f50f85c4c6ee0d3519ff8c2..4f0fad3cf138bb40f147cd0c118820016d70039d 100644 (file)
@@ -1283,25 +1283,6 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config)
        pipe_config->dpll_hw_state.ctrl1 = ctrl1;
 }
 
-void
-hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config)
-{
-       memset(&pipe_config->dpll_hw_state, 0,
-              sizeof(pipe_config->dpll_hw_state));
-
-       switch (pipe_config->port_clock / 2) {
-       case 81000:
-               pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810;
-               break;
-       case 135000:
-               pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_1350;
-               break;
-       case 270000:
-               pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_2700;
-               break;
-       }
-}
-
 static int
 intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
 {
@@ -1661,10 +1642,8 @@ found:
 
        if ((IS_SKYLAKE(dev)  || IS_KABYLAKE(dev)) && is_edp(intel_dp))
                skl_edp_set_pll_config(pipe_config);
-       else if (IS_BROXTON(dev))
+       else if (IS_BROXTON(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
                /* handled in ddi */;
-       else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-               hsw_dp_set_ddi_pll_sel(pipe_config);
        else
                intel_dp_set_clock(encoder, pipe_config);
 
index a2bd698fe2f78f801813c99b097d7576e2f0c869..8d1b7033aaba31d553fc3ad9c34dbf4a0aa5bd1e 100644 (file)
@@ -33,7 +33,6 @@
 static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
                                        struct intel_crtc_state *pipe_config)
 {
-       struct drm_device *dev = encoder->base.dev;
        struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
        struct intel_digital_port *intel_dig_port = intel_mst->primary;
        struct intel_dp *intel_dp = &intel_dig_port->dp;
@@ -92,9 +91,6 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
 
        pipe_config->dp_m_n.tu = slots;
 
-       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-               hsw_dp_set_ddi_pll_sel(pipe_config);
-
        return true;
 
 }
index a90ef34a77857e9d29baff8d65388aaaa7a6b827..a83af07e3570558f15206a348d296944c57f6137 100644 (file)
@@ -447,6 +447,12 @@ static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
                return PORT_CLK_SEL_WRPLL2;
        case DPLL_ID_SPLL:
                return PORT_CLK_SEL_SPLL;
+       case DPLL_ID_LCPLL_810:
+               return PORT_CLK_SEL_LCPLL_810;
+       case DPLL_ID_LCPLL_1350:
+               return PORT_CLK_SEL_LCPLL_1350;
+       case DPLL_ID_LCPLL_2700:
+               return PORT_CLK_SEL_LCPLL_2700;
        default:
                return PORT_CLK_SEL_NONE;
        }
@@ -671,9 +677,13 @@ static struct intel_shared_dpll *
 hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
             struct intel_encoder *encoder)
 {
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        struct intel_shared_dpll *pll;
        int clock = crtc_state->port_clock;
 
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
+
        if (encoder->type == INTEL_OUTPUT_HDMI) {
                uint32_t val;
                unsigned p, n2, r2;
@@ -684,21 +694,37 @@ hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
                      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
                      WRPLL_DIVIDER_POST(p);
 
-               memset(&crtc_state->dpll_hw_state, 0,
-                      sizeof(crtc_state->dpll_hw_state));
-
                crtc_state->dpll_hw_state.wrpll = val;
 
                pll = intel_find_shared_dpll(crtc, crtc_state,
                                             DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
 
+       } else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+                  encoder->type == INTEL_OUTPUT_DP_MST ||
+                  encoder->type == INTEL_OUTPUT_EDP) {
+               enum intel_dpll_id pll_id;
+
+               switch (clock / 2) {
+               case 81000:
+                       pll_id = DPLL_ID_LCPLL_810;
+                       break;
+               case 135000:
+                       pll_id = DPLL_ID_LCPLL_1350;
+                       break;
+               case 270000:
+                       pll_id = DPLL_ID_LCPLL_2700;
+                       break;
+               default:
+                       DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
+                       return NULL;
+               }
+
+               pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
+
        } else if (encoder->type == INTEL_OUTPUT_ANALOG) {
                if (WARN_ON(crtc_state->port_clock / 2 != 135000))
                        return NULL;
 
-               memset(&crtc_state->dpll_hw_state, 0,
-                      sizeof(crtc_state->dpll_hw_state));
-
                crtc_state->dpll_hw_state.spll =
                        SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
 
@@ -731,6 +757,29 @@ static const struct intel_shared_dpll_funcs hsw_ddi_spll_funcs = {
        .get_hw_state = hsw_ddi_spll_get_hw_state,
 };
 
+static void hsw_ddi_lcpll_enable(struct drm_i915_private *dev_priv,
+                                struct intel_shared_dpll *pll)
+{
+}
+
+static void hsw_ddi_lcpll_disable(struct drm_i915_private *dev_priv,
+                                 struct intel_shared_dpll *pll)
+{
+}
+
+static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,
+                                      struct intel_shared_dpll *pll,
+                                      struct intel_dpll_hw_state *hw_state)
+{
+       return true;
+}
+
+static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = {
+       .enable = hsw_ddi_lcpll_enable,
+       .disable = hsw_ddi_lcpll_disable,
+       .get_hw_state = hsw_ddi_lcpll_get_hw_state,
+};
+
 struct skl_dpll_regs {
        i915_reg_t ctl, cfgcr1, cfgcr2;
 };
@@ -1537,6 +1586,7 @@ struct dpll_info {
        const char *name;
        const int id;
        const struct intel_shared_dpll_funcs *funcs;
+       uint32_t flags;
 };
 
 struct intel_dpll_mgr {
@@ -1548,9 +1598,9 @@ struct intel_dpll_mgr {
 };
 
 static const struct dpll_info pch_plls[] = {
-       { "PCH DPLL A", DPLL_ID_PCH_PLL_A, &ibx_pch_dpll_funcs },
-       { "PCH DPLL B", DPLL_ID_PCH_PLL_B, &ibx_pch_dpll_funcs },
-       { NULL, -1, NULL },
+       { "PCH DPLL A", DPLL_ID_PCH_PLL_A, &ibx_pch_dpll_funcs, 0 },
+       { "PCH DPLL B", DPLL_ID_PCH_PLL_B, &ibx_pch_dpll_funcs, 0 },
+       { NULL, -1, NULL, 0 },
 };
 
 static const struct intel_dpll_mgr pch_pll_mgr = {
@@ -1559,9 +1609,12 @@ static const struct intel_dpll_mgr pch_pll_mgr = {
 };
 
 static const struct dpll_info hsw_plls[] = {
-       { "WRPLL 1", DPLL_ID_WRPLL1, &hsw_ddi_wrpll_funcs },
-       { "WRPLL 2", DPLL_ID_WRPLL2, &hsw_ddi_wrpll_funcs },
-       { "SPLL",    DPLL_ID_SPLL,   &hsw_ddi_spll_funcs },
+       { "WRPLL 1",    DPLL_ID_WRPLL1,     &hsw_ddi_wrpll_funcs, 0 },
+       { "WRPLL 2",    DPLL_ID_WRPLL2,     &hsw_ddi_wrpll_funcs, 0 },
+       { "SPLL",       DPLL_ID_SPLL,       &hsw_ddi_spll_funcs,  0 },
+       { "LCPLL 810",  DPLL_ID_LCPLL_810,  &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
+       { "LCPLL 1350", DPLL_ID_LCPLL_1350, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
+       { "LCPLL 2700", DPLL_ID_LCPLL_2700, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
        { NULL, -1, NULL, },
 };
 
@@ -1571,9 +1624,9 @@ 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 },
-       { "DPPL 2", DPLL_ID_SKL_DPLL2, &skl_ddi_pll_funcs },
-       { "DPPL 3", DPLL_ID_SKL_DPLL3, &skl_ddi_pll_funcs },
+       { "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, },
 };
 
@@ -1583,9 +1636,9 @@ static const struct intel_dpll_mgr skl_pll_mgr = {
 };
 
 static const struct dpll_info bxt_plls[] = {
-       { "PORT PLL A", 0, &bxt_ddi_pll_funcs },
-       { "PORT PLL B", 1, &bxt_ddi_pll_funcs },
-       { "PORT PLL C", 2, &bxt_ddi_pll_funcs },
+       { "PORT PLL A", 0, &bxt_ddi_pll_funcs, 0 },
+       { "PORT PLL B", 1, &bxt_ddi_pll_funcs, 0 },
+       { "PORT PLL C", 2, &bxt_ddi_pll_funcs, 0 },
        { NULL, -1, NULL, },
 };
 
@@ -1623,6 +1676,7 @@ void intel_shared_dpll_init(struct drm_device *dev)
                dev_priv->shared_dplls[i].id = dpll_info[i].id;
                dev_priv->shared_dplls[i].name = dpll_info[i].name;
                dev_priv->shared_dplls[i].funcs = *dpll_info[i].funcs;
+               dev_priv->shared_dplls[i].flags = dpll_info[i].flags;
        }
 
        dev_priv->dpll_mgr = dpll_mgr;
index 82e53f5b5c63559049c81b068d3dd467fa61bb26..adf4706b8e583d4cb4414672fcc15fa4ba919375 100644 (file)
@@ -49,13 +49,21 @@ enum intel_dpll_id {
        DPLL_ID_WRPLL1 = 0,
        DPLL_ID_WRPLL2 = 1,
        DPLL_ID_SPLL = 2,
+       DPLL_ID_LCPLL_810 = 3,
+       DPLL_ID_LCPLL_1350 = 4,
+       DPLL_ID_LCPLL_2700 = 5,
 
        /* skl */
        DPLL_ID_SKL_DPLL1 = 0,
        DPLL_ID_SKL_DPLL2 = 1,
        DPLL_ID_SKL_DPLL3 = 2,
 };
-#define I915_NUM_PLLS 3
+#define I915_NUM_PLLS 6
+
+/** Inform the state checker that the DPLL is kept enabled even if not
+ * in use by any crtc.
+ */
+#define INTEL_DPLL_ALWAYS_ON   (1 << 0)
 
 struct intel_dpll_hw_state {
        /* i9xx, pch plls */
@@ -113,6 +121,8 @@ struct intel_shared_dpll {
        enum intel_dpll_id id;
 
        struct intel_shared_dpll_funcs funcs;
+
+       uint32_t flags;
 };
 
 #define SKL_DPLL0 0
index 1f62fba3ae3a77e824ee5cd91d6a398df77e9908..1e39928896476a0928300c532c35c0f9b5cb8f0b 100644 (file)
@@ -1312,7 +1312,6 @@ void intel_edp_drrs_invalidate(struct drm_device *dev,
 void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
 bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
                                         struct intel_digital_port *port);
-void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
 
 void
 intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,