xf86-video-intel: Branch 'display-port' - src/i830_dp.c src/i830_dp.h

Keith Packard keithp at kemper.freedesktop.org
Fri Apr 3 10:13:00 PDT 2009


 src/i830_dp.c |  148 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 src/i830_dp.h |   13 ++++-
 2 files changed, 132 insertions(+), 29 deletions(-)

New commits:
commit 90787414ee1b098da395a66542741c64048e6e64
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Apr 3 10:10:52 2009 -0700

    Actually set Display Port signal parameters when training link.
    
    Training the Display Port link requires adjusting the voltage and
    pre-emphasis levels on the wire, and then telling the sink what levels are
    in use. This patch adds the first part, that of setting the hardware to
    the desired signal levels.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/src/i830_dp.c b/src/i830_dp.c
index 302dd9d..f7d4779 100644
--- a/src/i830_dp.c
+++ b/src/i830_dp.c
@@ -201,6 +201,12 @@ i830_dp_aux_ch(ScrnInfoPtr pScrn, uint32_t output_reg,
 	return -1;
     }
 
+    /* Check for timeout or receive error.
+     * Timeouts occur when the sink is not connected
+     */
+    if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR | DP_AUX_CH_CTL_RECEIVE_ERROR))
+	return -1;
+
     /* Unload any bytes sent back from the other side */
     recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
 		  DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
@@ -628,7 +634,7 @@ i830_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
 		 DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
     uint8_t l = i830_dp_link_status(link_status, i);
 
-    return (l >> s) & 3;
+    return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
 }
 
 static uint8_t
@@ -641,24 +647,95 @@ i830_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
 		 DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
     uint8_t l = i830_dp_link_status(link_status, i);
 
-    return (l >> s) & 3;
+    return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
 }
 
+/*
+ * These are source-specific values; current Intel hardware supports
+ * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
+ */
+#define I830_DP_VOLTAGE_MAX	    DP_TRAIN_VOLTAGE_SWING_800
+
 static uint8_t
+i830_dp_pre_emphasis_max(uint8_t voltage_swing)
+{
+    switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+    case DP_TRAIN_VOLTAGE_SWING_400:
+	return DP_TRAIN_PRE_EMPHASIS_6;
+    case DP_TRAIN_VOLTAGE_SWING_600:
+	return DP_TRAIN_PRE_EMPHASIS_3_5;
+    case DP_TRAIN_VOLTAGE_SWING_800:
+    case DP_TRAIN_VOLTAGE_SWING_1200:
+    default:
+	return DP_TRAIN_PRE_EMPHASIS_0;
+    }
+}
+
+static void
 i830_get_adjust_train(uint8_t link_status[DP_LINK_STATUS_SIZE],
-		      int lane)
+		      int lane_count,
+		      uint8_t train_set[4])
 {
-    uint8_t v = i830_get_adjust_request_voltage(link_status, lane);
-    uint8_t p = i830_get_adjust_request_pre_emphasis(link_status, lane);
-    uint8_t t;
-
-    t = ((v << DP_TRAIN_VOLTAGE_SWING_SET_SHIFT) |
-	 (p << DP_TRAIN_PRE_EMPHASIS_SHIFT));
-    if (v == 3)
-	t |= DP_TRAIN_MAX_SWING_REACHED;
-    if (v + p == 3)
-	t |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
-    return t;
+    uint8_t v = 0;
+    uint8_t p = 0;
+    int lane;
+
+    for (lane = 0; lane < lane_count; lane++) {
+	uint8_t this_v = i830_get_adjust_request_voltage(link_status, lane);
+	uint8_t this_p = i830_get_adjust_request_pre_emphasis(link_status, lane);
+
+	if (this_v > v)
+	    v = this_v;
+	if (this_p > p)
+	    p = this_p;
+    }
+
+    if (v >= I830_DP_VOLTAGE_MAX)
+	v = I830_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
+
+    if (p >= i830_dp_pre_emphasis_max(v))
+	p = i830_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+    for (lane = 0; lane < 4; lane++)
+	train_set[lane] = v | p;
+}
+
+static uint32_t
+i830_dp_signal_levels(uint8_t train_set, int lane_count)
+{
+    uint32_t	signal_levels = 0;
+
+    switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+    case DP_TRAIN_VOLTAGE_SWING_400:
+    default:
+	signal_levels |= DP_VOLTAGE_0_4;
+	break;
+    case DP_TRAIN_VOLTAGE_SWING_600:
+	signal_levels |= DP_VOLTAGE_0_6;
+	break;
+    case DP_TRAIN_VOLTAGE_SWING_800:
+	signal_levels |= DP_VOLTAGE_0_8;
+	break;
+    case DP_TRAIN_VOLTAGE_SWING_1200:
+	signal_levels |= DP_VOLTAGE_1_2;
+	break;
+    }
+    switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+    case DP_TRAIN_PRE_EMPHASIS_0:
+    default:
+	signal_levels |= DP_PRE_EMPHASIS_0;
+	break;
+    case DP_TRAIN_PRE_EMPHASIS_3_5:
+	signal_levels |= DP_PRE_EMPHASIS_3_5;
+	break;
+    case DP_TRAIN_PRE_EMPHASIS_6:
+	signal_levels |= DP_PRE_EMPHASIS_6;
+	break;
+    case DP_TRAIN_PRE_EMPHASIS_9_5:
+	signal_levels |= DP_PRE_EMPHASIS_9_5;
+	break;
+    }
+    return signal_levels;
 }
 
 static uint8_t
@@ -714,7 +791,8 @@ static Bool
 i830_dp_set_link_train(xf86OutputPtr output,
 		       uint32_t dp_reg_value,
 		       uint8_t dp_train_pat,
-		       uint8_t train_set[4])
+		       uint8_t train_set[4],
+		       Bool first)
 {
 	ScrnInfoPtr pScrn = output->scrn;
 	I830OutputPrivatePtr intel_output = output->driver_private;
@@ -724,6 +802,8 @@ i830_dp_set_link_train(xf86OutputPtr output,
 
 	OUTREG(dev_priv->output_reg, dp_reg_value);
 	POSTING_READ(dev_priv->output_reg);
+	if (first)
+		i830WaitForVblank(pScrn);
 
 	i830_dp_aux_native_write_1(pScrn, dev_priv->output_reg,
 				   DP_TRAINING_PATTERN_SET,
@@ -752,6 +832,7 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
     uint8_t voltage;
     Bool clock_recovery = FALSE;
     Bool channel_eq = FALSE;
+    Bool first = TRUE;
     int tries;
 
     if ((DP & DP_PORT_EN) == 0) {
@@ -762,13 +843,19 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
     DP &= ~DP_LINK_TRAIN_MASK;
 
     memset(train_set, 0, 4);
+
     voltage = 0xff;
     tries = 0;
     clock_recovery = FALSE;
     for (;;) {
+	/* Use train_set[0] to set the voltage and pre emphasis values */
+	uint32_t    signal_levels = i830_dp_signal_levels(train_set[0], dev_priv->lane_count);
+	DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+
 	if (!i830_dp_set_link_train(output, DP | DP_LINK_TRAIN_PAT_1,
-				    DP_TRAINING_PATTERN_1, train_set))
+				    DP_TRAINING_PATTERN_1, train_set, first))
 		break;
+	first = FALSE;
 	/* Set training pattern 1 */
 
 	usleep(100);
@@ -791,7 +878,7 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
 	}
 
 	/* Check to see if we've tried the same voltage 5 times */
-	if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_SET_MASK) == voltage) {
+	if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
 	    ++tries;
 	    if (tries == 5) {
 		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
@@ -800,11 +887,10 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
 	    }
 	} else
 	    tries = 0;
-	voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_SET_MASK;
+	voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
 	/* Compute new train_set as requested by target */
-	for (i = 0; i < dev_priv->lane_count; i++)
-	    train_set[i] = i830_get_adjust_train(link_status, i);
+        i830_get_adjust_train(link_status, dev_priv->lane_count, train_set);
     }
     if (!clock_recovery)
 	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
@@ -812,7 +898,7 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
     else if (pI830->debug_modes)
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		   "clock recovery at voltage %d pre-emphasis %d\n",
-		   train_set[0] & DP_TRAIN_VOLTAGE_SWING_SET_MASK,
+		   train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
 		   (train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
 		   DP_TRAIN_PRE_EMPHASIS_SHIFT);
 
@@ -820,9 +906,14 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
     tries = 0;
     channel_eq = FALSE;
     for (;;) {
+	/* Use train_set[0] to set the voltage and pre emphasis values */
+	uint32_t    signal_levels = i830_dp_signal_levels(train_set[0], dev_priv->lane_count);
+	DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+
 	/* channel eq pattern */
 	if (!i830_dp_set_link_train(output, DP | DP_LINK_TRAIN_PAT_2,
-				    DP_TRAINING_PATTERN_2, train_set))
+				    DP_TRAINING_PATTERN_2, train_set,
+				    FALSE))
 		break;
 
 	usleep(400);
@@ -842,8 +933,7 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
 	}
 
 	/* Compute new train_set as requested by target */
-	for (i = 0; i < dev_priv->lane_count; i++)
-	    train_set[i] = i830_get_adjust_train(link_status, i);
+        i830_get_adjust_train(link_status, dev_priv->lane_count, train_set);
 	++tries;
     }
     if (!channel_eq)
@@ -852,7 +942,7 @@ i830_dp_link_train(xf86OutputPtr output, uint32_t DP)
     else if (pI830->debug_modes)
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		   "channel eq at voltage %d pre-emphasis %d\n",
-		   train_set[0] & DP_TRAIN_VOLTAGE_SWING_SET_MASK,
+		   train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
 		   (train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
 		   >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
 
@@ -1020,11 +1110,15 @@ i830_dp_check_link_status(xf86OutputPtr output)
 	if (!output->crtc)
 		return;
 
-	if (!i830_dp_get_link_status(output, link_status))
+	if (!i830_dp_get_link_status(output, link_status)) {
+		OUTREG(dev_priv->output_reg,
+		       INREG(dev_priv->output_reg) & ~DP_PORT_EN);
 		return;
+	}
 
 	if (!i830_channel_eq_ok(link_status, dev_priv->lane_count))
-		i830_dp_link_train(output, INREG(dev_priv->output_reg));
+		i830_dp_link_train(output,
+				   INREG(dev_priv->output_reg) | DP_PORT_EN);
 }
 
 static CARD32
diff --git a/src/i830_dp.h b/src/i830_dp.h
index f53b9de..852f28b 100644
--- a/src/i830_dp.h
+++ b/src/i830_dp.h
@@ -74,11 +74,20 @@
 #define DP_TRAINING_LANE2_SET		    0x105
 #define DP_TRAINING_LANE3_SET		    0x106
 
-# define DP_TRAIN_VOLTAGE_SWING_SET_MASK    0x3
-# define DP_TRAIN_VOLTAGE_SWING_SET_SHIFT   0
+# define DP_TRAIN_VOLTAGE_SWING_MASK	    0x3
+# define DP_TRAIN_VOLTAGE_SWING_SHIFT	    0
 # define DP_TRAIN_MAX_SWING_REACHED	    (1 << 2)
+# define DP_TRAIN_VOLTAGE_SWING_400	    (0 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_600	    (1 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_800	    (2 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_1200	    (3 << 0)
 
 # define DP_TRAIN_PRE_EMPHASIS_MASK	    (3 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_0	    (0 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_3_5	    (1 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_6	    (2 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_9_5	    (3 << 3)
+
 # define DP_TRAIN_PRE_EMPHASIS_SHIFT	    3
 # define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED  (1 << 5)
 


More information about the xorg-commit mailing list