radeon_hd: Fix DisplayPort link training

* Original changes by Bill Randle
* Includes a large number of modifications
  and cleanups.
* Add a "currentMode" to the gDisplay to
  enable easier checking of intended changes.
  (we pass the display_mode around quite a
   bit, adding a "currentMode" allows code
   to know the intended display mode being set
   without passing the mode pointer around as
   much)
This commit is contained in:
Alexander von Gluck IV 2013-01-28 23:26:57 -06:00
parent 7d9c1f30f1
commit 00bc40ad58
11 changed files with 317 additions and 101 deletions

View File

@ -172,6 +172,7 @@ typedef struct {
uint32 hfreqMin;
edid1_info edidData;
display_mode preferredMode;
display_mode currentMode;
} display_info;

View File

@ -3,7 +3,8 @@
* Distributed under the terms of the MIT License.
*
* Authors:
* Alexander von Gluck, kallisti5@unixzen.com
* Alexander von Gluck, kallisti5@unixzen.com
* Bill Randle, billr@neocat.org
*/
/*
@ -240,6 +241,29 @@ detect_crt_ranges(uint32 crtid)
}
static void
remove_dup_displays(uint32 displayIndex, uint32 id)
{
/* hack for both digital and analog interfaces active */
if ((displayIndex > 0) && gDisplay[displayIndex]->attached) {
if (gConnector[id-1]->encoder.type == VIDEO_ENCODER_TMDS) {
int gpioID1 = gConnector[id-1]->gpioID;
int gpioID2 = gConnector[id]->gpioID;
edid1_info* edid = &gDisplay[displayIndex-1]->edidData;
if ((gGPIOInfo[gpioID1]->hwPin == gGPIOInfo[gpioID2]->hwPin) &&
edid->display.input_type)
// give preference to digital display when both are present
// and other display indicates it is digital
TRACE("%s: skipping connector %" B_PRIu32
": giving preference to digital "
"connector %d\n", __func__, id, id-1);
gDisplay[displayIndex]->attached = 0;
}
}
}
status_t
detect_displays()
{
@ -264,19 +288,18 @@ detect_displays()
}
if (gConnector[id]->type == VIDEO_CONNECTOR_DP) {
edid1_info* edid = &gDisplay[displayIndex]->edidData;
TRACE("%s: connector(%" B_PRIu32 "): Checking DP.\n", __func__, id);
status_t dpHasEDID = ddc2_dp_read_edid1(id, edid);
edid1_info* edid = &gDisplay[displayIndex]->edidData;
gDisplay[displayIndex]->attached
= (dpHasEDID == B_OK ? true : false);
= ddc2_dp_read_edid1(id, edid);
if (gDisplay[displayIndex]->attached) {
TRACE("%s: connector(%" B_PRIu32 "): Found DisplayPort EDID!\n",
__func__);
}
}
// TODO: As DP aux transactions don't work yet, just use LVDS as a hack
// TODO: Handle external DP brides - ??
#if 0
if (gConnector[id]->encoderExternal.isDPBridge == true) {
// If this is a DisplayPort Bridge, setup ddc on bus
@ -287,11 +310,9 @@ detect_displays()
gDisplay[displayIndex]->attached = true;
// TODO: DDC Router switching for DisplayPort (and others?)
} else if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
}
#endif
if (gDisplay[displayIndex]->attached == false
&& gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
// If plain (non-DP) laptop LVDS, read mode info from AtomBIOS
//TRACE("%s: non-DP laptop LVDS detected\n", __func__);
gDisplay[displayIndex]->attached = connector_read_mode_lvds(id,
@ -313,7 +334,7 @@ detect_displays()
// Since DVI-I shows up as two connectors, and there is only one
// edid channel, we have to make *sure* the edid data received is
// valid for te connector.
// valid for the connector.
// Found EDID data?
if (gDisplay[displayIndex]->attached) {
@ -331,6 +352,7 @@ detect_displays()
"and a analog encoder.\n", __func__, id);
gDisplay[displayIndex]->attached
= encoder_analog_load_detect(id);
remove_dup_displays(displayIndex, id);
} else if (edid->display.input_type && !analogEncoder) {
// If EDID is digital, we make an assumption here.
TRACE("%s: connector(%" B_PRIu32 "): has digital EDID "
@ -339,9 +361,16 @@ detect_displays()
// This generally means the monitor is of poor design
// Since we *know* there is no load on the analog encoder
// we assume that it is a digital display.
// This can also occur when a display has both DVI and VGA
// inputs and the graphics board has a DVI-I connector
// (reported as both digital and analog connectors) and the
// analog connection is the one in use. In that case, we
// get here when checking the digital connector and want
// to disable that display in favor of the analog one.
TRACE("%s: connector(%" B_PRIu32 "): Warning: monitor has "
"false digital EDID flag + unloaded analog encoder!\n",
__func__, id);
gDisplay[displayIndex]->attached = false;
}
}
}
@ -558,7 +587,6 @@ display_crtc_scale(uint8 crtcID, display_mode* mode)
void
display_crtc_dpms(uint8 crtcID, int mode)
{
radeon_shared_info &info = *gInfo->shared_info;
switch (mode) {
@ -566,8 +594,8 @@ display_crtc_dpms(uint8 crtcID, int mode)
TRACE("%s: crtc %" B_PRIu8 " dpms powerup\n", __func__, crtcID);
if (gDisplay[crtcID]->attached == false)
return;
gDisplay[crtcID]->powered = true;
display_crtc_power(crtcID, ATOM_ENABLE);
gDisplay[crtcID]->powered = true;
if (info.dceMajor >= 3)
display_crtc_memreq(crtcID, ATOM_ENABLE);
display_crtc_blank(crtcID, ATOM_BLANKING_OFF);
@ -588,12 +616,121 @@ display_crtc_dpms(uint8 crtcID, int mode)
}
void
display_dce45_crtc_load_lut(uint8 crtcID)
{
radeon_shared_info &info = *gInfo->shared_info;
register_info* regs = gDisplay[crtcID]->regs;
TRACE("%s: crtcID %" B_PRIu8 "\n", __func__, crtcID);
uint16* r = info.color_data;
uint16* g = r + 256;
uint16* b = r + 512;
if (info.dceMajor >= 5) {
Write32(OUT, NI_INPUT_CSC_CONTROL + regs->crtcOffset,
(NI_INPUT_CSC_GRPH_MODE(NI_INPUT_CSC_BYPASS) |
NI_INPUT_CSC_OVL_MODE(NI_INPUT_CSC_BYPASS)));
Write32(OUT, NI_PRESCALE_GRPH_CONTROL + regs->crtcOffset,
NI_GRPH_PRESCALE_BYPASS);
Write32(OUT, NI_PRESCALE_OVL_CONTROL + regs->crtcOffset,
NI_OVL_PRESCALE_BYPASS);
Write32(OUT, NI_INPUT_GAMMA_CONTROL + regs->crtcOffset,
(NI_GRPH_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT) |
NI_OVL_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT)));
}
Write32(OUT, EVERGREEN_DC_LUT_CONTROL + regs->crtcOffset, 0);
Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + regs->crtcOffset, 0);
Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + regs->crtcOffset, 0);
Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_RED + regs->crtcOffset, 0);
Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + regs->crtcOffset, 0xffff);
Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + regs->crtcOffset, 0xffff);
Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_RED + regs->crtcOffset, 0xffff);
Write32(OUT, EVERGREEN_DC_LUT_RW_MODE, 0);
Write32(OUT, EVERGREEN_DC_LUT_WRITE_EN_MASK, 0x00000007);
Write32(OUT, EVERGREEN_DC_LUT_RW_INDEX, 0);
for (int i = 0; i < 256; i++) {
Write32(OUT, EVERGREEN_DC_LUT_30_COLOR + regs->crtcOffset,
(r[i] << 20) |
(g[i] << 10) |
(b[i] << 0));
}
if (info.dceMajor >= 5) {
Write32(OUT, NI_DEGAMMA_CONTROL + regs->crtcOffset,
(NI_GRPH_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) |
NI_OVL_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) |
NI_ICON_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) |
NI_CURSOR_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)));
Write32(OUT, NI_GAMUT_REMAP_CONTROL + regs->crtcOffset,
(NI_GRPH_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS) |
NI_OVL_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS)));
Write32(OUT, NI_REGAMMA_CONTROL + regs->crtcOffset,
(NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) |
NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS)));
Write32(OUT, NI_OUTPUT_CSC_CONTROL + regs->crtcOffset,
(NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) |
NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
/* XXX match this to the depth of the crtc fmt block, move to modeset? */
Write32(OUT, 0x6940 + regs->crtcOffset, 0);
}
}
void
display_avivo_crtc_load_lut(uint8 crtcID)
{
radeon_shared_info &info = *gInfo->shared_info;
register_info* regs = gDisplay[crtcID]->regs;
TRACE("%s: crtcID %" B_PRIu8 "\n", __func__, crtcID);
uint16* r = info.color_data;
uint16* g = r + 256;
uint16* b = r + 512;
Write32(OUT, AVIVO_DC_LUTA_CONTROL + regs->crtcOffset, 0);
Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + regs->crtcOffset, 0);
Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + regs->crtcOffset, 0);
Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_RED + regs->crtcOffset, 0);
Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + regs->crtcOffset, 0xffff);
Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + regs->crtcOffset, 0xffff);
Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_RED + regs->crtcOffset, 0xffff);
Write32(OUT, AVIVO_DC_LUT_RW_SELECT, crtcID);
Write32(OUT, AVIVO_DC_LUT_RW_MODE, 0);
Write32(OUT, AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f);
Write32(OUT, AVIVO_DC_LUT_RW_INDEX, 0);
for (int i = 0; i < 256; i++) {
Write32(OUT, AVIVO_DC_LUT_30_COLOR,
(r[i] << 20) |
(g[i] << 10) |
(b[i] << 0));
}
Write32(OUT, AVIVO_D1GRPH_LUT_SEL + regs->crtcOffset, crtcID);
}
void
display_crtc_fb_set(uint8 crtcID, display_mode* mode)
{
radeon_shared_info &info = *gInfo->shared_info;
register_info* regs = gDisplay[crtcID]->regs;
uint16* r = info.color_data;
uint16* g = r + 256;
uint16* b = r + 512;
uint32 fbSwap;
if (info.dceMajor >= 4)
fbSwap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
@ -616,6 +753,7 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_8BPP
| AVIVO_D1GRPH_CONTROL_8BPP_INDEXED;
}
// TODO: copy system color map into shared info
break;
case B_RGB15_LITTLE:
bytesPerPixel = 2;
@ -646,6 +784,17 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
fbSwap = R600_D1GRPH_SWAP_ENDIAN_16BIT;
#endif
}
{
// default gamma table
uint16 gamma = 0;
for (int i = 0; i < 256; i++) {
r[i] = gamma;
g[i] = gamma;
b[i] = gamma;
gamma += 4;
}
}
break;
case B_RGB24_LITTLE:
case B_RGB32_LITTLE:
@ -666,6 +815,17 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
fbSwap = R600_D1GRPH_SWAP_ENDIAN_32BIT;
#endif
}
{
// default gamma table
uint16 gamma = 0;
for (int i = 0; i < 256; i++) {
r[i] = gamma;
g[i] = gamma;
b[i] = gamma;
gamma += 4;
}
}
break;
}
@ -685,7 +845,7 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
(fbAddress >> 32) & 0xf);
}
TRACE("%s: Set SurfaceAddress: 0x%" B_PRIX32 "\n",
TRACE("%s: Set SurfaceAddress: 0x%" B_PRIX64 "\n",
__func__, (fbAddress & 0xFFFFFFFF));
Write32(OUT, regs->grphPrimarySurfaceAddr, (fbAddress & 0xFFFFFFFF));
@ -700,16 +860,17 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
uint32 widthAligned = mode->virtual_width;
uint32 pitchMask = 0;
// assume micro-linear/macro-linear mode (i.e., not tiled)
switch (bytesPerPixel) {
case 1:
pitchMask = 255;
pitchMask = 63;
break;
case 2:
pitchMask = 127;
pitchMask = 31;
break;
case 3:
case 4:
pitchMask = 63;
pitchMask = 31;
break;
}
widthAligned += pitchMask;
@ -718,7 +879,7 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
TRACE("%s: fb: %" B_PRIu32 "x%" B_PRIu32 " (%" B_PRIu32 " bpp)\n", __func__,
mode->virtual_width, mode->virtual_height, bitsPerPixel);
TRACE("%s: fb pitch: %" B_PRIu32 " \n", __func__,
widthAligned * bytesPerPixel / 4);
widthAligned);
TRACE("%s: fb width aligned: %" B_PRIu32 "\n", __func__,
widthAligned);
@ -728,7 +889,7 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
Write32(CRT, regs->grphYStart, 0);
Write32(CRT, regs->grphXEnd, mode->virtual_width);
Write32(CRT, regs->grphYEnd, mode->virtual_height);
Write32(CRT, regs->grphPitch, widthAligned * bytesPerPixel / 4);
Write32(CRT, regs->grphPitch, widthAligned);
Write32(CRT, regs->grphEnable, 1);
// Enable Frame buffer
@ -751,7 +912,7 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
Write32(OUT, EVERGREEN_MASTER_UPDATE_MODE + regs->crtcOffset, 0);
// Pageflip to happen anywhere in vblank
display_dce45_crtc_load_lut(crtcID);
} else {
uint32 tmp = Read32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset);
tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN;
@ -759,6 +920,7 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
Write32(OUT, AVIVO_D1MODE_MASTER_UPDATE_MODE + regs->crtcOffset, 0);
// Pageflip to happen anywhere in vblank
display_avivo_crtc_load_lut(crtcID);
}
// update shared info
@ -816,8 +978,8 @@ display_crtc_set_dtd(uint8 crtcID, display_mode* mode)
{
display_timing& displayTiming = mode->timing;
TRACE("%s called to do %dx%d\n",
__func__, displayTiming.h_display, displayTiming.v_display);
TRACE("%s called to do %dx%d\n", __func__,
displayTiming.h_display, displayTiming.v_display);
SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
@ -825,6 +987,7 @@ display_crtc_set_dtd(uint8 crtcID, display_mode* mode)
memset(&args, 0, sizeof(args));
// Note: the code below assumes H & V borders are both zero
uint16 blankStart
= MIN(displayTiming.h_sync_start, displayTiming.h_display);
uint16 blankEnd

View File

@ -31,6 +31,8 @@ void display_crtc_set(uint8 crtcID, display_mode* mode);
void display_crtc_set_dtd(uint8 crtcID, display_mode* mode);
void display_crtc_power(uint8 crtcID, int command);
void display_crtc_memreq(uint8 crtcID, int command);
void display_avivo_crtc_load_lut(uint8 crtcID);
void display_dce45_crtc_load_lut(uint8 crtcID);
#endif /* RADEON_HD_DISPLAY_H */

View File

@ -15,6 +15,7 @@
#include "accelerant_protos.h"
#include "connector.h"
#include "mode.h"
#include "edid.h"
#undef TRACE
@ -341,8 +342,8 @@ dp_get_lane_count(uint32 connectorIndex, display_mode* mode)
size_t pixelChunk;
size_t pixelsPerChunk;
status_t result = dp_get_pixel_size_for((color_space)mode->space, &pixelChunk,
NULL, &pixelsPerChunk);
status_t result = dp_get_pixel_size_for((color_space)mode->space,
&pixelChunk, NULL, &pixelsPerChunk);
if (result != B_OK) {
TRACE("%s: Invalid color space!\n", __func__);
@ -355,7 +356,8 @@ dp_get_lane_count(uint32 connectorIndex, display_mode* mode)
uint32 dpMaxLaneCount = dp_get_lane_count_max(dpInfo);
uint32 lane;
for (lane = 1; lane < dpMaxLaneCount; lane <<= 1) {
// don't go below 2 lanes or display is jittery
for (lane = 2; lane < dpMaxLaneCount; lane <<= 1) {
uint32 maxPixelClock = dp_get_pixel_clock_max(dpMaxLinkRate, lane,
bitsPerPixel);
if (mode->timing.pixel_clock <= maxPixelClock)
@ -380,8 +382,8 @@ dp_get_link_rate(uint32 connectorIndex, display_mode* mode)
size_t pixelChunk;
size_t pixelsPerChunk;
status_t result = dp_get_pixel_size_for((color_space)mode->space, &pixelChunk,
NULL, &pixelsPerChunk);
status_t result = dp_get_pixel_size_for((color_space)mode->space,
&pixelChunk, NULL, &pixelsPerChunk);
if (result != B_OK) {
TRACE("%s: Invalid color space!\n", __func__);
@ -430,6 +432,8 @@ dp_setup_connectors()
continue;
}
TRACE("%s: found dp connector on index %" B_PRIu32 "\n",
__func__, index);
uint32 gpioID = gConnector[index]->gpioID;
uint32 auxPin = gGPIOInfo[gpioID]->hwPin;
@ -655,6 +659,7 @@ dp_link_train_cr(uint32 connectorIndex)
dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_1);
memset(dp->trainingSet, 0, 4);
dp_update_vs_emph(connectorIndex);
snooze(400);
while (1) {
if (dp->trainingReadInterval == 0)
@ -763,11 +768,13 @@ dp_link_train_ce(uint32 connectorIndex)
status_t
dp_link_train(uint32 connectorIndex, display_mode* mode)
dp_link_train(uint8 crtcID)
{
TRACE("%s\n", __func__);
uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
dp_info* dp = &gConnector[connectorIndex]->dpInfo;
display_mode* mode = &gDisplay[crtcID]->currentMode;
if (dp->valid != true) {
ERROR("%s: started on invalid DisplayPort connector #%" B_PRIu32 "\n",
@ -830,7 +837,10 @@ dp_link_train(uint32 connectorIndex, display_mode* mode)
encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
ATOM_ENCODER_CMD_SETUP_PANEL_MODE);
if (dp->config[0] >= DP_DPCD_REV_11)
// TODO: Doesn't this overwrite important dpcd info?
sandbox = dp->laneCount;
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);
@ -872,7 +882,7 @@ dp_link_train(uint32 connectorIndex, display_mode* mode)
}
status_t
bool
ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info* edid)
{
TRACE("%s\n", __func__);
@ -880,15 +890,16 @@ ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info* edid)
dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
if (!dpInfo->valid)
return B_ERROR;
edid1_raw raw;
uint8* rdata = (uint8_t*)&raw;
uint8 sdata = 0;
return false;
// The following sequence is from a trace of the Linux kernel
// radeon code; not sure if the initial writes to address 0 are
// requried.
// TODO: This surely cane be cleaned up
edid1_raw raw;
uint8* rdata = (uint8*)&raw;
uint8 sdata = 0;
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x00, &sdata, true, false);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x00, &sdata, false, true);
@ -902,25 +913,25 @@ ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info* edid)
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata, true, false);
for (uint32 i = 0; i < sizeof(raw); i++) {
status_t result = dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, rdata++,
false, false);
if (result) {
ERROR("%s: error reading EDID data at index %" B_PRIu32 "\n",
__func__, i);
status_t ret = dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50,
rdata++, false, false);
if (ret) {
TRACE("%s: error reading EDID data at index %d, ret = %d\n",
__func__, i, ret);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, true);
return B_ERROR;
return false;
}
}
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, true);
if (raw.version.version != 1 || raw.version.revision > 4) {
ERROR("%s: EDID version or revision out of range\n", __func__);
return B_ERROR;
return false;
}
edid_decode(edid, &raw);
return B_OK;
return true;
}

View File

@ -40,7 +40,7 @@ uint32 dp_get_lane_count(uint32 connectorIndex, display_mode* mode);
void dp_setup_connectors();
status_t dp_link_train(uint32 connectorIndex, display_mode* mode);
status_t dp_link_train(uint8 crtcID);
status_t dp_link_train_cr(uint32 connectorIndex);
status_t dp_link_train_ce(uint32 connectorIndex);
@ -48,7 +48,8 @@ void debug_dp_info();
status_t dp_get_pixel_size_for(color_space space, size_t *pixelChunk,
size_t *rowAlignment, size_t *pixelsPerChunk);
status_t ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info *edid);
bool ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info *edid);
#endif /* RADEON_HD_DISPLAYPORT_H */
#endif /* RADEON_HD_DISPLAYPORT_H */

View File

@ -294,7 +294,7 @@ encoder_mode_set(uint8 crtcID)
uint16 encoderFlags = gConnector[connectorIndex]->encoder.flags;
pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
// Adjusted pixel clock (*NOT* original mode pixel clock)
// TODO: Should this be the adjusted pll or the original?
uint32 pixelClock = pll->pixelClock;
switch (gConnector[connectorIndex]->encoder.objectID) {
@ -324,6 +324,9 @@ encoder_mode_set(uint8 crtcID)
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
// already handled by virue of setting DPMS_OFF before
// getting here
#if 0
if ((info.chipsetFlags & CHIP_APU) != 0
|| info.dceMajor >= 5) {
// Setup DIG encoder
@ -356,6 +359,7 @@ encoder_mode_set(uint8 crtcID)
transmitter_dig_setup(connectorIndex, pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_ENABLE);
}
#endif
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
@ -1828,8 +1832,17 @@ encoder_dpms_set_dig(uint8 crtcID, int mode)
transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_ENCODER_CMD_SETUP);
}
encoder_dig_setup(connectorIndex, pll->pixelClock, ATOM_ENABLE);
transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_SETUP);
transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_ENABLE);
/* some early dce3.2 boards have a bug in their transmitter
control table */
if (info.chipsetID != RADEON_RV710
&& info.chipsetID != RADEON_RV730)
transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT);
} else {
transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT);
@ -1845,12 +1858,15 @@ encoder_dpms_set_dig(uint8 crtcID, int mode)
encoder_dig_setup(connectorIndex, pll->pixelClock,
ATOM_ENCODER_CMD_DP_VIDEO_OFF);
}
// TODO: dp link train here
//radeon_dp_link_train(encoder, connector);
// dp link train
dp_link_train(crtcID);
if (info.dceMajor >= 4) {
encoder_dig_setup(connectorIndex, pll->pixelClock,
ATOM_ENCODER_CMD_DP_VIDEO_ON);
}
// not sure what AtomBIOS table/command sets this
// register, but it's required to get the video output
Write32(OUT, AVIVO_DP_VID_STREAM_CNTL, 0x201);
}
if ((encoderFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
transmitter_dig_setup(connectorIndex, pll->pixelClock,
@ -1866,6 +1882,9 @@ encoder_dpms_set_dig(uint8 crtcID, int mode)
} else {
transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT);
transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_DISABLE);
encoder_dig_setup(connectorIndex, pll->pixelClock, ATOM_DISABLE);
}
if (connector_is_dp(connectorIndex)) {
if (info.dceMajor >= 4) {

View File

@ -39,7 +39,7 @@ get_accelerant_hook(uint32 feature, void* data)
case B_DPMS_MODE:
return (void*)radeon_dpms_mode;
case B_SET_DPMS_MODE:
return (void*)radeon_dpms_set;
return (void*)radeon_dpms_set_hook;
/* mode configuration */
case B_ACCELERANT_MODE_COUNT:

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006-2011, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2013, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Support for i915 chipset and up based on the X driver,
@ -69,6 +69,7 @@ uint32
radeon_accelerant_mode_count(void)
{
TRACE("%s\n", __func__);
// TODO: multi-monitor? we need crtcid here
return gInfo->shared_info->mode_count;
}
@ -78,6 +79,7 @@ status_t
radeon_get_mode_list(display_mode* modeList)
{
TRACE("%s\n", __func__);
// TODO: multi-monitor? we need crtcid here
memcpy(modeList, gInfo->mode_list,
gInfo->shared_info->mode_count * sizeof(display_mode));
return B_OK;
@ -88,8 +90,8 @@ status_t
radeon_get_preferred_mode(display_mode* preferredMode)
{
TRACE("%s\n", __func__);
// TODO: multi-monitor? we need crtcid here
// TODO: Argh! Which display? :)
uint8_t crtc = 0;
if (gDisplay[crtc]->preferredMode.virtual_width > 0
@ -119,7 +121,7 @@ radeon_get_edid_info(void* info, size_t size, uint32* edid_version)
memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
// VESA
//memcpy(info, &gDisplay[0]->edidData, sizeof(struct edid1_info));
// BitBanged display 0
// Display 0
*edid_version = EDID_VERSION_1;
@ -145,27 +147,46 @@ radeon_dpms_mode(void)
void
radeon_dpms_set(int mode)
radeon_dpms_set(uint8 id, int mode)
{
for (uint8 id = 0; id < MAX_DISPLAY; id++) {
if (mode == B_DPMS_ON) {
display_crtc_dpms(id, mode);
encoder_dpms_set(id, mode);
} else {
encoder_dpms_set(id, mode);
display_crtc_dpms(id, mode);
}
gInfo->dpms_mode = mode;
}
void
radeon_dpms_set_hook(int mode)
{
// TODO: multi-monitor? for now we use VESA edid
// As the accelerant hook doesn't pass crtc id
for (uint8 id = 0; id < MAX_DISPLAY; id++) {
radeon_dpms_set(id, mode);
}
}
status_t
radeon_set_display_mode(display_mode* mode)
{
radeon_shared_info &info = *gInfo->shared_info;
// 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
// Set mode on each display
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
memcpy(&gDisplay[id]->currentMode, mode, sizeof(display_mode));
uint32 connectorIndex = gDisplay[id]->connectorIndex;
// Determine DP lanes if DP
@ -177,9 +198,8 @@ radeon_set_display_mode(display_mode* mode)
// *** crtc and encoder prep
encoder_output_lock(true);
encoder_dpms_set(id, B_DPMS_OFF);
display_crtc_lock(id, ATOM_ENABLE);
display_crtc_dpms(id, B_DPMS_OFF);
radeon_dpms_set(id, B_DPMS_OFF);
// *** Set up encoder -> crtc routing
encoder_assign_crtc(id);
@ -201,31 +221,15 @@ radeon_set_display_mode(display_mode* mode)
// *** encoder mode set
encoder_mode_set(id);
// *** CRT controler commit
display_crtc_dpms(id, B_DPMS_ON);
// *** encoder and CRT controller commit
radeon_dpms_set(id, B_DPMS_ON);
display_crtc_lock(id, ATOM_DISABLE);
// *** encoder commit
// handle DisplayPort link training
if (connector_is_dp(connectorIndex)) {
if (info.dceMajor >= 4)
encoder_dig_setup(connectorIndex,
ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
dp_link_train(connectorIndex, mode);
if (info.dceMajor >= 4)
encoder_dig_setup(connectorIndex,
ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
}
encoder_dpms_set(id, B_DPMS_ON);
encoder_output_lock(false);
}
#ifdef TRACE_MODE
// for debugging
// debug_dp_info();
debug_dp_info();
TRACE("D1CRTC_STATUS Value: 0x%X\n",
Read32(CRT, AVIVO_D1CRTC_STATUS));
@ -247,6 +251,7 @@ radeon_set_display_mode(display_mode* mode)
Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n",
Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
#endif
return B_OK;
}
@ -258,6 +263,7 @@ radeon_get_display_mode(display_mode* _currentMode)
TRACE("%s\n", __func__);
*_currentMode = gInfo->shared_info->current_mode;
//*_currentMode = gDisplay[X]->currentMode;
return B_OK;
}

View File

@ -32,7 +32,8 @@ bool is_mode_supported(display_mode* mode);
status_t is_mode_sane(display_mode* mode);
uint32 radeon_dpms_capabilities(void);
uint32 radeon_dpms_mode(void);
void radeon_dpms_set(int mode);
void radeon_dpms_set(uint8 id, int mode);
void radeon_dpms_set_hook(int mode);
uint32 get_mode_bpp(display_mode* mode);

View File

@ -301,7 +301,7 @@ pll_compute_post_divider(pll_info* pll)
if ((pll->flags & PLL_IS_LCD) != 0)
vco = pll->lcdPllOutMin;
else
vco = pll->pllOutMin;
vco = pll->pllOutMax;
} else {
if ((pll->flags & PLL_IS_LCD) != 0)
vco = pll->lcdPllOutMax;
@ -311,8 +311,8 @@ pll_compute_post_divider(pll_info* pll)
TRACE("%s: vco = %" B_PRIu32 "\n", __func__, vco);
uint32 postDivider = vco / pll->pixelClock;
uint32 tmp = vco % pll->pixelClock;
uint32 postDivider = vco / pll->adjustedClock;
uint32 tmp = vco % pll->adjustedClock;
if ((pll->flags & PLL_PREFER_MINM_OVER_MAXP) != 0) {
if (tmp)
@ -337,7 +337,7 @@ pll_compute(pll_info* pll)
{
pll_compute_post_divider(pll);
uint32 targetClock = pll->pixelClock;
uint32 targetClock = pll->adjustedClock;
pll->feedbackDiv = 0;
pll->feedbackDivFrac = 0;
@ -364,7 +364,7 @@ pll_compute(pll_info* pll)
pll->feedbackDiv = pll->minFeedbackDiv;
pll->feedbackDivFrac
= (100 * pll->feedbackDivFrac) / pll->referenceFreq;
= (1000 * pll->feedbackDivFrac) / pll->referenceFreq;
if (pll->feedbackDivFrac >= 5) {
pll->feedbackDivFrac -= 5;
@ -436,12 +436,12 @@ pll_compute(pll_info* pll)
TRACE("%s: pixel clock: %" B_PRIu32 " gives:"
" feedbackDivider = %" B_PRIu32 ".%" B_PRIu32
"; referenceDivider = %" B_PRIu32 "; postDivider = %" B_PRIu32 "\n",
__func__, pll->pixelClock, pll->feedbackDiv, pll->feedbackDivFrac,
__func__, pll->adjustedClock, pll->feedbackDiv, pll->feedbackDivFrac,
pll->referenceDiv, pll->postDiv);
if (pll->pixelClock != calculatedClock) {
if (pll->adjustedClock != calculatedClock) {
TRACE("%s: pixel clock %" B_PRIu32 " was changed to %" B_PRIu32 "\n",
__func__, pll->pixelClock, calculatedClock);
__func__, pll->adjustedClock, calculatedClock);
pll->pixelClock = calculatedClock;
}
@ -515,6 +515,7 @@ pll_adjust(pll_info* pll, display_mode* mode, uint8 crtcID)
uint32 encoderFlags = connector->encoder.flags;
uint32 externalEncoderID = 0;
pll->adjustedClock = pll->pixelClock;
if (connector->encoderExternal.isDPBridge)
externalEncoderID = connector->encoderExternal.objectID;
@ -557,9 +558,9 @@ pll_adjust(pll_info* pll, display_mode* mode, uint8 crtcID)
atom_execute_table(gAtomContext, index, (uint32*)&args);
// get returned adjusted clock
pll->pixelClock
pll->adjustedClock
= B_LENDIAN_TO_HOST_INT16(args.v1.usPixelClock);
pll->pixelClock *= 10;
pll->adjustedClock *= 10;
break;
case 3:
args.v3.sInput.usPixelClock
@ -607,10 +608,10 @@ pll_adjust(pll_info* pll, display_mode* mode, uint8 crtcID)
atom_execute_table(gAtomContext, index, (uint32*)&args);
// get returned adjusted clock
pll->pixelClock
pll->adjustedClock
= B_LENDIAN_TO_HOST_INT32(
args.v3.sOutput.ulDispPllFreq);
pll->pixelClock *= 10;
pll->adjustedClock *= 10;
// convert to kHz for storage
if (args.v3.sOutput.ucRefDiv) {
@ -638,7 +639,7 @@ pll_adjust(pll_info* pll, display_mode* mode, uint8 crtcID)
}
TRACE("%s: was: %" B_PRIu32 ", now: %" B_PRIu32 "\n", __func__,
pixelClock, pll->pixelClock);
pixelClock, pll->adjustedClock);
return B_OK;
}
@ -649,6 +650,8 @@ pll_set(display_mode* mode, uint8 crtcID)
{
uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
uint32 dp_clock = gConnector[connectorIndex]->dpInfo.linkRate / 10;
bool ssEnabled = false;
pll->pixelClock = mode->timing.pixel_clock;
@ -668,23 +671,28 @@ pll_set(display_mode* mode, uint8 crtcID)
if (info.dceMajor >= 4)
pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_DP);
else {
// TODO: DP Clock == 1.62Ghz?
pll_ppll_ss_probe(pll, ATOM_DP_SS_ID1);
if (dp_clock == 16200) {
ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID2);
if (!ssEnabled)
// id2 failed, try id1
ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID1);
} else
ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID1);
}
break;
case ATOM_ENCODER_MODE_LVDS:
if (info.dceMajor >= 4)
pll_asic_ss_probe(pll, gInfo->lvdsSpreadSpectrumID);
ssEnabled = pll_asic_ss_probe(pll, gInfo->lvdsSpreadSpectrumID);
else
pll_ppll_ss_probe(pll, gInfo->lvdsSpreadSpectrumID);
ssEnabled = pll_ppll_ss_probe(pll, gInfo->lvdsSpreadSpectrumID);
break;
case ATOM_ENCODER_MODE_DVI:
if (info.dceMajor >= 4)
pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_TMDS);
ssEnabled = pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_TMDS);
break;
case ATOM_ENCODER_MODE_HDMI:
if (info.dceMajor >= 4)
pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_HDMI);
ssEnabled = pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_HDMI);
break;
}
@ -836,7 +844,8 @@ pll_set(display_mode* mode, uint8 crtcID)
status_t result = atom_execute_table(gAtomContext, index, (uint32*)&args);
display_crtc_ss(pll, ATOM_ENABLE);
if (ssEnabled)
display_crtc_ss(pll, ATOM_ENABLE);
return result;
}

View File

@ -93,6 +93,9 @@ struct pll_info {
/* asic spread spectrum */
uint16 ssRate;
uint16 ssAmount;
/* pixel clock to be used in pll calculations (kHz) */
uint32 adjustedClock;
};