A0 stepping chips need to use manual training, but the bits have all
moved.  So fix things up so we can at least train FDI for VGA links.

Signed-off-by: Jesse Barnes <jbar...@virtuousgeek.org>
---
 drivers/gpu/drm/i915/i915_reg.h      |   10 +++
 drivers/gpu/drm/i915/intel_display.c |  129 +++++++++++++++++++++++++++++++++-
 2 files changed, 136 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index b77bd49..03c99ed 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3105,7 +3105,15 @@
 #define  FDI_TX_ENHANCE_FRAME_ENABLE    (1<<18)
 /* Ironlake: hardwired to 1 */
 #define  FDI_TX_PLL_ENABLE              (1<<14)
+
+/* Ivybridge has different bits for lolz */
+#define  FDI_LINK_TRAIN_PATTERN_1_IVB       (0<<8)
+#define  FDI_LINK_TRAIN_PATTERN_2_IVB       (1<<8)
+#define  FDI_LINK_TRAIN_PATTERN_IDLE_IVB    (2<<8)
+#define  FDI_LINK_TRAIN_NONE_IVB            (3<<8)
+
 /* both Tx and Rx */
+#define  FDI_LINK_TRAIN_AUTO           (1<<10)
 #define  FDI_SCRAMBLING_ENABLE          (0<<7)
 #define  FDI_SCRAMBLING_DISABLE         (1<<7)
 /* Ivybridge */
@@ -3117,6 +3125,8 @@
 #define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
 #define  FDI_RX_ENABLE          (1<<31)
 /* train, dp width same as FDI_TX */
+#define  FDI_FS_ERRC_ENABLE            (1<<27)
+#define  FDI_FE_ERRC_ENABLE            (1<<26)
 #define  FDI_DP_PORT_WIDTH_X8           (7<<19)
 #define  FDI_8BPC                       (0<<16)
 #define  FDI_10BPC                      (1<<16)
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index db46e4f..866abe5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2047,8 +2047,13 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
        /* enable normal train */
        reg = FDI_TX_CTL(pipe);
        temp = I915_READ(reg);
-       temp &= ~FDI_LINK_TRAIN_NONE;
-       temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       if (IS_GEN6(dev)) {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       } else if (IS_IVYBRIDGE(dev)) {
+               temp &= ~FDI_LINK_TRAIN_NONE_IVB;
+               temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
+       }
        I915_WRITE(reg, temp);
 
        reg = FDI_RX_CTL(pipe);
@@ -2065,6 +2070,11 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
        /* wait one idle pattern time */
        POSTING_READ(reg);
        udelay(1000);
+
+       /* IVB wants error correction enabled */
+       if (IS_IVYBRIDGE(dev))
+               I915_WRITE(reg, I915_READ(reg) | FDI_FS_ERRC_ENABLE |
+                          FDI_FE_ERRC_ENABLE);
 }
 
 /* The FDI link training functions for ILK/Ibexpeak. */
@@ -2292,6 +2302,115 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        DRM_DEBUG_KMS("FDI train done.\n");
 }
 
+/* Manual link training for Ivy Bridge A0 parts */
+static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       u32 reg, temp, i;
+
+       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+          for train result */
+       reg = FDI_RX_IMR(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_RX_SYMBOL_LOCK;
+       temp &= ~FDI_RX_BIT_LOCK;
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
+       udelay(150);
+
+       /* enable CPU FDI TX and PCH FDI RX */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~(7 << 19);
+       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+       temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
+       temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
+       temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+       temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       I915_WRITE(reg, temp | FDI_TX_ENABLE);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_AUTO;
+       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+       temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+       I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
+       udelay(150);
+
+       for (i = 0; i < 4; i++ ) {
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               temp |= snb_b_fdi_train_param[i];
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
+               udelay(500);
+
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_BIT_LOCK ||
+                   (I915_READ(reg) & FDI_RX_BIT_LOCK)) {
+                       I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
+                       DRM_DEBUG_KMS("FDI train 1 done.\n");
+                       break;
+               }
+       }
+       if (i == 4)
+               DRM_ERROR("FDI train 1 fail!\n");
+
+       /* Train 2 */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE_IVB;
+       temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
+       temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+       temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       I915_WRITE(reg, temp);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+       temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
+       udelay(150);
+
+       for (i = 0; i < 4; i++ ) {
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               temp |= snb_b_fdi_train_param[i];
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
+               udelay(500);
+
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_SYMBOL_LOCK) {
+                       I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
+                       DRM_DEBUG_KMS("FDI train 2 done.\n");
+                       break;
+               }
+       }
+       if (i == 4)
+               DRM_ERROR("FDI train 2 fail!\n");
+
+       DRM_DEBUG_KMS("FDI train done.\n");
+}
+
 /* On Ivybridge we can use auto training */
 static void ivb_fdi_link_train(struct drm_crtc *crtc)
 {
@@ -7367,7 +7486,11 @@ static void intel_init_display(struct drm_device *dev)
                        }
                        dev_priv->display.train_fdi = gen6_fdi_link_train;
                } else if (IS_IVYBRIDGE(dev)) {
-                       dev_priv->display.train_fdi = ivb_fdi_link_train;
+                       /* FIXME: detect B0+ stepping and use auto training */
+                       if (0)
+                               dev_priv->display.train_fdi = 
ivb_fdi_link_train;
+                       else
+                               dev_priv->display.train_fdi = 
ivb_manual_fdi_link_train;
                } else
                        dev_priv->display.update_wm = NULL;
        } else if (IS_PINEVIEW(dev)) {
-- 
1.7.4.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to