drm/i915: ->disable hook for WRPLLs
[cascardo/linux.git] / drivers / gpu / drm / i915 / intel_ddi.c
index b17b9c7..7c6e8d5 100644 (file)
@@ -76,12 +76,12 @@ static const u32 bdw_ddi_translations_edp[] = {
        0x00FFFFFF, 0x00000012,         /* eDP parameters */
        0x00EBAFFF, 0x00020011,
        0x00C71FFF, 0x0006000F,
+       0x00AAAFFF, 0x000E000A,
        0x00FFFFFF, 0x00020011,
        0x00DB6FFF, 0x0005000F,
        0x00BEEFFF, 0x000A000C,
        0x00FFFFFF, 0x0005000F,
        0x00DB6FFF, 0x000A000C,
-       0x00FFFFFF, 0x000A000C,
        0x00FFFFFF, 0x00140006          /* HDMI parameters 800mV 0dB*/
 };
 
@@ -89,12 +89,12 @@ static const u32 bdw_ddi_translations_dp[] = {
        0x00FFFFFF, 0x0007000E,         /* DP parameters */
        0x00D75FFF, 0x000E000A,
        0x00BEFFFF, 0x00140006,
+       0x80B2CFFF, 0x001B0002,
        0x00FFFFFF, 0x000E000A,
        0x00D75FFF, 0x00180004,
        0x80CB2FFF, 0x001B0002,
        0x00F7DFFF, 0x00180004,
        0x80D75FFF, 0x001B0002,
-       0x80FFFFFF, 0x001B0002,
        0x00FFFFFF, 0x00140006          /* HDMI parameters 800mV 0dB*/
 };
 
@@ -277,7 +277,8 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
        I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
 
        /* Configure Port Clock Select */
-       I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->ddi_pll_sel);
+       I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config.ddi_pll_sel);
+       WARN_ON(intel_crtc->config.ddi_pll_sel != PORT_CLK_SEL_SPLL);
 
        /* Start the training iterating through available voltages and emphasis,
         * testing each value twice. */
@@ -390,46 +391,27 @@ void intel_ddi_put_crtc_pll(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t val;
+       struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(intel_crtc);
 
-       switch (intel_crtc->ddi_pll_sel) {
-       case PORT_CLK_SEL_SPLL:
-               plls->spll_refcount--;
-               if (plls->spll_refcount == 0) {
-                       DRM_DEBUG_KMS("Disabling SPLL\n");
-                       val = I915_READ(SPLL_CTL);
-                       WARN_ON(!(val & SPLL_PLL_ENABLE));
-                       I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
-                       POSTING_READ(SPLL_CTL);
-               }
-               break;
+       switch (intel_crtc->config.ddi_pll_sel) {
        case PORT_CLK_SEL_WRPLL1:
                plls->wrpll1_refcount--;
                if (plls->wrpll1_refcount == 0) {
-                       DRM_DEBUG_KMS("Disabling WRPLL 1\n");
-                       val = I915_READ(WRPLL_CTL1);
-                       WARN_ON(!(val & WRPLL_PLL_ENABLE));
-                       I915_WRITE(WRPLL_CTL1, val & ~WRPLL_PLL_ENABLE);
-                       POSTING_READ(WRPLL_CTL1);
+                       pll->disable(dev_priv, pll);
                }
+               intel_crtc->config.ddi_pll_sel = PORT_CLK_SEL_NONE;
                break;
        case PORT_CLK_SEL_WRPLL2:
                plls->wrpll2_refcount--;
                if (plls->wrpll2_refcount == 0) {
-                       DRM_DEBUG_KMS("Disabling WRPLL 2\n");
-                       val = I915_READ(WRPLL_CTL2);
-                       WARN_ON(!(val & WRPLL_PLL_ENABLE));
-                       I915_WRITE(WRPLL_CTL2, val & ~WRPLL_PLL_ENABLE);
-                       POSTING_READ(WRPLL_CTL2);
+                       pll->disable(dev_priv, pll);
                }
+               intel_crtc->config.ddi_pll_sel = PORT_CLK_SEL_NONE;
                break;
        }
 
-       WARN(plls->spll_refcount < 0, "Invalid SPLL refcount\n");
        WARN(plls->wrpll1_refcount < 0, "Invalid WRPLL1 refcount\n");
        WARN(plls->wrpll2_refcount < 0, "Invalid WRPLL2 refcount\n");
-
-       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_NONE;
 }
 
 #define LC_FREQ 2700
@@ -592,9 +574,9 @@ static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
        u32 wrpll;
 
        wrpll = I915_READ(reg);
-       switch (wrpll & SPLL_PLL_REF_MASK) {
-       case SPLL_PLL_SSC:
-       case SPLL_PLL_NON_SSC:
+       switch (wrpll & WRPLL_PLL_REF_MASK) {
+       case WRPLL_PLL_SSC:
+       case WRPLL_PLL_NON_SSC:
                /*
                 * We could calculate spread here, but our checking
                 * code only cares about 5% accuracy, and spread is a max of
@@ -602,7 +584,7 @@ static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
                 */
                refclk = 135;
                break;
-       case SPLL_PLL_LCPLL:
+       case WRPLL_PLL_LCPLL:
                refclk = LC_FREQ;
                break;
        default:
@@ -622,11 +604,10 @@ static void intel_ddi_clock_get(struct intel_encoder *encoder,
                                struct intel_crtc_config *pipe_config)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
-       enum port port = intel_ddi_get_encoder_port(encoder);
        int link_clock = 0;
        u32 val, pll;
 
-       val = I915_READ(PORT_CLK_SEL(port));
+       val = pipe_config->ddi_pll_sel;
        switch (val & PORT_CLK_SEL_MASK) {
        case PORT_CLK_SEL_LCPLL_810:
                link_clock = 81000;
@@ -750,7 +731,6 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
 {
        struct drm_crtc *crtc = &intel_crtc->base;
        struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
-       struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
        int type = intel_encoder->type;
@@ -759,32 +739,13 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
 
        intel_ddi_put_crtc_pll(crtc);
 
-       if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
-               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
-               switch (intel_dp->link_bw) {
-               case DP_LINK_BW_1_62:
-                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810;
-                       break;
-               case DP_LINK_BW_2_7:
-                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_LCPLL_1350;
-                       break;
-               case DP_LINK_BW_5_4:
-                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_LCPLL_2700;
-                       break;
-               default:
-                       DRM_ERROR("Link bandwidth %d unsupported\n",
-                                 intel_dp->link_bw);
-                       return false;
-               }
-
-       } else if (type == INTEL_OUTPUT_HDMI) {
+       if (type == INTEL_OUTPUT_HDMI) {
                uint32_t reg, val;
                unsigned p, n2, r2;
 
                intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
 
-               val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 |
+               val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
                      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
                      WRPLL_DIVIDER_POST(p);
 
@@ -814,26 +775,15 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
 
                if (reg == WRPLL_CTL1) {
                        plls->wrpll1_refcount++;
-                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1;
+                       intel_crtc->config.ddi_pll_sel = PORT_CLK_SEL_WRPLL1;
+                       intel_crtc->config.shared_dpll = DPLL_ID_WRPLL1;
                } else {
                        plls->wrpll2_refcount++;
-                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2;
+                       intel_crtc->config.ddi_pll_sel = PORT_CLK_SEL_WRPLL2;
+                       intel_crtc->config.shared_dpll = DPLL_ID_WRPLL2;
                }
 
-       } else if (type == INTEL_OUTPUT_ANALOG) {
-               if (plls->spll_refcount == 0) {
-                       DRM_DEBUG_KMS("Using SPLL on pipe %c\n",
-                                     pipe_name(pipe));
-                       plls->spll_refcount++;
-                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL;
-               } else {
-                       DRM_ERROR("SPLL already in use\n");
-                       return false;
-               }
-
-       } else {
-               WARN(1, "Invalid DDI encoder type %d\n", type);
-               return false;
+               intel_crtc->config.dpll_hw_state.wrpll = val;
        }
 
        return true;
@@ -858,27 +808,10 @@ void intel_ddi_pll_enable(struct intel_crtc *crtc)
        BUILD_BUG_ON(enable_bit != SPLL_PLL_ENABLE);
        BUILD_BUG_ON(enable_bit != WRPLL_PLL_ENABLE);
 
-       switch (crtc->ddi_pll_sel) {
-       case PORT_CLK_SEL_LCPLL_2700:
-       case PORT_CLK_SEL_LCPLL_1350:
-       case PORT_CLK_SEL_LCPLL_810:
-               /*
-                * LCPLL should always be enabled at this point of the mode set
-                * sequence, so nothing to do.
-                */
-               return;
-
-       case PORT_CLK_SEL_SPLL:
-               pll_name = "SPLL";
-               reg = SPLL_CTL;
-               refcount = plls->spll_refcount;
-               new_val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz |
-                         SPLL_PLL_SSC;
-               break;
-
+       switch (crtc->config.ddi_pll_sel) {
        case PORT_CLK_SEL_WRPLL1:
        case PORT_CLK_SEL_WRPLL2:
-               if (crtc->ddi_pll_sel == PORT_CLK_SEL_WRPLL1) {
+               if (crtc->config.ddi_pll_sel == PORT_CLK_SEL_WRPLL1) {
                        pll_name = "WRPLL1";
                        reg = WRPLL_CTL1;
                        refcount = plls->wrpll1_refcount;
@@ -890,7 +823,7 @@ void intel_ddi_pll_enable(struct intel_crtc *crtc)
 
                intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
 
-               new_val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 |
+               new_val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
                          WRPLL_DIVIDER_REFERENCE(r2) |
                          WRPLL_DIVIDER_FEEDBACK(n2) | WRPLL_DIVIDER_POST(p);
 
@@ -900,7 +833,6 @@ void intel_ddi_pll_enable(struct intel_crtc *crtc)
                WARN(1, "Bad selected pll: PORT_CLK_SEL_NONE\n");
                return;
        default:
-               WARN(1, "Bad selected pll: 0x%08x\n", crtc->ddi_pll_sel);
                return;
        }
 
@@ -995,7 +927,9 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
                         * eDP when not using the panel fitter, and when not
                         * using motion blur mitigation (which we don't
                         * support). */
-                       if (IS_HASWELL(dev) && intel_crtc->config.pch_pfit.enabled)
+                       if (IS_HASWELL(dev) &&
+                           (intel_crtc->config.pch_pfit.enabled ||
+                            intel_crtc->config.pch_pfit.force_thru))
                                temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
                        else
                                temp |= TRANS_DDI_EDP_INPUT_A_ON;
@@ -1146,47 +1080,12 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
        return false;
 }
 
-static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv,
-                                      enum pipe pipe)
-{
-       uint32_t temp, ret;
-       enum port port = I915_MAX_PORTS;
-       enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
-                                                                     pipe);
-       int i;
-
-       if (cpu_transcoder == TRANSCODER_EDP) {
-               port = PORT_A;
-       } else {
-               temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
-               temp &= TRANS_DDI_PORT_MASK;
-
-               for (i = PORT_B; i <= PORT_E; i++)
-                       if (temp == TRANS_DDI_SELECT_PORT(i))
-                               port = i;
-       }
-
-       if (port == I915_MAX_PORTS) {
-               WARN(1, "Pipe %c enabled on an unknown port\n",
-                    pipe_name(pipe));
-               ret = PORT_CLK_SEL_NONE;
-       } else {
-               ret = I915_READ(PORT_CLK_SEL(port));
-               DRM_DEBUG_KMS("Pipe %c connected to port %c using clock "
-                             "0x%08x\n", pipe_name(pipe), port_name(port),
-                             ret);
-       }
-
-       return ret;
-}
-
 void intel_ddi_setup_hw_pll_state(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe;
        struct intel_crtc *intel_crtc;
 
-       dev_priv->ddi_plls.spll_refcount = 0;
        dev_priv->ddi_plls.wrpll1_refcount = 0;
        dev_priv->ddi_plls.wrpll2_refcount = 0;
 
@@ -1195,17 +1094,11 @@ void intel_ddi_setup_hw_pll_state(struct drm_device *dev)
                        to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 
                if (!intel_crtc->active) {
-                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_NONE;
+                       intel_crtc->config.ddi_pll_sel = PORT_CLK_SEL_NONE;
                        continue;
                }
 
-               intel_crtc->ddi_pll_sel = intel_ddi_get_crtc_pll(dev_priv,
-                                                                pipe);
-
-               switch (intel_crtc->ddi_pll_sel) {
-               case PORT_CLK_SEL_SPLL:
-                       dev_priv->ddi_plls.spll_refcount++;
-                       break;
+               switch (intel_crtc->config.ddi_pll_sel) {
                case PORT_CLK_SEL_WRPLL1:
                        dev_priv->ddi_plls.wrpll1_refcount++;
                        break;
@@ -1261,8 +1154,8 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
                intel_edp_panel_on(intel_dp);
        }
 
-       WARN_ON(crtc->ddi_pll_sel == PORT_CLK_SEL_NONE);
-       I915_WRITE(PORT_CLK_SEL(port), crtc->ddi_pll_sel);
+       WARN_ON(crtc->config.ddi_pll_sel == PORT_CLK_SEL_NONE);
+       I915_WRITE(PORT_CLK_SEL(port), crtc->config.ddi_pll_sel);
 
        if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -1418,10 +1311,54 @@ int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
        }
 }
 
+static void hsw_ddi_pll_disable(struct drm_i915_private *dev_priv,
+                               struct intel_shared_dpll *pll)
+{
+       uint32_t val;
+
+       val = I915_READ(WRPLL_CTL(pll->id));
+       WARN_ON(!(val & WRPLL_PLL_ENABLE));
+       I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
+       POSTING_READ(WRPLL_CTL(pll->id));
+}
+
+static bool hsw_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;
+
+       if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_PLLS))
+               return false;
+
+       val = I915_READ(WRPLL_CTL(pll->id));
+       hw_state->wrpll = val;
+
+       return val & WRPLL_PLL_ENABLE;
+}
+
+static char *hsw_ddi_pll_names[] = {
+       "WRPLL 1",
+       "WRPLL 2",
+};
+
 void intel_ddi_pll_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t val = I915_READ(LCPLL_CTL);
+       int i;
+
+       /* Dummy setup until everything is moved over to avoid upsetting the hw
+        * state cross checker. */
+       dev_priv->num_shared_dpll = 0;
+
+       for (i = 0; i < 2; i++) {
+               dev_priv->shared_dplls[i].id = i;
+               dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
+               dev_priv->shared_dplls[i].disable = hsw_ddi_pll_disable;
+               dev_priv->shared_dplls[i].get_hw_state =
+                       hsw_ddi_pll_get_hw_state;
+       }
 
        /* The LCPLL register should be turned on by the BIOS. For now let's
         * just check its state and print errors in case something is wrong.
@@ -1705,6 +1642,9 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
        intel_encoder->cloneable = 0;
        intel_encoder->hot_plug = intel_ddi_hot_plug;
 
+       intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
+       dev_priv->hpd_irq_port[port] = intel_dig_port;
+
        if (init_dp)
                dp_connector = intel_ddi_init_dp_connector(intel_dig_port);