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 #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_LB_D6_VBLANK_INTERRUPT (1 << 3)
#define SI_DC_HPD6_INTERRUPT (1 << 17) #define SI_DC_HPD6_INTERRUPT (1 << 17)
#define SI_DC_HPD6_RX_INTERRUPT (1 << 18) #define SI_DC_HPD6_RX_INTERRUPT (1 << 18)
#define SI_DC_GPIO_HPD_A 0x65b4
/* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */ /* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */
#define SI_GRPH_INT_STATUS 0x6858 #define SI_GRPH_INT_STATUS 0x6858
@@ -161,7 +161,6 @@ typedef struct {
uint16 hpdPinIndex; // id of gpio pin for hotplug detection uint16 hpdPinIndex; // id of gpio pin for hotplug detection
struct encoder_info encoder; struct encoder_info encoder;
struct encoder_info encoderExternal; struct encoder_info encoderExternal;
// TODO struct radeon_hpd hpd;
dp_info dpInfo; dp_info dpInfo;
} connector_info; } connector_info;
@@ -31,10 +31,13 @@
static status_t 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) 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__); ERROR("%s: cannot speak on invalid GPIO pin!\n", __func__);
return B_IO_ERROR; 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.lpAuxRequest = B_HOST_TO_LENDIAN_INT16(0 + 4);
args.v1.lpDataOut = B_HOST_TO_LENDIAN_INT16(16 + 4); args.v1.lpDataOut = B_HOST_TO_LENDIAN_INT16(16 + 4);
args.v1.ucDataOutLen = 0; args.v1.ucDataOutLen = 0;
args.v1.ucChannelID = hwPin; args.v1.ucChannelID = dpInfo->auxPin;
args.v1.ucDelay = delay / 10; args.v1.ucDelay = delay / 10;
//if (ASIC_IS_DCE4(rdev)) uint16 hpdPinIndex = gConnector[connectorIndex]->hpdPinIndex;
// args.v2.ucHPD_ID = chan->rec.hpd; 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); unsigned char* base = (unsigned char*)(gAtomContext->scratch + 1);
@@ -94,7 +132,7 @@ dp_aux_speak(uint32 hwPin, uint8* send, int sendBytes,
status_t status_t
dp_aux_write(uint32 hwPin, uint16 address, dp_aux_write(uint32 connectorIndex, uint16 address,
uint8* send, uint8 sendBytes, uint8 delay) uint8* send, uint8 sendBytes, uint8 delay)
{ {
uint8 auxMessage[20]; uint8 auxMessage[20];
@@ -114,8 +152,8 @@ dp_aux_write(uint32 hwPin, uint16 address,
uint8 retry; uint8 retry;
for (retry = 0; retry < 7; retry++) { for (retry = 0; retry < 7; retry++) {
uint8 ack; uint8 ack;
status_t result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes, status_t result = dp_aux_speak(connectorIndex, auxMessage,
NULL, 0, delay, &ack); auxMessageBytes, NULL, 0, delay, &ack);
if (result == B_BUSY) if (result == B_BUSY)
continue; continue;
@@ -137,7 +175,7 @@ dp_aux_write(uint32 hwPin, uint16 address,
status_t status_t
dp_aux_read(uint32 hwPin, uint16 address, dp_aux_read(uint32 connectorIndex, uint16 address,
uint8* recv, int recvBytes, uint8 delay) uint8* recv, int recvBytes, uint8 delay)
{ {
uint8 auxMessage[4]; uint8 auxMessage[4];
@@ -151,8 +189,8 @@ dp_aux_read(uint32 hwPin, uint16 address,
uint8 retry; uint8 retry;
for (retry = 0; retry < 7; retry++) { for (retry = 0; retry < 7; retry++) {
uint8 ack; uint8 ack;
status_t result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes, status_t result = dp_aux_speak(connectorIndex, auxMessage,
recv, recvBytes, delay, &ack); auxMessageBytes, recv, recvBytes, delay, &ack);
if (result == B_BUSY) if (result == B_BUSY)
continue; continue;
@@ -174,19 +212,19 @@ dp_aux_read(uint32 hwPin, uint16 address,
void 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) if (result != B_OK)
ERROR("%s: error on DisplayPort aux write (0x%lX)\n", __func__, result); ERROR("%s: error on DisplayPort aux write (0x%lX)\n", __func__, result);
} }
uint8 uint8
dpcd_reg_read(uint32 hwPin, uint16 address) dpcd_reg_read(uint32 connectorIndex, uint16 address)
{ {
uint8 value = 0; 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) if (result != B_OK)
ERROR("%s: error on DisplayPort aux read (0x%lX)\n", __func__, result); 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 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) bool start, bool stop)
{ {
uint8 auxMessage[5]; uint8 auxMessage[5];
@@ -217,15 +255,14 @@ dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data,
auxMessageBytes = 4; auxMessageBytes = 4;
} }
int retry; int retry;
for (retry = 0; retry < 4; retry++) { for (retry = 0; retry < 4; retry++) {
uint8 ack; uint8 ack;
uint8 reply[2]; uint8 reply[2];
int replyBytes = 1; int replyBytes = 1;
status_t result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes, status_t result = dp_aux_speak(connectorIndex, auxMessage,
reply, replyBytes, 0, &ack); auxMessageBytes, reply, replyBytes, 0, &ack);
if (result == B_BUSY) if (result == B_BUSY)
continue; continue;
else if (result != B_OK) { else if (result != B_OK) {
@@ -274,7 +311,7 @@ dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data,
status_t 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) bool start, bool stop)
{ {
uint8 auxMessage[5]; uint8 auxMessage[5];
@@ -303,8 +340,8 @@ dp_aux_set_i2c_byte(uint32 hwPin, uint16 address, uint8* data,
uint8 reply[2]; uint8 reply[2];
int replyBytes = 1; int replyBytes = 1;
status_t result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes, status_t result = dp_aux_speak(connectorIndex, auxMessage,
reply, replyBytes, 0, &ack); auxMessageBytes, reply, replyBytes, 0, &ack);
if (result == B_BUSY) if (result == B_BUSY)
continue; continue;
else if (result != B_OK) { else if (result != B_OK) {
@@ -455,7 +492,7 @@ dp_setup_connectors()
uint8 auxMessage[DP_DPCD_SIZE]; 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); DP_DPCD_SIZE, 0);
if (result == B_OK) { if (result == B_OK) {
@@ -476,10 +513,11 @@ dp_setup_connectors()
} }
static bool bool
dp_get_link_status(dp_info* dp) 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); dp->linkStatus, DP_LINK_STATUS_SIZE, 100);
if (result != B_OK) { if (result != B_OK) {
@@ -547,7 +585,7 @@ dp_update_vs_emph(uint32 connectorIndex)
dp->trainingSet[0], ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH); dp->trainingSet[0], ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH);
// Set vs and emph on the sink // 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); dp->trainingSet, dp->laneCount, 0);
} }
@@ -664,7 +702,7 @@ dp_set_tp(uint32 connectorIndex, int trainingPattern)
} }
// Enable training pattern on the sink // 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 else
snooze(1000 * 4 * dp->trainingReadInterval); snooze(1000 * 4 * dp->trainingReadInterval);
if (!dp_get_link_status(dp)) if (!dp_get_link_status(connectorIndex))
break; break;
if (dp_clock_recovery_ok(dp)) { if (dp_clock_recovery_ok(dp)) {
@@ -759,7 +797,7 @@ dp_link_train_ce(uint32 connectorIndex)
else else
snooze(1000 * 4 * dp->trainingReadInterval); snooze(1000 * 4 * dp->trainingReadInterval);
if (!dp_get_link_status(dp)) if (!dp_get_link_status(connectorIndex))
break; break;
if (dp_clock_equalization_ok(dp)) { if (dp_clock_equalization_ok(dp)) {
@@ -824,8 +862,6 @@ dp_link_train(uint8 crtcID)
uint32 linkEnumeration uint32 linkEnumeration
= gConnector[connectorIndex]->encoder.linkEnumeration; = gConnector[connectorIndex]->encoder.linkEnumeration;
uint32 i2cPinIndex = gConnector[connectorIndex]->i2cPinIndex;
uint32 hwPin = gGPIOInfo[i2cPinIndex]->hwPin;
uint32 dpEncoderID = 0; uint32 dpEncoderID = 0;
if (encoder_pick_dig(connectorIndex) > 0) if (encoder_pick_dig(connectorIndex) > 0)
@@ -838,9 +874,9 @@ dp_link_train(uint8 crtcID)
dpEncoderID |= ATOM_DP_CONFIG_LINK_A; dpEncoderID |= ATOM_DP_CONFIG_LINK_A;
dp->trainingReadInterval 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; radeon_shared_info &info = *gInfo->shared_info;
//bool dpTPS3Supported = false; //bool dpTPS3Supported = false;
@@ -851,13 +887,14 @@ dp_link_train(uint8 crtcID)
// Power up the DP sink // Power up the DP sink
if (dp->config[0] >= DP_DPCD_REV_11) 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 // Possibly enable downspread on the sink
if ((dp->config[3] & 0x1) != 0) if ((dp->config[3] & 0x1) != 0) {
dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, DP_DOWNSPREAD_CTRL_AMP_EN); dpcd_reg_write(connectorIndex, DP_DOWNSPREAD_CTRL,
else DP_DOWNSPREAD_CTRL_AMP_EN);
dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, 0); } else
dpcd_reg_write(connectorIndex, DP_DOWNSPREAD_CTRL, 0);
encoder_dig_setup(connectorIndex, mode->timing.pixel_clock, encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
ATOM_ENCODER_CMD_SETUP_PANEL_MODE); ATOM_ENCODER_CMD_SETUP_PANEL_MODE);
@@ -867,11 +904,11 @@ dp_link_train(uint8 crtcID)
if ((dp->config[0] >= DP_DPCD_REV_11) if ((dp->config[0] >= DP_DPCD_REV_11)
&& (dp->config[2] & DP_ENHANCED_FRAME_CAP_EN)) && (dp->config[2] & DP_ENHANCED_FRAME_CAP_EN))
sandbox |= DP_ENHANCED_FRAME_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 // Set the link rate on the DP sink
sandbox = dp_encode_link_rate(dp->linkRate); 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 // Start link training on source
if (info.dceMajor >= 4 || !dp->trainingUseEncoder) { if (info.dceMajor >= 4 || !dp->trainingUseEncoder) {
@@ -883,7 +920,7 @@ dp_link_train(uint8 crtcID)
} }
// Disable the training pattern on the sink // 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_cr(connectorIndex);
dp_link_train_ce(connectorIndex); dp_link_train_ce(connectorIndex);
@@ -892,7 +929,7 @@ dp_link_train(uint8 crtcID)
snooze(400); snooze(400);
// Disable the training pattern on the sink // 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 // Disable the training pattern on the source
if (info.dceMajor >= 4 || !dp->trainingUseEncoder) { 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 // radeon code; not sure if the initial writes to address 0 are
// requried. // requried.
// TODO: This surely cane be cleaned up // TODO: This surely cane be cleaned up
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x00, &sdata, true, false); dp_aux_set_i2c_byte(connectorIndex, 0x00, &sdata, true, false);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x00, &sdata, false, true); 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(connectorIndex, 0x50, &sdata, true, false);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, false); dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, false, false);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, true, false); dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, true, false);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, false, false); dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, false, false);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, false, true); dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, false, true);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, true, false); dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, true, false);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, false); dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, false, false);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, true, false); dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, true, false);
for (uint32 i = 0; i < sizeof(raw); i++) { 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); rdata++, false, false);
if (result != B_OK) { if (result != B_OK) {
TRACE("%s: error reading EDID data at index %" B_PRIu32 ", " TRACE("%s: error reading EDID data at index %" B_PRIu32 ", "
"result = 0x%lX\n", __func__, i, result); "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; 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) { if (raw.version.version != 1 || raw.version.revision > 4) {
ERROR("%s: EDID version or revision out of range\n", __func__); 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 #define DP_TPS3_SUPPORTED (1 << 6) // Stored within MAX_LANE_COUNT
uint8 dpcd_reg_read(uint32 hwPin, uint16 address); uint8 dpcd_reg_read(uint32 connectorIndex, uint16 address);
void dpcd_reg_write(uint32 hwPin, uint16 address, uint8 value); void dpcd_reg_write(uint32 connectorIndex, uint16 address, uint8 value);
// Communication over DisplayPort AUX channel // 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); 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); 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); 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); uint8* data, bool start, bool stop);
uint32 dp_get_link_rate(uint32 connectorIndex, display_mode* mode); 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 status_t
radeon_get_edid_info(void* info, size_t size, uint32* edid_version) 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; uint8 crtcID = 0;
TRACE("%s\n", __func__); TRACE("%s\n", __func__);
@@ -164,14 +164,12 @@ radeon_dpms_set(uint8 id, int mode)
void void
radeon_dpms_set_hook(int mode) 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 uint8 crtcID = 0;
for (uint8 id = 0; id < MAX_DISPLAY; id++) {
if (gDisplay[id]->attached == false) if (gDisplay[crtcID]->attached)
continue; radeon_dpms_set(crtcID, mode);
radeon_dpms_set(id, mode);
}
} }
@@ -179,57 +177,55 @@ status_t
radeon_set_display_mode(display_mode* mode) radeon_set_display_mode(display_mode* mode)
{ {
// TODO: multi-monitor? For now we set the mode on // TODO: multi-monitor? For now we set the mode on
// all displays (this is very incorrect). This also // the first display found.
// causes a lot of problems on DisplayPort devices
// Set mode on each display uint8 crtcID = 0;
for (uint8 id = 0; id < MAX_DISPLAY; id++) {
if (gDisplay[id]->attached == false)
continue;
// Copy this display mode into the "current mode" for the display if (gDisplay[crtcID]->attached == false)
memcpy(&gDisplay[id]->currentMode, mode, sizeof(display_mode)); 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 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
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 // Determine DP lanes if DP
encoder_output_lock(true); if (connector_is_dp(connectorIndex)) {
display_crtc_lock(id, ATOM_ENABLE); dp_info *dpInfo = &gConnector[connectorIndex]->dpInfo;
radeon_dpms_set(id, B_DPMS_OFF); dpInfo->laneCount = dp_get_lane_count(connectorIndex, mode);
dpInfo->linkRate = dp_get_link_rate(connectorIndex, mode);
// *** 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);
} }
// *** 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 #ifdef TRACE_MODE
// for debugging // for debugging
debug_dp_info(); debug_dp_info();