xf86-video-ati: Branch 'displayport' - 2 commits

Dave Airlie airlied at kemper.freedesktop.org
Mon Jul 6 23:10:50 PDT 2009


 src/atombios_output.c |  521 ++++++++++++++++++++++++++++++++++++++++++--------
 src/radeon_probe.h    |    6 
 2 files changed, 453 insertions(+), 74 deletions(-)

New commits:
commit c09a726e0396c2703b6e74d80f0c9fd73125d926
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue Jul 7 00:49:20 2009 -0400

    radeon: displayport: oops I mistype something here.

diff --git a/src/atombios_output.c b/src/atombios_output.c
index 006a5bd..ccd7fd7 100644
--- a/src/atombios_output.c
+++ b/src/atombios_output.c
@@ -1772,7 +1772,7 @@ atombios_dac_detect(xf86OutputPtr output)
 #define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK   0xc0
 #define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT  6
 
-#define DP_LINK_STATUS_SIZE 65
+#define DP_LINK_STATUS_SIZE 6
 
 #define DP_SET_POWER_D0  0x1
 #define DP_SET_POWER_D3  0x2
@@ -2318,11 +2318,6 @@ atom_dp_set_link_train(xf86OutputPtr output, uint8_t dp_train_pat, uint8_t train
     xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
 	       "Training  trying link voltage %x pre-emphasis\n", train_set[0]);
 
-    for (i = 0; i < 4; i++)
-	RADEON_DP_DigTransmitterSetup_VSEMPH(output, i, train_set[i]);
-
-    atom_dp_aux_native_write(output, DP_TRAINING_LANE0_SET, 4, train_set);
-
     usleep(400);
 
     /* set DP encoder training start */
@@ -2475,7 +2470,15 @@ static void radeon_dp_mode_set(xf86OutputPtr output, DisplayModePtr mode, Displa
     }
 }
 
+static void dp_update_dpvs_emph(xf86OutputPtr output, uint8_t train_set[4])
+{
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    int i;
+    for (i = 0; i < radeon_output->dp_lane_count; i++)
+	RADEON_DP_DigTransmitterSetup_VSEMPH(output, i, train_set[i]);
 
+    atom_dp_aux_native_write(output, DP_TRAINING_LANE0_SET, 4, train_set);
+}
 
 static void do_displayport_dance(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
 {
@@ -2518,7 +2521,7 @@ static void do_displayport_dance(xf86OutputPtr output, DisplayModePtr mode, Disp
     RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START, enc_id, 0);
 
     RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 0);
-
+    dp_update_dpvs_emph(output, train_set);
     memset(train_set, 0, 4);
     /* loop around doing configuration reads and DP encoder setups */
     clock_recovery = FALSE;
@@ -2526,9 +2529,11 @@ static void do_displayport_dance(xf86OutputPtr output, DisplayModePtr mode, Disp
     voltage = 0xff;
     for (;;) {
 
-	if (!atom_dp_set_link_train(output, DP_TRAINING_PATTERN_1, train_set))
-	    break;
-	
+	//	if (!atom_dp_set_link_train(output, DP_TRAINING_PATTERN_1, train_set))
+	//	    break;
+	usleep(400);
+	dp_set_training(output, DP_TRAINING_PATTERN_1);
+
 	usleep(100);
 	if (!atom_dp_get_link_status(output, link_status))
 	    break;
@@ -2561,6 +2566,8 @@ static void do_displayport_dance(xf86OutputPtr output, DisplayModePtr mode, Disp
 	voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
         dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set);
+	dp_update_dpvs_emph(output, train_set);
+
     }
 
     if (!clock_recovery)
@@ -2576,11 +2583,11 @@ static void do_displayport_dance(xf86OutputPtr output, DisplayModePtr mode, Disp
     /* channel equalization */
     tries = 0;
     channel_eq = FALSE;
+    dp_set_training(output, DP_TRAINING_PATTERN_2);
     RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 1);
+
     for (;;) {
 
-	if (!atom_dp_set_link_train(output, DP_TRAINING_PATTERN_2, train_set))
-	    break;
 	usleep(400);
 	if (!atom_dp_get_link_status(output, link_status))
 	    break;
@@ -2599,6 +2606,8 @@ static void do_displayport_dance(xf86OutputPtr output, DisplayModePtr mode, Disp
 
 	/* Compute new train_set as requested by target */
         dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set);
+	dp_update_dpvs_emph(output, train_set);
+
 	++tries;
     }
     
commit 06b8feceaf615dadc8a3ab690fb3c3e114988774
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue Jul 7 00:40:10 2009 -0400

    radeon: displayport.
    
    well this is most of the typing over with.
    
    fixed a lot of buggies around that native read/write, esp the length fields
    and address ordering.

diff --git a/src/atombios_output.c b/src/atombios_output.c
index 424396f..006a5bd 100644
--- a/src/atombios_output.c
+++ b/src/atombios_output.c
@@ -1528,14 +1528,14 @@ atombios_output_mode_set(xf86OutputPtr output,
 	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE);
 	atombios_output_dig_encoder_setup(output, ATOM_DISABLE);
 
-	/* setup and enable the encoder and transmitter */
-	atombios_output_dig_encoder_setup(output, ATOM_ENABLE);
-	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP);
-	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE);
-
 	if (radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT && radeon_output->MonType == MT_DP) {
 	    do_displayport_dance(output, mode, adjusted_mode);
 	    //return;
+	} else {
+	    /* setup and enable the encoder and transmitter */
+	    atombios_output_dig_encoder_setup(output, ATOM_ENABLE);
+	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP);
+	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE);
 	}
 	break;
     case ENCODER_OBJECT_ID_INTERNAL_DDI:
@@ -1672,8 +1672,8 @@ atombios_dac_detect(xf86OutputPtr output)
     return MonType;
 }
 
-#define AUX_NATIVE_READ 0x8
-#define AUX_NATIVE_WRITE 0x9
+#define AUX_NATIVE_WRITE 0x8
+#define AUX_NATIVE_READ 0x9
 
 #define AUX_I2C_WRITE 0x0
 #define AUX_I2C_READ 0x1
@@ -1774,8 +1774,28 @@ atombios_dac_detect(xf86OutputPtr output)
 
 #define DP_LINK_STATUS_SIZE 65
 
+#define DP_SET_POWER_D0  0x1
+#define DP_SET_POWER_D3  0x2
+
+static inline int atom_dp_get_encoder_id(xf86OutputPtr output)
+{
+    RADEONInfoPtr info       = RADEONPTR(output->scrn);
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    if (IS_DCE32_VARIANT) {
+	if (radeon_output->dig_block)
+	    return ATOM_DP_CONFIG_DIG2_ENCODER;
+	else
+	    return ATOM_DP_CONFIG_DIG1_ENCODER;
+    } else {
+	if (radeon_output->linkb)
+	    return ATOM_DP_CONFIG_DIG2_ENCODER;
+	else
+	    return ATOM_DP_CONFIG_DIG1_ENCODER;
+    }
+}
+
 Bool
-RADEONProcessAuxCH(xf86OutputPtr output, char *req_bytes, int num_bytes, uint8_t *read_byte, uint8_t read_buf_len)
+RADEONProcessAuxCH(xf86OutputPtr output, char *req_bytes, int num_bytes, uint8_t *read_byte, uint8_t read_buf_len, uint8_t delay)
 {
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
     RADEONInfoPtr info       = RADEONPTR(output->scrn);
@@ -1798,15 +1818,17 @@ RADEONProcessAuxCH(xf86OutputPtr output, char *req_bytes, int num_bytes, uint8_t
     args.lpDataOut = 16;
     args.ucDataOutLen = 0;
     args.ucChannelID = radeon_output->ucI2cId;
-    args.ucDelay = 0;
+    args.ucDelay = delay;
 
     data.exec.index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
     data.exec.dataSpace = (void *)&space;
     data.exec.pspace = &args;
 
     RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data);
-    if (args.ucReplyStatus)
-		return FALSE;
+    if (args.ucReplyStatus) {
+	ErrorF("failed to get auxch %02x%02x %02x %02x %02x\n", req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3],args.ucReplyStatus);
+	return FALSE;
+    }
     if (args.ucDataOutLen && read_byte && read_buf_len) {
 	if (read_buf_len < args.ucDataOutLen) {
 	    ErrorF("%s: Buffer too small for return answer %d %d\n", __func__, read_buf_len, args.ucDataOutLen);
@@ -1821,7 +1843,7 @@ RADEONProcessAuxCH(xf86OutputPtr output, char *req_bytes, int num_bytes, uint8_t
 }
 
 int
-RADEONDPEncoderService(xf86OutputPtr output, int action, uint8_t ucconfig)
+RADEONDPEncoderService(xf86OutputPtr output, int action, uint8_t ucconfig, uint8_t lane_num)
 {
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
     RADEONInfoPtr info       = RADEONPTR(output->scrn);
@@ -1834,7 +1856,7 @@ RADEONDPEncoderService(xf86OutputPtr output, int action, uint8_t ucconfig)
     args.ucLinkClock = 0;
     args.ucConfig = ucconfig;
     args.ucAction = action;
-    args.ucLaneNum = 0;
+    args.ucLaneNum = lane_num;
     args.ucStatus = 0;
 
     data.exec.index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
@@ -1851,42 +1873,113 @@ int RADEON_DP_GetSinkType(xf86OutputPtr output)
 {
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
-    return RADEONDPEncoderService(output, ATOM_DP_ACTION_GET_SINK_TYPE, radeon_output->ucI2cId);
+    return RADEONDPEncoderService(output, ATOM_DP_ACTION_GET_SINK_TYPE, radeon_output->ucI2cId, 0);
 }
 
+int RADEON_DP_DigTransmitterSetup_VSEMPH(xf86OutputPtr output, uint8_t lane_num, uint8_t lane_set)
+{
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    RADEONInfoPtr info       = RADEONPTR(output->scrn);
+    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
+    DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
+    AtomBiosArgRec data;
+    unsigned char *space;
+    int clock = radeon_output->pixel_clock;
+    int dig_block = radeon_output->dig_block;
+    int num = 0;
+    int index = 0;
+
+    if (radeon_encoder == NULL)
+        return ATOM_NOT_IMPLEMENTED;
+
+    memset(&v2,0, sizeof(v2));
+
+    index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
+
+    v2.asMode.ucLaneSel = lane_num;
+    v2.asMode.ucLaneSet = lane_set;
+    v2.ucAction = ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH;
+    v2.acConfig.fDPConnector = 1;
+    if (dig_block)
+      v2.acConfig.ucEncoderSel = 1;
+
+
+    switch (radeon_encoder->encoder_id) {
+    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+      v2.acConfig.ucTransmitterSel = 0;
+      num = 0;
+      break;
+    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+      v2.acConfig.ucTransmitterSel = 1;
+      num = 1;
+      break;
+    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+      v2.acConfig.ucTransmitterSel = 2;
+      num = 2;
+      break;
+    }
+
+    data.exec.index = index;
+    data.exec.dataSpace = (void *)&space;
+    data.exec.pspace = &v2;
+
+    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
+	if (IS_DCE32_VARIANT)
+	    ErrorF("Output UNIPHY%d transmitter VSEMPH setup success\n", num);
+	else
+	   ErrorF("Output DIG%d transmitter VSEMPH setup success\n", num);
+	return ATOM_SUCCESS;
+    }
+
+    ErrorF("Output DIG%d transmitter VSEMPH setup failed\n", num);
+    return ATOM_NOT_IMPLEMENTED;
+    
+}
 
 static Bool atom_dp_aux_native_write(xf86OutputPtr output, uint16_t address,
 				     uint8_t send_bytes, uint8_t *send)
 {
     uint8_t msg[20];
-    uint8_t msg_len;
+    uint8_t msg_len, dp_msg_len;
     int ret;
 
+    dp_msg_len = 4;
     msg[2] = AUX_NATIVE_WRITE << 4;
-    msg[0] = address >> 8;
-    msg[1] = address;
-    msg[3] = 0x30 | (send_bytes - 1);
+    msg[0] = address;
+    msg[1] = address >> 8;
+    dp_msg_len += send_bytes;
+    msg[3] = (dp_msg_len << 4)| (send_bytes - 1);
+    
+
+    ErrorF("writing %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], send_bytes, dp_msg_len);
+    if (send_bytes > 16)
+	return FALSE;
 
+    memcpy(&msg[4], send, send_bytes);
     msg_len = 4 + send_bytes;
-    ret = RADEONProcessAuxCH(output, msg, msg_len, NULL, 0);
+    ret = RADEONProcessAuxCH(output, msg, msg_len, NULL, 0, 0);
     return ret;
 }
 
 static Bool atom_dp_aux_native_read(xf86OutputPtr output, uint16_t address,
+				    uint8_t delay, 
 				    uint8_t expected_bytes, uint8_t *read_p)
 {
     uint8_t msg[20];
-    uint8_t msg_len;
+    uint8_t msg_len, dp_msg_len;
     int ret;
 
     msg_len = 4;
-    msg[2] = AUX_NATIVE_WRITE << 4;
-    msg[0] = address >> 8;
-    msg[1] = address;
-    msg[3] = 0x40 | (expected_bytes - 1);
-
+    dp_msg_len = 4;
+    msg[0] = address;
+    msg[1] = address >> 8;
+    msg[2] = AUX_NATIVE_READ << 4;
+    msg[3] = (dp_msg_len) << 4;
+    msg[3] |= expected_bytes - 1;
     
-    ret = RADEONProcessAuxCH(output, msg, msg_len, read_p, expected_bytes);
+
+    ErrorF("reading %02x %02x %02x, %d\n", msg[0], msg[1], msg[3], expected_bytes, dp_msg_len);
+    ret = RADEONProcessAuxCH(output, msg, msg_len, read_p, expected_bytes, delay);
     return ret;
 }
 
@@ -1897,12 +1990,25 @@ void RADEON_DP_GetDPCP(xf86OutputPtr output)
     uint8_t msg[25];
     int ret;
 
-    ret = atom_dp_aux_native_read(output, DP_DPCP_REV, 8, msg);
+    ret = atom_dp_aux_native_read(output, DP_DPCP_REV, 0, 8, msg);
     if (ret) {
 	memcpy(radeon_output->dpcp8, msg, 8);
+	{ 
+	    int i;
+	    ErrorF("DPCP: ");
+	    for (i = 0; i < 8; i++)
+		ErrorF("%02x ", radeon_output->dpcp8[i]);
+	    ErrorF("\n");
+	}
+	ret = atom_dp_aux_native_read(output, 0x100, 0, 2, msg);
+	if (ret) {
+	    ErrorF("0x200: %02x %02x\n", msg[0], msg[1]);
+	}
 	return;
     }
     radeon_output->dpcp8[0] = 0;
+
+
     return;
 }
 
@@ -1919,9 +2025,10 @@ static Bool atom_dp_aux_i2c_transaction(xf86OutputPtr output, uint16_t address,
 				       enum dp_aux_i2c_mode mode,
 				       uint8_t write_byte, uint8_t *read_byte)
 {
-    uint8_t msg[8], msg_len;
+    uint8_t msg[8], msg_len, dp_msg_len;
     int ret;
-    int auxch_cmd = 0; 
+    int auxch_cmd = 0;
+    
 
     memset(msg, 0, 8);
 
@@ -1940,23 +2047,23 @@ static Bool atom_dp_aux_i2c_transaction(xf86OutputPtr output, uint16_t address,
     msg[1] = (address >> 9);
 
     msg_len = 4;
+    dp_msg_len = 3;
     switch (mode) {
-    case dp_aux_i2c_start:
-    case dp_aux_i2c_stop:
-	msg[3] = 0x30;
-	break;
     case dp_aux_i2c_read:
 	/* bottom bits is byte count - 1 so for 1 byte == 0 */
-	msg[3] = 0x40;
+	dp_msg_len += 1;
 	break;
     case dp_aux_i2c_write:
-	msg[3] = 0x50;
+	dp_msg_len += 2;
 	msg[4] = write_byte;
 	msg_len++;
 	break;
+    default:
+	break;
     }
+    msg[3] = dp_msg_len << 4;
 
-    ret = RADEONProcessAuxCH(output, msg, msg_len, read_byte, 1);
+    ret = RADEONProcessAuxCH(output, msg, msg_len, read_byte, 1, 0);
     return ret;
 }
 
@@ -2088,6 +2195,31 @@ static Bool dp_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int l
     }
     return TRUE;
 }
+
+
+/* Check to see if channel eq is done on all channels */
+#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\
+			 DP_LANE_CHANNEL_EQ_DONE|\
+			 DP_LANE_SYMBOL_LOCKED)
+static Bool
+dp_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+{
+    uint8_t lane_align;
+    uint8_t lane_status;
+    int lane;
+    
+    lane_align = dp_link_status(link_status,
+				DP_LANE_ALIGN_STATUS_UPDATED);
+    if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
+	return FALSE;
+    for (lane = 0; lane < lane_count; lane++) {
+	lane_status = dp_get_lane_status(link_status, lane);
+	if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
+	    return FALSE;
+    }
+    return TRUE;
+}
+
 /*
  * Fetch AUX CH registers 0x202 - 0x207 which contain
  * link status information
@@ -2099,12 +2231,15 @@ atom_dp_get_link_status(xf86OutputPtr output,
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
     ScrnInfoPtr pScrn = output->scrn;
     int ret;
-    ret = atom_dp_aux_native_read(output, DP_LANE0_1_STATUS,
+    ret = atom_dp_aux_native_read(output, DP_LANE0_1_STATUS, 1,
 				  DP_LINK_STATUS_SIZE, link_status);
     if (!ret) {
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "dp link status failed\n");
 	return FALSE;
     }
+    ErrorF("link status %02x %02x %02x %02x %02x %02x\n", link_status[0], link_status[1],
+	   link_status[2], link_status[3], link_status[4], link_status[5]);
+	  
     return TRUE;
 }
 
@@ -2124,7 +2259,7 @@ dp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
 
 static uint8_t
 dp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
-                                     int lane)
+				   int lane)
 {
     int     i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
     int     s = ((lane & 1) ?
@@ -2149,7 +2284,7 @@ static char     *link_train_names[] = {
  * 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
+#define DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_1200
 
 static uint8_t
 dp_pre_emphasis_max(uint8_t voltage_swing)
@@ -2167,17 +2302,180 @@ dp_pre_emphasis_max(uint8_t voltage_swing)
     }
 }
 
+static void dp_set_training(xf86OutputPtr output, uint8_t training)
+{
+    atom_dp_aux_native_write(output, DP_TRAINING_PATTERN_SET, 1, &training);
+}
+
 static Bool
 atom_dp_set_link_train(xf86OutputPtr output, uint8_t dp_train_pat, uint8_t train_set[4])
 {
+    int ret;
+    int enc_id = atom_dp_get_encoder_id(output);
+    int i;
+    /* set DP encoder training start */
+
+    xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
+	       "Training  trying link voltage %x pre-emphasis\n", train_set[0]);
+
+    for (i = 0; i < 4; i++)
+	RADEON_DP_DigTransmitterSetup_VSEMPH(output, i, train_set[i]);
+
+    atom_dp_aux_native_write(output, DP_TRAINING_LANE0_SET, 4, train_set);
+
+    usleep(400);
 
     /* set DP encoder training start */
-    atom_dp_aux_native_write(output, DP_TRAINING_PATTERN_SET, dp_train_pat, 1);
+    dp_set_training(output, dp_train_pat);
+
+    return TRUE;
+}
 
-    atom_dp_aux_native_write(output, DP_TRAINING_LANE0_SET, train_set, 4);
+static void dp_set_power(xf86OutputPtr output, uint8_t power_state)
+{
+    uint8_t pstate;
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
+    if (radeon_output->dpcp8[0] >= 0x11) {
+	atom_dp_aux_native_write(output, 0x600, 1, &power_state);
+    }
 }
 		       
+static void
+dp_get_adjust_train(xf86OutputPtr output,
+		      uint8_t link_status[DP_LINK_STATUS_SIZE],
+		      int lane_count,
+		      uint8_t train_set[4])
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    RADEONInfoPtr info       = RADEONPTR(output->scrn);
+    uint8_t v = 0;
+    uint8_t p = 0;
+    int lane;
+
+    for (lane = 0; lane < lane_count; lane++) {
+	uint8_t this_v = dp_get_adjust_request_voltage(link_status, lane);
+	uint8_t this_p = dp_get_adjust_request_pre_emphasis(link_status, lane);
+
+	if  (1) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "requested signal parameters: lane %d voltage %s pre_emph %s\n",
+		       lane,
+		       voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
+		       pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
+	}
+	if (this_v > v)
+	    v = this_v;
+	if (this_p > p)
+	    p = this_p;
+    }
+
+    if (v >= DP_VOLTAGE_MAX)
+	v = DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
+
+    if (p >= dp_pre_emphasis_max(v))
+	p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+    if (1) {
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		   "using signal parameters: voltage %s pre_emph %s\n",
+		   voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
+		   pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
+    }
+    for (lane = 0; lane < 4; lane++)
+	train_set[lane] = v | p;
+}
+
+static int radeon_dp_max_lane_count(xf86OutputPtr output)
+{
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    int max_lane_count = 4;
+
+    if (radeon_output->dpcp8[0] >= 0x11) {
+	max_lane_count = radeon_output->dpcp8[2] & 0x1f;
+	switch(max_lane_count) {
+	case 1: case 2: case 4:
+	    break;
+	default:
+	    max_lane_count = 4;
+	}
+    }
+    return max_lane_count;
+}
+
+static int radeon_dp_max_link_bw(xf86OutputPtr output)
+{
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    int max_link_bw = radeon_output->dpcp8[1];
+    switch(max_link_bw) {
+    case DP_LINK_BW_1_62:
+    case DP_LINK_BW_2_7:
+	break;
+    default:
+	max_link_bw = DP_LINK_BW_1_62;
+	break;
+    }
+    return max_link_bw;
+}
+
+static int radeon_dp_link_clock(uint8_t link_bw)
+{
+    if (link_bw == DP_LINK_BW_2_7)
+	return 270000;
+    else
+	return 162000;
+}
+
+
+/* I think this is a fiction */
+static int radeon_dp_link_required(int pixel_clock)
+{
+    return pixel_clock * 3;
+}
+
+static Bool radeon_dp_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    RADEONInfoPtr info       = RADEONPTR(output->scrn);
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    int lane_count, clock;
+    int max_lane_count = radeon_dp_max_lane_count(output);
+    int max_clock = radeon_dp_max_link_bw(output) == DP_LINK_BW_2_7 ? 1 : 0;
+    static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
+
+    for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
+	for (clock = 0; clock <= max_clock; clock++) {
+	    int link_avail = radeon_dp_link_clock(bws[clock]) * lane_count;
+	    
+	    if (radeon_dp_link_required(mode->Clock) <= link_avail) {
+		radeon_output->dp_link_bw = bws[clock];
+		radeon_output->dp_lane_count = lane_count;
+		radeon_output->dp_clock = radeon_dp_link_clock(radeon_output->dp_link_bw);
+		if (1)
+			xf86DrvMsg(0, X_INFO,
+				   "link_bw %d lane_count %d clock %d\n",
+				   radeon_output->dp_link_bw, radeon_output->dp_lane_count,
+				   radeon_output->dp_clock);
+		return TRUE;
+	    }
+	}
+    }
+    return FALSE;
+}
+ 
+static void radeon_dp_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
+{
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    memset(radeon_output->dp_link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
+    radeon_output->dp_link_configuration[0] = radeon_output->dp_link_bw;
+    radeon_output->dp_link_configuration[1] = radeon_output->dp_lane_count;
+    
+    if (radeon_output->dpcp8[0] >= 0x11) {
+	radeon_output->dp_link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+    }
+}
+
+
 
 static void do_displayport_dance(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
 {
@@ -2186,45 +2484,83 @@ static void do_displayport_dance(xf86OutputPtr output, DisplayModePtr mode, Disp
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
     int num_lane = dp_lanes_for_mode_clock(mode->Clock);
     int dp_clock = dp_link_clock_for_mode_clock(mode->Clock);
+    int enc_id = atom_dp_get_encoder_id(output);
     Bool clock_recovery;
     uint8_t link_status[DP_LINK_STATUS_SIZE];
-    uint8_t tries;
+    uint8_t tries, voltage;
     uint8_t train_set[4];
+    Bool ret;
+    int i;
+    Bool channel_eq;
+
     ErrorF("Doing displayport DANCE lanes:%d %d\n", num_lane, dp_clock);
 
-    if (IS_DCE32_VARIANT) {
-	if (radeon_output->dig_block)
-	    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START,
-				   ATOM_DP_CONFIG_DIG2_ENCODER);
-	else
-	    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START,
-				   ATOM_DP_CONFIG_DIG1_ENCODER);
-    } else {
-	if (radeon_output->linkb)
-	    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START,
-				   ATOM_DP_CONFIG_DIG2_ENCODER);
-	else
-	    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START,
-				   ATOM_DP_CONFIG_DIG1_ENCODER);
+    ret = radeon_dp_mode_fixup(output, mode, adjusted_mode);
+    if (ret == FALSE) {
+	ErrorF("Doing displayport DANCE failed to fixup\n");
+	return;
     }
 
+    /* set up link configuration */
+    radeon_dp_mode_set(output, mode, adjusted_mode);
+
+    /* power up to D0 */
+    dp_set_power(output, DP_SET_POWER_D0);
+
+    /* disable training */
+    dp_set_training(output, DP_TRAINING_PATTERN_DISABLE);
+
+    /* write link rate / num / eh framing */
+    atom_dp_aux_native_write(output, 0x100, 2,
+			     radeon_output->dp_link_configuration);
+
+    /* start local training start */
+    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START, enc_id, 0);
+
+    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 0);
+
     memset(train_set, 0, 4);
     /* loop around doing configuration reads and DP encoder setups */
     clock_recovery = FALSE;
     tries = 0;
+    voltage = 0xff;
     for (;;) {
+
+	if (!atom_dp_set_link_train(output, DP_TRAINING_PATTERN_1, train_set))
+	    break;
+	
+	usleep(100);
 	if (!atom_dp_get_link_status(output, link_status))
 	    break;
 
-	    
 	if (dp_clock_recovery_ok(link_status, num_lane)) {
 	    clock_recovery = TRUE;
 	    break;
 	}
-	tries++;
 
-	if (tries == 5)
+	for (i = 0; i < radeon_output->dp_lane_count; i++)
+	    if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+		break;
+	if (i == radeon_output->dp_lane_count) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "clock recovery reached max voltage\n");
 	    break;
+	}
+
+	/* Check to see if we've tried the same voltage 5 times */
+	if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+	    ++tries;
+	    if (tries == 5) {
+		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+			   "clock recovery tried 5 times\n");
+		break;
+	    }
+	} else
+	    tries = 0;
+
+	voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+        dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set);
     }
 
     if (!clock_recovery)
@@ -2237,19 +2573,47 @@ static void do_displayport_dance(xf86OutputPtr output, DisplayModePtr mode, Disp
                    (train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
                    DP_TRAIN_PRE_EMPHASIS_SHIFT);
 
-    if (IS_DCE32_VARIANT) {
-	if (radeon_output->dig_block)
-	    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE,
-				   ATOM_DP_CONFIG_DIG2_ENCODER);
-	else
-	    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE,
-				   ATOM_DP_CONFIG_DIG1_ENCODER);
-    } else {
-	if (radeon_output->linkb)
-	    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE,
-				   ATOM_DP_CONFIG_DIG2_ENCODER);
-	else
-	    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE,
-				   ATOM_DP_CONFIG_DIG1_ENCODER);
+    /* channel equalization */
+    tries = 0;
+    channel_eq = FALSE;
+    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 1);
+    for (;;) {
+
+	if (!atom_dp_set_link_train(output, DP_TRAINING_PATTERN_2, train_set))
+	    break;
+	usleep(400);
+	if (!atom_dp_get_link_status(output, link_status))
+	    break;
+
+	if (dp_channel_eq_ok(link_status, radeon_output->dp_lane_count)) {
+	    channel_eq = TRUE;
+	    break;
+	}
+	
+	/* Try 5 times */
+	if (tries > 5) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "channel eq failed: 5 tries\n");
+	    break;
+	}
+
+	/* Compute new train_set as requested by target */
+        dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set);
+	++tries;
     }
+    
+    if (!channel_eq)
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "channel eq failed\n");
+    else if (1) //pI830->debug_modes)
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		   "channel eq at voltage %d pre-emphasis %d\n",
+		   train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
+		   (train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
+		   >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
+
+
+    dp_set_training(output, DP_TRAINING_PATTERN_DISABLE);
+    RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE, enc_id, 0);
+
 }
diff --git a/src/radeon_probe.h b/src/radeon_probe.h
index 7717031..16b5f06 100644
--- a/src/radeon_probe.h
+++ b/src/radeon_probe.h
@@ -226,6 +226,7 @@ typedef struct _radeon_dvo {
     Bool              dvo_duallink;
 } radeon_dvo_rec, *radeon_dvo_ptr;
 
+
 typedef struct {
     RADEONConnectorType ConnectorType;
     Bool valid;
@@ -287,6 +288,11 @@ typedef struct _RADEONOutputPrivateRec {
     uint32_t dp_i2c_addr, dp_i2c_running;
     uint8_t dpcp8[8];
     uint8_t ucI2cId;
+    int dp_lane_count;
+    int dp_link_bw;
+    int dp_clock;
+#define DP_LINK_CONFIGURATION_SIZE 9
+    uint8_t dp_link_configuration[DP_LINK_CONFIGURATION_SIZE];
 } RADEONOutputPrivateRec, *RADEONOutputPrivatePtr;
 
 struct avivo_pll_state {


More information about the xorg-commit mailing list