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; uint32 hfreqMin;
edid1_info edidData; edid1_info edidData;
display_mode preferredMode; display_mode preferredMode;
display_mode currentMode;
} display_info; } display_info;

View File

@ -3,7 +3,8 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * 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 status_t
detect_displays() detect_displays()
{ {
@ -264,19 +288,18 @@ detect_displays()
} }
if (gConnector[id]->type == VIDEO_CONNECTOR_DP) { if (gConnector[id]->type == VIDEO_CONNECTOR_DP) {
edid1_info* edid = &gDisplay[displayIndex]->edidData;
TRACE("%s: connector(%" B_PRIu32 "): Checking DP.\n", __func__, id); 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 gDisplay[displayIndex]->attached
= (dpHasEDID == B_OK ? true : false); = ddc2_dp_read_edid1(id, edid);
if (gDisplay[displayIndex]->attached) { if (gDisplay[displayIndex]->attached) {
TRACE("%s: connector(%" B_PRIu32 "): Found DisplayPort EDID!\n", TRACE("%s: connector(%" B_PRIu32 "): Found DisplayPort EDID!\n",
__func__); __func__);
} }
} }
// TODO: Handle external DP brides - ??
// TODO: As DP aux transactions don't work yet, just use LVDS as a hack
#if 0 #if 0
if (gConnector[id]->encoderExternal.isDPBridge == true) { if (gConnector[id]->encoderExternal.isDPBridge == true) {
// If this is a DisplayPort Bridge, setup ddc on bus // If this is a DisplayPort Bridge, setup ddc on bus
@ -287,11 +310,9 @@ detect_displays()
gDisplay[displayIndex]->attached = true; gDisplay[displayIndex]->attached = true;
// TODO: DDC Router switching for DisplayPort (and others?) // TODO: DDC Router switching for DisplayPort (and others?)
} else if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) { }
#endif #endif
if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
if (gDisplay[displayIndex]->attached == false
&& gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
// If plain (non-DP) laptop LVDS, read mode info from AtomBIOS // If plain (non-DP) laptop LVDS, read mode info from AtomBIOS
//TRACE("%s: non-DP laptop LVDS detected\n", __func__); //TRACE("%s: non-DP laptop LVDS detected\n", __func__);
gDisplay[displayIndex]->attached = connector_read_mode_lvds(id, 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 // 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 // edid channel, we have to make *sure* the edid data received is
// valid for te connector. // valid for the connector.
// Found EDID data? // Found EDID data?
if (gDisplay[displayIndex]->attached) { if (gDisplay[displayIndex]->attached) {
@ -331,6 +352,7 @@ detect_displays()
"and a analog encoder.\n", __func__, id); "and a analog encoder.\n", __func__, id);
gDisplay[displayIndex]->attached gDisplay[displayIndex]->attached
= encoder_analog_load_detect(id); = encoder_analog_load_detect(id);
remove_dup_displays(displayIndex, id);
} else if (edid->display.input_type && !analogEncoder) { } else if (edid->display.input_type && !analogEncoder) {
// If EDID is digital, we make an assumption here. // If EDID is digital, we make an assumption here.
TRACE("%s: connector(%" B_PRIu32 "): has digital EDID " TRACE("%s: connector(%" B_PRIu32 "): has digital EDID "
@ -339,9 +361,16 @@ detect_displays()
// This generally means the monitor is of poor design // This generally means the monitor is of poor design
// Since we *know* there is no load on the analog encoder // Since we *know* there is no load on the analog encoder
// we assume that it is a digital display. // 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 " TRACE("%s: connector(%" B_PRIu32 "): Warning: monitor has "
"false digital EDID flag + unloaded analog encoder!\n", "false digital EDID flag + unloaded analog encoder!\n",
__func__, id); __func__, id);
gDisplay[displayIndex]->attached = false;
} }
} }
} }
@ -558,7 +587,6 @@ display_crtc_scale(uint8 crtcID, display_mode* mode)
void void
display_crtc_dpms(uint8 crtcID, int mode) display_crtc_dpms(uint8 crtcID, int mode)
{ {
radeon_shared_info &info = *gInfo->shared_info; radeon_shared_info &info = *gInfo->shared_info;
switch (mode) { switch (mode) {
@ -566,8 +594,8 @@ display_crtc_dpms(uint8 crtcID, int mode)
TRACE("%s: crtc %" B_PRIu8 " dpms powerup\n", __func__, crtcID); TRACE("%s: crtc %" B_PRIu8 " dpms powerup\n", __func__, crtcID);
if (gDisplay[crtcID]->attached == false) if (gDisplay[crtcID]->attached == false)
return; return;
gDisplay[crtcID]->powered = true;
display_crtc_power(crtcID, ATOM_ENABLE); display_crtc_power(crtcID, ATOM_ENABLE);
gDisplay[crtcID]->powered = true;
if (info.dceMajor >= 3) if (info.dceMajor >= 3)
display_crtc_memreq(crtcID, ATOM_ENABLE); display_crtc_memreq(crtcID, ATOM_ENABLE);
display_crtc_blank(crtcID, ATOM_BLANKING_OFF); 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 void
display_crtc_fb_set(uint8 crtcID, display_mode* mode) display_crtc_fb_set(uint8 crtcID, display_mode* mode)
{ {
radeon_shared_info &info = *gInfo->shared_info; radeon_shared_info &info = *gInfo->shared_info;
register_info* regs = gDisplay[crtcID]->regs; register_info* regs = gDisplay[crtcID]->regs;
uint16* r = info.color_data;
uint16* g = r + 256;
uint16* b = r + 512;
uint32 fbSwap; uint32 fbSwap;
if (info.dceMajor >= 4) if (info.dceMajor >= 4)
fbSwap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 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 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_8BPP
| AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; | AVIVO_D1GRPH_CONTROL_8BPP_INDEXED;
} }
// TODO: copy system color map into shared info
break; break;
case B_RGB15_LITTLE: case B_RGB15_LITTLE:
bytesPerPixel = 2; bytesPerPixel = 2;
@ -646,6 +784,17 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
fbSwap = R600_D1GRPH_SWAP_ENDIAN_16BIT; fbSwap = R600_D1GRPH_SWAP_ENDIAN_16BIT;
#endif #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; break;
case B_RGB24_LITTLE: case B_RGB24_LITTLE:
case B_RGB32_LITTLE: case B_RGB32_LITTLE:
@ -666,6 +815,17 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
fbSwap = R600_D1GRPH_SWAP_ENDIAN_32BIT; fbSwap = R600_D1GRPH_SWAP_ENDIAN_32BIT;
#endif #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; break;
} }
@ -685,7 +845,7 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
(fbAddress >> 32) & 0xf); (fbAddress >> 32) & 0xf);
} }
TRACE("%s: Set SurfaceAddress: 0x%" B_PRIX32 "\n", TRACE("%s: Set SurfaceAddress: 0x%" B_PRIX64 "\n",
__func__, (fbAddress & 0xFFFFFFFF)); __func__, (fbAddress & 0xFFFFFFFF));
Write32(OUT, regs->grphPrimarySurfaceAddr, (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 widthAligned = mode->virtual_width;
uint32 pitchMask = 0; uint32 pitchMask = 0;
// assume micro-linear/macro-linear mode (i.e., not tiled)
switch (bytesPerPixel) { switch (bytesPerPixel) {
case 1: case 1:
pitchMask = 255; pitchMask = 63;
break; break;
case 2: case 2:
pitchMask = 127; pitchMask = 31;
break; break;
case 3: case 3:
case 4: case 4:
pitchMask = 63; pitchMask = 31;
break; break;
} }
widthAligned += pitchMask; 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__, TRACE("%s: fb: %" B_PRIu32 "x%" B_PRIu32 " (%" B_PRIu32 " bpp)\n", __func__,
mode->virtual_width, mode->virtual_height, bitsPerPixel); mode->virtual_width, mode->virtual_height, bitsPerPixel);
TRACE("%s: fb pitch: %" B_PRIu32 " \n", __func__, TRACE("%s: fb pitch: %" B_PRIu32 " \n", __func__,
widthAligned * bytesPerPixel / 4); widthAligned);
TRACE("%s: fb width aligned: %" B_PRIu32 "\n", __func__, TRACE("%s: fb width aligned: %" B_PRIu32 "\n", __func__,
widthAligned); widthAligned);
@ -728,7 +889,7 @@ display_crtc_fb_set(uint8 crtcID, display_mode* mode)
Write32(CRT, regs->grphYStart, 0); Write32(CRT, regs->grphYStart, 0);
Write32(CRT, regs->grphXEnd, mode->virtual_width); Write32(CRT, regs->grphXEnd, mode->virtual_width);
Write32(CRT, regs->grphYEnd, mode->virtual_height); Write32(CRT, regs->grphYEnd, mode->virtual_height);
Write32(CRT, regs->grphPitch, widthAligned * bytesPerPixel / 4); Write32(CRT, regs->grphPitch, widthAligned);
Write32(CRT, regs->grphEnable, 1); Write32(CRT, regs->grphEnable, 1);
// Enable Frame buffer // 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); Write32(OUT, EVERGREEN_MASTER_UPDATE_MODE + regs->crtcOffset, 0);
// Pageflip to happen anywhere in vblank // Pageflip to happen anywhere in vblank
display_dce45_crtc_load_lut(crtcID);
} else { } else {
uint32 tmp = Read32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset); uint32 tmp = Read32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset);
tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; 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); Write32(OUT, AVIVO_D1MODE_MASTER_UPDATE_MODE + regs->crtcOffset, 0);
// Pageflip to happen anywhere in vblank // Pageflip to happen anywhere in vblank
display_avivo_crtc_load_lut(crtcID);
} }
// update shared info // update shared info
@ -816,8 +978,8 @@ display_crtc_set_dtd(uint8 crtcID, display_mode* mode)
{ {
display_timing& displayTiming = mode->timing; display_timing& displayTiming = mode->timing;
TRACE("%s called to do %dx%d\n", TRACE("%s called to do %dx%d\n", __func__,
__func__, displayTiming.h_display, displayTiming.v_display); displayTiming.h_display, displayTiming.v_display);
SET_CRTC_USING_DTD_TIMING_PARAMETERS args; SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
@ -825,6 +987,7 @@ display_crtc_set_dtd(uint8 crtcID, display_mode* mode)
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
// Note: the code below assumes H & V borders are both zero
uint16 blankStart uint16 blankStart
= MIN(displayTiming.h_sync_start, displayTiming.h_display); = MIN(displayTiming.h_sync_start, displayTiming.h_display);
uint16 blankEnd 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_set_dtd(uint8 crtcID, display_mode* mode);
void display_crtc_power(uint8 crtcID, int command); void display_crtc_power(uint8 crtcID, int command);
void display_crtc_memreq(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 */ #endif /* RADEON_HD_DISPLAY_H */

View File

@ -15,6 +15,7 @@
#include "accelerant_protos.h" #include "accelerant_protos.h"
#include "connector.h" #include "connector.h"
#include "mode.h" #include "mode.h"
#include "edid.h"
#undef TRACE #undef TRACE
@ -341,8 +342,8 @@ dp_get_lane_count(uint32 connectorIndex, display_mode* mode)
size_t pixelChunk; size_t pixelChunk;
size_t pixelsPerChunk; size_t pixelsPerChunk;
status_t result = dp_get_pixel_size_for((color_space)mode->space, &pixelChunk, status_t result = dp_get_pixel_size_for((color_space)mode->space,
NULL, &pixelsPerChunk); &pixelChunk, NULL, &pixelsPerChunk);
if (result != B_OK) { if (result != B_OK) {
TRACE("%s: Invalid color space!\n", __func__); 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 dpMaxLaneCount = dp_get_lane_count_max(dpInfo);
uint32 lane; 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, uint32 maxPixelClock = dp_get_pixel_clock_max(dpMaxLinkRate, lane,
bitsPerPixel); bitsPerPixel);
if (mode->timing.pixel_clock <= maxPixelClock) if (mode->timing.pixel_clock <= maxPixelClock)
@ -380,8 +382,8 @@ dp_get_link_rate(uint32 connectorIndex, display_mode* mode)
size_t pixelChunk; size_t pixelChunk;
size_t pixelsPerChunk; size_t pixelsPerChunk;
status_t result = dp_get_pixel_size_for((color_space)mode->space, &pixelChunk, status_t result = dp_get_pixel_size_for((color_space)mode->space,
NULL, &pixelsPerChunk); &pixelChunk, NULL, &pixelsPerChunk);
if (result != B_OK) { if (result != B_OK) {
TRACE("%s: Invalid color space!\n", __func__); TRACE("%s: Invalid color space!\n", __func__);
@ -430,6 +432,8 @@ dp_setup_connectors()
continue; continue;
} }
TRACE("%s: found dp connector on index %" B_PRIu32 "\n",
__func__, index);
uint32 gpioID = gConnector[index]->gpioID; uint32 gpioID = gConnector[index]->gpioID;
uint32 auxPin = gGPIOInfo[gpioID]->hwPin; uint32 auxPin = gGPIOInfo[gpioID]->hwPin;
@ -655,6 +659,7 @@ dp_link_train_cr(uint32 connectorIndex)
dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_1); dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_1);
memset(dp->trainingSet, 0, 4); memset(dp->trainingSet, 0, 4);
dp_update_vs_emph(connectorIndex); dp_update_vs_emph(connectorIndex);
snooze(400);
while (1) { while (1) {
if (dp->trainingReadInterval == 0) if (dp->trainingReadInterval == 0)
@ -763,11 +768,13 @@ dp_link_train_ce(uint32 connectorIndex)
status_t status_t
dp_link_train(uint32 connectorIndex, display_mode* mode) dp_link_train(uint8 crtcID)
{ {
TRACE("%s\n", __func__); TRACE("%s\n", __func__);
uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
dp_info* dp = &gConnector[connectorIndex]->dpInfo; dp_info* dp = &gConnector[connectorIndex]->dpInfo;
display_mode* mode = &gDisplay[crtcID]->currentMode;
if (dp->valid != true) { if (dp->valid != true) {
ERROR("%s: started on invalid DisplayPort connector #%" B_PRIu32 "\n", 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, encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
ATOM_ENCODER_CMD_SETUP_PANEL_MODE); 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; sandbox |= DP_ENHANCED_FRAME_EN;
dpcd_reg_write(hwPin, DP_LANE_COUNT, sandbox); 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) ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info* edid)
{ {
TRACE("%s\n", __func__); TRACE("%s\n", __func__);
@ -880,15 +890,16 @@ ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info* edid)
dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo; dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
if (!dpInfo->valid) if (!dpInfo->valid)
return B_ERROR; return false;
edid1_raw raw;
uint8* rdata = (uint8_t*)&raw;
uint8 sdata = 0;
// The following sequence is from a trace of the Linux kernel // The following sequence is from a trace of the Linux kernel
// 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
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, true, false);
dp_aux_set_i2c_byte(dpInfo->auxPin, 0x00, &sdata, false, true); 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); dp_aux_get_i2c_byte(dpInfo->auxPin, 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, rdata++, status_t ret = dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50,
false, false); rdata++, false, false);
if (result) { if (ret) {
ERROR("%s: error reading EDID data at index %" B_PRIu32 "\n", TRACE("%s: error reading EDID data at index %d, ret = %d\n",
__func__, i); __func__, i, ret);
dp_aux_get_i2c_byte(dpInfo->auxPin, 0x50, &sdata, false, true); 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); dp_aux_get_i2c_byte(dpInfo->auxPin, 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__);
return B_ERROR; return false;
} }
edid_decode(edid, &raw); 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(); 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_cr(uint32 connectorIndex);
status_t dp_link_train_ce(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, status_t dp_get_pixel_size_for(color_space space, size_t *pixelChunk,
size_t *rowAlignment, size_t *pixelsPerChunk); 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; uint16 encoderFlags = gConnector[connectorIndex]->encoder.flags;
pll_info* pll = &gConnector[connectorIndex]->encoder.pll; 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; uint32 pixelClock = pll->pixelClock;
switch (gConnector[connectorIndex]->encoder.objectID) { 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_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: 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 if ((info.chipsetFlags & CHIP_APU) != 0
|| info.dceMajor >= 5) { || info.dceMajor >= 5) {
// Setup DIG encoder // Setup DIG encoder
@ -356,6 +359,7 @@ encoder_mode_set(uint8 crtcID)
transmitter_dig_setup(connectorIndex, pixelClock, 0, 0, transmitter_dig_setup(connectorIndex, pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_ENABLE); ATOM_TRANSMITTER_ACTION_ENABLE);
} }
#endif
break; break;
case ENCODER_OBJECT_ID_INTERNAL_DDI: case ENCODER_OBJECT_ID_INTERNAL_DDI:
case ENCODER_OBJECT_ID_INTERNAL_DVO1: 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, transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_ENCODER_CMD_SETUP); 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, transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_ENABLE); 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 { } else {
transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0, transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT); ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT);
@ -1845,12 +1858,15 @@ encoder_dpms_set_dig(uint8 crtcID, int mode)
encoder_dig_setup(connectorIndex, pll->pixelClock, encoder_dig_setup(connectorIndex, pll->pixelClock,
ATOM_ENCODER_CMD_DP_VIDEO_OFF); ATOM_ENCODER_CMD_DP_VIDEO_OFF);
} }
// TODO: dp link train here // dp link train
//radeon_dp_link_train(encoder, connector); dp_link_train(crtcID);
if (info.dceMajor >= 4) { if (info.dceMajor >= 4) {
encoder_dig_setup(connectorIndex, pll->pixelClock, encoder_dig_setup(connectorIndex, pll->pixelClock,
ATOM_ENCODER_CMD_DP_VIDEO_ON); 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) { if ((encoderFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
transmitter_dig_setup(connectorIndex, pll->pixelClock, transmitter_dig_setup(connectorIndex, pll->pixelClock,
@ -1866,6 +1882,9 @@ encoder_dpms_set_dig(uint8 crtcID, int mode)
} else { } else {
transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0, transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT); 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 (connector_is_dp(connectorIndex)) {
if (info.dceMajor >= 4) { if (info.dceMajor >= 4) {

View File

@ -39,7 +39,7 @@ get_accelerant_hook(uint32 feature, void* data)
case B_DPMS_MODE: case B_DPMS_MODE:
return (void*)radeon_dpms_mode; return (void*)radeon_dpms_mode;
case B_SET_DPMS_MODE: case B_SET_DPMS_MODE:
return (void*)radeon_dpms_set; return (void*)radeon_dpms_set_hook;
/* mode configuration */ /* mode configuration */
case B_ACCELERANT_MODE_COUNT: 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. * Distributed under the terms of the MIT License.
* *
* Support for i915 chipset and up based on the X driver, * Support for i915 chipset and up based on the X driver,
@ -69,6 +69,7 @@ uint32
radeon_accelerant_mode_count(void) radeon_accelerant_mode_count(void)
{ {
TRACE("%s\n", __func__); TRACE("%s\n", __func__);
// TODO: multi-monitor? we need crtcid here
return gInfo->shared_info->mode_count; return gInfo->shared_info->mode_count;
} }
@ -78,6 +79,7 @@ status_t
radeon_get_mode_list(display_mode* modeList) radeon_get_mode_list(display_mode* modeList)
{ {
TRACE("%s\n", __func__); TRACE("%s\n", __func__);
// TODO: multi-monitor? we need crtcid here
memcpy(modeList, gInfo->mode_list, memcpy(modeList, gInfo->mode_list,
gInfo->shared_info->mode_count * sizeof(display_mode)); gInfo->shared_info->mode_count * sizeof(display_mode));
return B_OK; return B_OK;
@ -88,8 +90,8 @@ status_t
radeon_get_preferred_mode(display_mode* preferredMode) radeon_get_preferred_mode(display_mode* preferredMode)
{ {
TRACE("%s\n", __func__); TRACE("%s\n", __func__);
// TODO: multi-monitor? we need crtcid here
// TODO: Argh! Which display? :)
uint8_t crtc = 0; uint8_t crtc = 0;
if (gDisplay[crtc]->preferredMode.virtual_width > 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)); memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
// VESA // VESA
//memcpy(info, &gDisplay[0]->edidData, sizeof(struct edid1_info)); //memcpy(info, &gDisplay[0]->edidData, sizeof(struct edid1_info));
// BitBanged display 0 // Display 0
*edid_version = EDID_VERSION_1; *edid_version = EDID_VERSION_1;
@ -145,27 +147,46 @@ radeon_dpms_mode(void)
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); encoder_dpms_set(id, mode);
display_crtc_dpms(id, mode); display_crtc_dpms(id, mode);
} }
gInfo->dpms_mode = 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 status_t
radeon_set_display_mode(display_mode* mode) 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 // Set mode on each display
for (uint8 id = 0; id < MAX_DISPLAY; id++) { for (uint8 id = 0; id < MAX_DISPLAY; id++) {
if (gDisplay[id]->attached == false) if (gDisplay[id]->attached == false)
continue; 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; uint32 connectorIndex = gDisplay[id]->connectorIndex;
// Determine DP lanes if DP // Determine DP lanes if DP
@ -177,9 +198,8 @@ radeon_set_display_mode(display_mode* mode)
// *** crtc and encoder prep // *** crtc and encoder prep
encoder_output_lock(true); encoder_output_lock(true);
encoder_dpms_set(id, B_DPMS_OFF);
display_crtc_lock(id, ATOM_ENABLE); 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 // *** Set up encoder -> crtc routing
encoder_assign_crtc(id); encoder_assign_crtc(id);
@ -201,31 +221,15 @@ radeon_set_display_mode(display_mode* mode)
// *** encoder mode set // *** encoder mode set
encoder_mode_set(id); encoder_mode_set(id);
// *** CRT controler commit // *** encoder and CRT controller commit
display_crtc_dpms(id, B_DPMS_ON); radeon_dpms_set(id, B_DPMS_ON);
display_crtc_lock(id, ATOM_DISABLE); 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); encoder_output_lock(false);
} }
#ifdef TRACE_MODE
// for debugging // for debugging
// debug_dp_info(); debug_dp_info();
TRACE("D1CRTC_STATUS Value: 0x%X\n", TRACE("D1CRTC_STATUS Value: 0x%X\n",
Read32(CRT, AVIVO_D1CRTC_STATUS)); Read32(CRT, AVIVO_D1CRTC_STATUS));
@ -247,6 +251,7 @@ radeon_set_display_mode(display_mode* mode)
Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n", TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n",
Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
#endif
return B_OK; return B_OK;
} }
@ -258,6 +263,7 @@ radeon_get_display_mode(display_mode* _currentMode)
TRACE("%s\n", __func__); TRACE("%s\n", __func__);
*_currentMode = gInfo->shared_info->current_mode; *_currentMode = gInfo->shared_info->current_mode;
//*_currentMode = gDisplay[X]->currentMode;
return B_OK; return B_OK;
} }

View File

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

View File

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