diff mbox

[11/16] drm/i915: manual FDI training for Ivy Bridge

Message ID 1303861134-8762-12-git-send-email-jbarnes@virtuousgeek.org (mailing list archive)
State New, archived
Headers show

Commit Message

Jesse Barnes April 26, 2011, 11:38 p.m. UTC
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 <jbarnes@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(-)

Comments

Keith Packard April 27, 2011, 3:10 p.m. UTC | #1
On Tue, 26 Apr 2011 16:38:49 -0700, Jesse Barnes <jbarnes@virtuousgeek.org> wrote:
> 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.

This patch should be before the auto-train patch so that we don't have
a broken driver between them.

> 
> Signed-off-by: Jesse Barnes <jbarnes@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
Jesse Barnes April 27, 2011, 9:13 p.m. UTC | #2
On Wed, 27 Apr 2011 08:10:29 -0700
Keith Packard <keithp@keithp.com> wrote:

> On Tue, 26 Apr 2011 16:38:49 -0700, Jesse Barnes <jbarnes@virtuousgeek.org> wrote:
> > 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.
> 
> This patch should be before the auto-train patch so that we don't have
> a broken driver between them.

Ok, will re-order.

Jesse
diff mbox

Patch

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)) {