Merge tag 'drm-intel-next-2012-12-21' of git://people.freedesktop.org/~danvet/drm...
[cascardo/linux.git] / drivers / gpu / drm / i915 / intel_ddi.c
index f02b3fe..2e904a5 100644 (file)
@@ -140,6 +140,19 @@ static const long hsw_ddi_buf_ctl_values[] = {
        DDI_BUF_EMP_800MV_3_5DB_HSW
 };
 
+static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
+                                   enum port port)
+{
+       uint32_t reg = DDI_BUF_CTL(port);
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               udelay(1);
+               if (I915_READ(reg) & DDI_BUF_IS_IDLE)
+                       return;
+       }
+       DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port));
+}
 
 /* Starting with Haswell, different DDI ports can work in FDI mode for
  * connection to the PCH-located connectors. For this, it is necessary to train
@@ -169,6 +182,8 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
        /* Enable the PCH Receiver FDI PLL */
        rx_ctl_val = FDI_RX_PLL_ENABLE | FDI_RX_ENHANCE_FRAME_ENABLE |
                     ((intel_crtc->fdi_lanes - 1) << 19);
+       if (dev_priv->fdi_rx_polarity_reversed)
+               rx_ctl_val |= FDI_RX_POLARITY_REVERSED_LPT;
        I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
        POSTING_READ(_FDI_RXA_CTL);
        udelay(220);
@@ -233,18 +248,30 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
                        return;
                }
 
+               temp = I915_READ(DDI_BUF_CTL(PORT_E));
+               temp &= ~DDI_BUF_CTL_ENABLE;
+               I915_WRITE(DDI_BUF_CTL(PORT_E), temp);
+               POSTING_READ(DDI_BUF_CTL(PORT_E));
+
                /* Disable DP_TP_CTL and FDI_RX_CTL and retry */
-               I915_WRITE(DP_TP_CTL(PORT_E),
-                          I915_READ(DP_TP_CTL(PORT_E)) & ~DP_TP_CTL_ENABLE);
+               temp = I915_READ(DP_TP_CTL(PORT_E));
+               temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK);
+               temp |= DP_TP_CTL_LINK_TRAIN_PAT1;
+               I915_WRITE(DP_TP_CTL(PORT_E), temp);
+               POSTING_READ(DP_TP_CTL(PORT_E));
+
+               intel_wait_ddi_buf_idle(dev_priv, PORT_E);
 
                rx_ctl_val &= ~FDI_RX_ENABLE;
                I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
+               POSTING_READ(_FDI_RXA_CTL);
 
                /* Reset FDI_RX_MISC pwrdn lanes */
                temp = I915_READ(_FDI_RXA_MISC);
                temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
                temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
                I915_WRITE(_FDI_RXA_MISC, temp);
+               POSTING_READ(_FDI_RXA_MISC);
        }
 
        DRM_ERROR("FDI link training failed!\n");
@@ -1224,20 +1251,6 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
        }
 }
 
-static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
-                                   enum port port)
-{
-       uint32_t reg = DDI_BUF_CTL(port);
-       int i;
-
-       for (i = 0; i < 8; i++) {
-               udelay(1);
-               if (I915_READ(reg) & DDI_BUF_IS_IDLE)
-                       return;
-       }
-       DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port));
-}
-
 static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
 {
        struct drm_encoder *encoder = &intel_encoder->base;