radeon_hd: Rework dp aux functions to take connector index

* This is less pretty, but we need access to the connector
  to find the HPD gpio pin mask on the card.
* dp_aux communications seem to work again.
* If you have a DisplayPort item attached to your card you
  may want to just unplug it at this point. We attempt DP
  link training and it fails. This failure will also cause
  other monitors to not function as app_server still isn't
  multi-head aware (#10486)
This commit is contained in:
Alexander von Gluck IV
2014-02-03 20:20:13 -06:00
parent 27a5783afc
commit 339a018112
6 changed files with 149 additions and 116 deletions
@@ -258,4 +258,4 @@
#define EVERGREEN_DC_GPIO_HPD_Y 0x64bc
#endif /* __EVERGREEN_REG_H__ */
#endif /* __EVERGREEN_REG_H__ */
@@ -304,6 +304,7 @@
#define SI_LB_D6_VBLANK_INTERRUPT (1 << 3)
#define SI_DC_HPD6_INTERRUPT (1 << 17)
#define SI_DC_HPD6_RX_INTERRUPT (1 << 18)
#define SI_DC_GPIO_HPD_A 0x65b4
/* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */
#define SI_GRPH_INT_STATUS 0x6858
@@ -161,7 +161,6 @@ typedef struct {
uint16 hpdPinIndex; // id of gpio pin for hotplug detection
struct encoder_info encoder;
struct encoder_info encoderExternal;
// TODO struct radeon_hpd hpd;
dp_info dpInfo;
} connector_info;
@@ -31,10 +31,13 @@
static status_t
dp_aux_speak(uint32 hwPin, uint8* send, int sendBytes,
dp_aux_speak(uint32 connectorIndex, uint8* send, int sendBytes,
uint8* recv, int recvBytes, uint8 delay, uint8* ack)
{
if (hwPin == 0) {
radeon_shared_info &info = *gInfo->shared_info;
dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
if (dpInfo->auxPin == 0) {
ERROR("%s: cannot speak on invalid GPIO pin!\n", __func__);
return B_IO_ERROR;
}
@@ -52,11 +55,46 @@ dp_aux_speak(uint32 hwPin, uint8* send, int sendBytes,
args.v1.lpAuxRequest = B_HOST_TO_LENDIAN_INT16(0 + 4);
args.v1.lpDataOut = B_HOST_TO_LENDIAN_INT16(16 + 4);
args.v1.ucDataOutLen = 0;
args.v1.ucChannelID = hwPin;
args.v1.ucChannelID = dpInfo->auxPin;
args.v1.ucDelay = delay / 10;
//if (ASIC_IS_DCE4(rdev))
// args.v2.ucHPD_ID = chan->rec.hpd;
uint16 hpdPinIndex = gConnector[connectorIndex]->hpdPinIndex;
if (info.dceMajor >= 4
&& gGPIOInfo[hpdPinIndex]->valid) {
uint32 targetReg = EVERGREEN_DC_GPIO_HPD_A;
if (info.dceMajor >= 6)
targetReg = SI_DC_GPIO_HPD_A;
// You're drunk AMD, go home. (this makes no sense)
if (gGPIOInfo[hpdPinIndex]->hwReg == targetReg) {
switch(gGPIOInfo[hpdPinIndex]->hwMask) {
case (1 << 0):
args.v2.ucHPD_ID = 0;
break;
case (1 << 8):
args.v2.ucHPD_ID = 1;
break;
case (1 << 16):
args.v2.ucHPD_ID = 2;
break;
case (1 << 24):
args.v2.ucHPD_ID = 3;
break;
case (1 << 26):
args.v2.ucHPD_ID = 4;
break;
case (1 << 28):
args.v2.ucHPD_ID = 5;
break;
default:
args.v2.ucHPD_ID = 0xff;
break;
}
} else {
args.v2.ucHPD_ID = 0xff;
}
}
unsigned char* base = (unsigned char*)(gAtomContext->scratch + 1);
@@ -94,7 +132,7 @@ dp_aux_speak(uint32 hwPin, uint8* send, int sendBytes,
status_t
dp_aux_write(uint32 hwPin, uint16 address,
dp_aux_write(uint32 connectorIndex, uint16 address,
uint8* send, uint8 sendBytes, uint8 delay)
{
uint8 auxMessage[20];
@@ -114,8 +152,8 @@ dp_aux_write(uint32 hwPin, uint16 address,
uint8 retry;
for (retry = 0; retry < 7; retry++) {
uint8 ack;
status_t result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes,
NULL, 0, delay, &ack);
status_t result = dp_aux_speak(connectorIndex, auxMessage,
auxMessageBytes, NULL, 0, delay, &ack);
if (result == B_BUSY)
continue;
@@ -137,7 +175,7 @@ dp_aux_write(uint32 hwPin, uint16 address,
status_t
dp_aux_read(uint32 hwPin, uint16 address,
dp_aux_read(uint32 connectorIndex, uint16 address,
uint8* recv, int recvBytes, uint8 delay)
{
uint8 auxMessage[4];
@@ -151,8 +189,8 @@ dp_aux_read(uint32 hwPin, uint16 address,
uint8 retry;
for (retry = 0; retry < 7; retry++) {
uint8 ack;
status_t result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes,
recv, recvBytes, delay, &ack);
status_t result = dp_aux_speak(connectorIndex, auxMessage,
auxMessageBytes, recv, recvBytes, delay, &ack);
if (result == B_BUSY)
continue;
@@ -174,19 +212,19 @@ dp_aux_read(uint32 hwPin, uint16 address,
void
dpcd_reg_write(uint32 hwPin, uint16 address, uint8 value)
dpcd_reg_write(uint32 connectorIndex, uint16 address, uint8 value)
{
status_t result = dp_aux_write(hwPin, address, &value, 1, 0);
status_t result = dp_aux_write(connectorIndex, address, &value, 1, 0);
if (result != B_OK)
ERROR("%s: error on DisplayPort aux write (0x%lX)\n", __func__, result);
}
uint8
dpcd_reg_read(uint32 hwPin, uint16 address)
dpcd_reg_read(uint32 connectorIndex, uint16 address)
{
uint8 value = 0;
status_t result = dp_aux_read(hwPin, address, &value, 1, 0);
status_t result = dp_aux_read(connectorIndex, address, &value, 1, 0);
if (result != B_OK)
ERROR("%s: error on DisplayPort aux read (0x%lX)\n", __func__, result);
@@ -195,7 +233,7 @@ dpcd_reg_read(uint32 hwPin, uint16 address)
status_t
dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data,
dp_aux_get_i2c_byte(uint32 connectorIndex, uint16 address, uint8* data,
bool start, bool stop)
{
uint8 auxMessage[5];
@@ -217,15 +255,14 @@ dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data,
auxMessageBytes = 4;
}
int retry;
for (retry = 0; retry < 4; retry++) {
uint8 ack;
uint8 reply[2];
int replyBytes = 1;
status_t result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes,
reply, replyBytes, 0, &ack);
status_t result = dp_aux_speak(connectorIndex, auxMessage,
auxMessageBytes, reply, replyBytes, 0, &ack);
if (result == B_BUSY)
continue;
else if (result != B_OK) {
@@ -274,7 +311,7 @@ dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data,
status_t
dp_aux_set_i2c_byte(uint32 hwPin, uint16 address, uint8* data,
dp_aux_set_i2c_byte(uint32 connectorIndex, uint16 address, uint8* data,
bool start, bool stop)
{
uint8 auxMessage[5];
@@ -303,8 +340,8 @@ dp_aux_set_i2c_byte(uint32 hwPin, uint16 address, uint8* data,
uint8 reply[2];
int replyBytes = 1;
status_t result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes,
reply, replyBytes, 0, &ack);
status_t result = dp_aux_speak(connectorIndex, auxMessage,
auxMessageBytes, reply, replyBytes, 0, &ack);
if (result == B_BUSY)
continue;
else if (result != B_OK) {
@@ -455,7 +492,7 @@ dp_setup_connectors()
uint8 auxMessage[DP_DPCD_SIZE];
status_t result = dp_aux_read(auxPin, DP_DPCD_REV, auxMessage,
status_t result = dp_aux_read(index, DP_DPCD_REV, auxMessage,
DP_DPCD_SIZE, 0);
if (result == B_OK) {
@@ -476,10 +513,11 @@ dp_setup_connectors()
}
static bool
dp_get_link_status(dp_info* dp)
bool
dp_get_link_status(uint32 connectorIndex)
{
status_t result = dp_aux_read(dp->auxPin, DP_LANE_STATUS_0_1,
dp_info* dp = &gConnector[connectorIndex]->dpInfo;
status_t result = dp_aux_read(connectorIndex, DP_LANE_STATUS_0_1,
dp->linkStatus, DP_LINK_STATUS_SIZE, 100);
if (result != B_OK) {
@@ -547,7 +585,7 @@ dp_update_vs_emph(uint32 connectorIndex)
dp->trainingSet[0], ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH);
// Set vs and emph on the sink
dp_aux_write(dp->auxPin, DP_TRAIN_LANE0,
dp_aux_write(connectorIndex, DP_TRAIN_LANE0,
dp->trainingSet, dp->laneCount, 0);
}
@@ -664,7 +702,7 @@ dp_set_tp(uint32 connectorIndex, int trainingPattern)
}
// Enable training pattern on the sink
dpcd_reg_write(dp->auxPin, DP_TRAIN, trainingPattern);
dpcd_reg_write(connectorIndex, DP_TRAIN, trainingPattern);
}
@@ -692,7 +730,7 @@ dp_link_train_cr(uint32 connectorIndex)
else
snooze(1000 * 4 * dp->trainingReadInterval);
if (!dp_get_link_status(dp))
if (!dp_get_link_status(connectorIndex))
break;
if (dp_clock_recovery_ok(dp)) {
@@ -759,7 +797,7 @@ dp_link_train_ce(uint32 connectorIndex)
else
snooze(1000 * 4 * dp->trainingReadInterval);
if (!dp_get_link_status(dp))
if (!dp_get_link_status(connectorIndex))
break;
if (dp_clock_equalization_ok(dp)) {
@@ -824,8 +862,6 @@ dp_link_train(uint8 crtcID)
uint32 linkEnumeration
= gConnector[connectorIndex]->encoder.linkEnumeration;
uint32 i2cPinIndex = gConnector[connectorIndex]->i2cPinIndex;
uint32 hwPin = gGPIOInfo[i2cPinIndex]->hwPin;
uint32 dpEncoderID = 0;
if (encoder_pick_dig(connectorIndex) > 0)
@@ -838,9 +874,9 @@ dp_link_train(uint8 crtcID)
dpEncoderID |= ATOM_DP_CONFIG_LINK_A;
dp->trainingReadInterval
= dpcd_reg_read(hwPin, DP_TRAINING_AUX_RD_INTERVAL);
= dpcd_reg_read(connectorIndex, DP_TRAINING_AUX_RD_INTERVAL);
uint8 sandbox = dpcd_reg_read(hwPin, DP_MAX_LANE_COUNT);
uint8 sandbox = dpcd_reg_read(connectorIndex, DP_MAX_LANE_COUNT);
radeon_shared_info &info = *gInfo->shared_info;
//bool dpTPS3Supported = false;
@@ -851,13 +887,14 @@ dp_link_train(uint8 crtcID)
// Power up the DP sink
if (dp->config[0] >= DP_DPCD_REV_11)
dpcd_reg_write(hwPin, DP_SET_POWER, DP_SET_POWER_D0);
dpcd_reg_write(connectorIndex, DP_SET_POWER, DP_SET_POWER_D0);
// Possibly enable downspread on the sink
if ((dp->config[3] & 0x1) != 0)
dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, DP_DOWNSPREAD_CTRL_AMP_EN);
else
dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, 0);
if ((dp->config[3] & 0x1) != 0) {
dpcd_reg_write(connectorIndex, DP_DOWNSPREAD_CTRL,
DP_DOWNSPREAD_CTRL_AMP_EN);
} else
dpcd_reg_write(connectorIndex, DP_DOWNSPREAD_CTRL, 0);
encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
ATOM_ENCODER_CMD_SETUP_PANEL_MODE);
@@ -867,11 +904,11 @@ dp_link_train(uint8 crtcID)
if ((dp->config[0] >= DP_DPCD_REV_11)
&& (dp->config[2] & DP_ENHANCED_FRAME_CAP_EN))
sandbox |= DP_ENHANCED_FRAME_EN;
dpcd_reg_write(hwPin, DP_LANE_COUNT, sandbox);
dpcd_reg_write(connectorIndex, DP_LANE_COUNT, sandbox);
// Set the link rate on the DP sink
sandbox = dp_encode_link_rate(dp->linkRate);
dpcd_reg_write(hwPin, DP_LINK_RATE, sandbox);
dpcd_reg_write(connectorIndex, DP_LINK_RATE, sandbox);
// Start link training on source
if (info.dceMajor >= 4 || !dp->trainingUseEncoder) {
@@ -883,7 +920,7 @@ dp_link_train(uint8 crtcID)
}
// Disable the training pattern on the sink
dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
dpcd_reg_write(connectorIndex, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
dp_link_train_cr(connectorIndex);
dp_link_train_ce(connectorIndex);
@@ -892,7 +929,7 @@ dp_link_train(uint8 crtcID)
snooze(400);
// Disable the training pattern on the sink
dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
dpcd_reg_write(connectorIndex, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
// Disable the training pattern on the source
if (info.dceMajor >= 4 || !dp->trainingUseEncoder) {
@@ -928,29 +965,29 @@ ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info* edid)
// radeon code; not sure if the initial writes to address 0 are
// requried.
// TODO: This surely cane be cleaned up
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x00, &sdata, true, false);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x00, &sdata, false, true);
dp_aux_set_i2c_byte(connectorIndex, 0x00, &sdata, true, false);
dp_aux_set_i2c_byte(connectorIndex, 0x00, &sdata, false, true);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, true, false);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, false);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, true, false);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, false, false);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, false, true);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, true, false);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, false);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, true, false);
dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, true, false);
dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, false, false);
dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, true, false);
dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, false, false);
dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, false, true);
dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, true, false);
dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, false, false);
dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, true, false);
for (uint32 i = 0; i < sizeof(raw); i++) {
status_t result = dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50,
status_t result = dp_aux_get_i2c_byte(connectorIndex, 0x50,
rdata++, false, false);
if (result != B_OK) {
TRACE("%s: error reading EDID data at index %" B_PRIu32 ", "
"result = 0x%lX\n", __func__, i, result);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, true);
dp_aux_get_i2c_byte(connectorIndex, 0x50, &sdata, false, true);
return false;
}
}
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, true);
dp_aux_get_i2c_byte(connectorIndex, 0x50, &sdata, false, true);
if (raw.version.version != 1 || raw.version.revision > 4) {
ERROR("%s: EDID version or revision out of range\n", __func__);
@@ -23,18 +23,18 @@
#define DP_TPS3_SUPPORTED (1 << 6) // Stored within MAX_LANE_COUNT
uint8 dpcd_reg_read(uint32 hwPin, uint16 address);
void dpcd_reg_write(uint32 hwPin, uint16 address, uint8 value);
uint8 dpcd_reg_read(uint32 connectorIndex, uint16 address);
void dpcd_reg_write(uint32 connectorIndex, uint16 address, uint8 value);
// Communication over DisplayPort AUX channel
status_t dp_aux_write(uint32 hwPin, uint16 address, uint8* send,
status_t dp_aux_write(uint32 connectorIndex, uint16 address, uint8* send,
uint8 sendBytes, uint8 delay);
status_t dp_aux_read(uint32 hwPin, uint16 address, uint8* recv,
status_t dp_aux_read(uint32 connectorIndex, uint16 address, uint8* recv,
int recvBytes, uint8 delay);
status_t dp_aux_set_i2c_byte(uint32 hwPin, uint16 address,
status_t dp_aux_set_i2c_byte(uint32 connectorIndex, uint16 address,
uint8* data, bool start, bool stop);
status_t dp_aux_get_i2c_byte(uint32 hwPin, uint16 address,
status_t dp_aux_get_i2c_byte(uint32 connectorIndex, uint16 address,
uint8* data, bool start, bool stop);
uint32 dp_get_link_rate(uint32 connectorIndex, display_mode* mode);
+48 -52
View File
@@ -110,7 +110,7 @@ radeon_get_preferred_mode(display_mode* preferredMode)
status_t
radeon_get_edid_info(void* info, size_t size, uint32* edid_version)
{
// TODO: multi-monitor? for now we use VESA edid
// TODO: multi-monitor? for now we use display 0
uint8 crtcID = 0;
TRACE("%s\n", __func__);
@@ -164,14 +164,12 @@ radeon_dpms_set(uint8 id, int mode)
void
radeon_dpms_set_hook(int mode)
{
// TODO: multi-monitor? for now we use VESA edid
// TODO: multi-monitor?
// As the accelerant hook doesn't pass crtc id
for (uint8 id = 0; id < MAX_DISPLAY; id++) {
if (gDisplay[id]->attached == false)
continue;
radeon_dpms_set(id, mode);
}
uint8 crtcID = 0;
if (gDisplay[crtcID]->attached)
radeon_dpms_set(crtcID, mode);
}
@@ -179,57 +177,55 @@ status_t
radeon_set_display_mode(display_mode* mode)
{
// TODO: multi-monitor? For now we set the mode on
// all displays (this is very incorrect). This also
// causes a lot of problems on DisplayPort devices
// the first display found.
// Set mode on each display
for (uint8 id = 0; id < MAX_DISPLAY; id++) {
if (gDisplay[id]->attached == false)
continue;
uint8 crtcID = 0;
// Copy this display mode into the "current mode" for the display
memcpy(&gDisplay[id]->currentMode, mode, sizeof(display_mode));
if (gDisplay[crtcID]->attached == false)
return B_ERROR;
uint32 connectorIndex = gDisplay[id]->connectorIndex;
// Copy this display mode into the "current mode" for the display
memcpy(&gDisplay[crtcID]->currentMode, mode, sizeof(display_mode));
// Determine DP lanes if DP
if (connector_is_dp(connectorIndex)) {
dp_info *dpInfo = &gConnector[connectorIndex]->dpInfo;
dpInfo->laneCount = dp_get_lane_count(connectorIndex, mode);
dpInfo->linkRate = dp_get_link_rate(connectorIndex, mode);
}
uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
// *** crtc and encoder prep
encoder_output_lock(true);
display_crtc_lock(id, ATOM_ENABLE);
radeon_dpms_set(id, B_DPMS_OFF);
// *** Set up encoder -> crtc routing
encoder_assign_crtc(id);
// *** CRT controler mode set
// Set up PLL for connector
pll_pick(connectorIndex);
pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
TRACE("%s: pll %d selected for connector %" B_PRIu32 "\n", __func__,
pll->id, connectorIndex);
pll_set(mode, id);
display_crtc_set_dtd(id, mode);
display_crtc_fb_set(id, mode);
// atombios_overscan_setup
display_crtc_scale(id, mode);
// *** encoder mode set
encoder_mode_set(id);
// *** encoder and CRT controller commit
radeon_dpms_set(id, B_DPMS_ON);
display_crtc_lock(id, ATOM_DISABLE);
encoder_output_lock(false);
// Determine DP lanes if DP
if (connector_is_dp(connectorIndex)) {
dp_info *dpInfo = &gConnector[connectorIndex]->dpInfo;
dpInfo->laneCount = dp_get_lane_count(connectorIndex, mode);
dpInfo->linkRate = dp_get_link_rate(connectorIndex, mode);
}
// *** crtc and encoder prep
encoder_output_lock(true);
display_crtc_lock(crtcID, ATOM_ENABLE);
radeon_dpms_set(crtcID, B_DPMS_OFF);
// *** Set up encoder -> crtc routing
encoder_assign_crtc(crtcID);
// *** CRT controler mode set
// Set up PLL for connector
pll_pick(connectorIndex);
pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
TRACE("%s: pll %d selected for connector %" B_PRIu32 "\n", __func__,
pll->id, connectorIndex);
pll_set(mode, crtcID);
display_crtc_set_dtd(crtcID, mode);
display_crtc_fb_set(crtcID, mode);
// atombios_overscan_setup
display_crtc_scale(crtcID, mode);
// *** encoder mode set
encoder_mode_set(crtcID);
// *** encoder and CRT controller commit
radeon_dpms_set(crtcID, B_DPMS_ON);
display_crtc_lock(crtcID, ATOM_DISABLE);
encoder_output_lock(false);
#ifdef TRACE_MODE
// for debugging
debug_dp_info();