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