diff --git a/headers/private/graphics/radeon_hd/evergreen_reg.h b/headers/private/graphics/radeon_hd/evergreen_reg.h index 40d152ac04..3ad4796652 100644 --- a/headers/private/graphics/radeon_hd/evergreen_reg.h +++ b/headers/private/graphics/radeon_hd/evergreen_reg.h @@ -258,4 +258,4 @@ #define EVERGREEN_DC_GPIO_HPD_Y 0x64bc -#endif /* __EVERGREEN_REG_H__ */ \ No newline at end of file +#endif /* __EVERGREEN_REG_H__ */ diff --git a/headers/private/graphics/radeon_hd/si_reg.h b/headers/private/graphics/radeon_hd/si_reg.h index 7654d0e863..adc6f08c5e 100644 --- a/headers/private/graphics/radeon_hd/si_reg.h +++ b/headers/private/graphics/radeon_hd/si_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 diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.h b/src/add-ons/accelerants/radeon_hd/accelerant.h index b286a1b397..61bf1367a5 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.h +++ b/src/add-ons/accelerants/radeon_hd/accelerant.h @@ -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; diff --git a/src/add-ons/accelerants/radeon_hd/displayport.cpp b/src/add-ons/accelerants/radeon_hd/displayport.cpp index 5ebe5bf7f9..78ed25c48c 100644 --- a/src/add-ons/accelerants/radeon_hd/displayport.cpp +++ b/src/add-ons/accelerants/radeon_hd/displayport.cpp @@ -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__); diff --git a/src/add-ons/accelerants/radeon_hd/displayport.h b/src/add-ons/accelerants/radeon_hd/displayport.h index d6e1d7a512..5ad9f19c95 100644 --- a/src/add-ons/accelerants/radeon_hd/displayport.h +++ b/src/add-ons/accelerants/radeon_hd/displayport.h @@ -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); diff --git a/src/add-ons/accelerants/radeon_hd/mode.cpp b/src/add-ons/accelerants/radeon_hd/mode.cpp index 7bd1cda5fb..75c33e9857 100644 --- a/src/add-ons/accelerants/radeon_hd/mode.cpp +++ b/src/add-ons/accelerants/radeon_hd/mode.cpp @@ -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();