radeon_hd: clean up clock units

* Ensure we store all clock units as khz or
  n * 10 off from AtomBIOS unit expected
* Perform DDC setup of external encoder
This commit is contained in:
Alexander von Gluck IV
2013-12-30 19:09:53 -06:00
parent 5ed8c605ef
commit 224b875b3a
5 changed files with 52 additions and 37 deletions
@@ -72,7 +72,7 @@ struct accelerant_info {
volatile uint32 dpms_mode; // current driver dpms mode volatile uint32 dpms_mode; // current driver dpms mode
uint16 maximumPixelClock; uint32 maximumPixelClock;
uint32 displayClockFrequency; uint32 displayClockFrequency;
uint32 dpExternalClock; uint32 dpExternalClock;
@@ -138,7 +138,7 @@ struct encoder_info {
bool valid; bool valid;
uint16 objectID; uint16 objectID;
uint32 type; uint32 type;
uint16 capabilities; uint32 capabilities;
uint32 linkEnumeration; // ex. linkb == GRAPH_OBJECT_ENUM_ID2 uint32 linkEnumeration; // ex. linkb == GRAPH_OBJECT_ENUM_ID2
bool isExternal; bool isExternal;
bool isDPBridge; bool isDPBridge;
+10 -13
View File
@@ -267,29 +267,26 @@ detect_displays()
if (gConnector[id]->type == VIDEO_CONNECTOR_DP) { if (gConnector[id]->type == VIDEO_CONNECTOR_DP) {
TRACE("%s: connector(%" B_PRIu32 "): Checking DP.\n", __func__, id); TRACE("%s: connector(%" B_PRIu32 "): Checking DP.\n", __func__, id);
if (gConnector[id]->encoderExternal.valid == true) {
// If this has a valid external encoder (dp bridge)
// normally TRAVIS (LVDS) or NUTMEG (VGA)
TRACE("%s: external encoder, performing bridge DDC setup\n",
__func__);
encoder_external_setup(id,
EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
}
edid1_info* edid = &gDisplay[displayIndex]->edidData; edid1_info* edid = &gDisplay[displayIndex]->edidData;
gDisplay[displayIndex]->attached gDisplay[displayIndex]->attached
= ddc2_dp_read_edid1(id, edid); = ddc2_dp_read_edid1(id, edid);
// TODO: DDC Router switching for DisplayPort (and others?)
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 - ??
#if 0
if (gConnector[id]->encoderExternal.isDPBridge == true) {
// If this is a DisplayPort Bridge, setup ddc on bus
// TRAVIS (LVDS) or NUTMEG (VGA)
TRACE("%s: is bridge, performing bridge DDC setup\n", __func__);
encoder_external_setup(id, 23860,
EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
gDisplay[displayIndex]->attached = true;
// TODO: DDC Router switching for DisplayPort (and others?)
}
#endif
if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) { if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
display_mode preferredMode; display_mode preferredMode;
@@ -970,7 +970,7 @@ dp_is_dp12_capable(uint32 connectorIndex)
uint32 capabilities = gConnector[connectorIndex]->encoder.capabilities; uint32 capabilities = gConnector[connectorIndex]->encoder.capabilities;
if (info.dceMajor >= 5 if (info.dceMajor >= 5
&& gInfo->dpExternalClock >= 53900 && gInfo->dpExternalClock >= 539000
&& (capabilities & ATOM_ENCODER_CAP_RECORD_HBR2) != 0) { && (capabilities & ATOM_ENCODER_CAP_RECORD_HBR2) != 0) {
return true; return true;
} }
+6 -3
View File
@@ -68,21 +68,24 @@ radeon_gpu_probe()
if (info.dceMajor >= 4) { if (info.dceMajor >= 4) {
gInfo->displayClockFrequency = B_LENDIAN_TO_HOST_INT32( gInfo->displayClockFrequency = B_LENDIAN_TO_HOST_INT32(
firmwareInfo->info_21.ulDefaultDispEngineClkFreq); firmwareInfo->info_21.ulDefaultDispEngineClkFreq);
gInfo->displayClockFrequency *= 10;
if (gInfo->displayClockFrequency == 0) { if (gInfo->displayClockFrequency == 0) {
if (info.dceMajor >= 5) if (info.dceMajor >= 5)
gInfo->displayClockFrequency = 54000; gInfo->displayClockFrequency = 540000;
else else
gInfo->displayClockFrequency = 60000; gInfo->displayClockFrequency = 600000;
} }
gInfo->dpExternalClock = B_LENDIAN_TO_HOST_INT16( gInfo->dpExternalClock = B_LENDIAN_TO_HOST_INT16(
firmwareInfo->info_21.usUniphyDPModeExtClkFreq); firmwareInfo->info_21.usUniphyDPModeExtClkFreq);
gInfo->dpExternalClock *= 10;
} }
gInfo->maximumPixelClock = B_LENDIAN_TO_HOST_INT16( gInfo->maximumPixelClock = B_LENDIAN_TO_HOST_INT16(
firmwareInfo->info.usMaxPixelClock); firmwareInfo->info.usMaxPixelClock);
gInfo->maximumPixelClock *= 10;
if (gInfo->maximumPixelClock == 0) if (gInfo->maximumPixelClock == 0)
gInfo->maximumPixelClock = 40000; gInfo->maximumPixelClock = 400000;
return B_OK; return B_OK;
} }
+33 -18
View File
@@ -34,6 +34,16 @@ extern "C" void _sPrintf(const char* format, ...);
#define ERROR(x...) _sPrintf("radeon_hd: " x) #define ERROR(x...) _sPrintf("radeon_hd: " x)
// Pixel Clock Storage
// kHz Value Result
// Haiku: 104000 khz 104 Mhz
// Linux: 104000 khz 104 Mhz
// AtomBIOS: 10400 * 10 khz 104 Mhz
// Ghz
// Haiku: 162000 * 10 khz 1.62 Ghz
// Linux: 162000 * 10 khz 1.62 Ghz
// AtomBIOS: 16200 * 10 Khz 0.162 * 10 Ghz
status_t status_t
pll_limit_probe(pll_info* pll) pll_limit_probe(pll_info* pll)
@@ -118,9 +128,9 @@ pll_limit_probe(pll_info* pll)
pll->pllInMax = B_LENDIAN_TO_HOST_INT16( pll->pllInMax = B_LENDIAN_TO_HOST_INT16(
firmwareInfo->info.usMaxPixelClockPLL_Input) * 10; firmwareInfo->info.usMaxPixelClockPLL_Input) * 10;
TRACE("%s: referenceFreq: %" B_PRIu16 "; pllOutMin: %" B_PRIu16 "; " TRACE("%s: referenceFreq: %" B_PRIu32 "; pllOutMin: %" B_PRIu32 "; "
" pllOutMax: %" B_PRIu16 "; pllInMin: %" B_PRIu16 ";" " pllOutMax: %" B_PRIu32 "; pllInMin: %" B_PRIu32 ";"
"pllInMax: %" B_PRIu16 "\n", __func__, pll->referenceFreq, "pllInMax: %" B_PRIu32 "\n", __func__, pll->referenceFreq,
pll->pllOutMin, pll->pllOutMax, pll->pllInMin, pll->pllInMax); pll->pllOutMin, pll->pllOutMax, pll->pllInMin, pll->pllInMax);
return B_OK; return B_OK;
@@ -205,7 +215,7 @@ pll_asic_ss_probe(pll_info* pll, uint32 ssID)
continue; continue;
} }
TRACE("%s: ss match found\n", __func__); TRACE("%s: ss match found\n", __func__);
if (pll->pixelClock > B_LENDIAN_TO_HOST_INT32( if (pll->pixelClock * 10 > B_LENDIAN_TO_HOST_INT32(
ss_info->info.asSpreadSpectrum[i].ulTargetClockRange)) { ss_info->info.asSpreadSpectrum[i].ulTargetClockRange)) {
TRACE("%s: pixelClock > targetClockRange!\n", __func__); TRACE("%s: pixelClock > targetClockRange!\n", __func__);
continue; continue;
@@ -232,7 +242,7 @@ pll_asic_ss_probe(pll_info* pll, uint32 ssID)
continue; continue;
} }
TRACE("%s: ss match found\n", __func__); TRACE("%s: ss match found\n", __func__);
if (pll->pixelClock > B_LENDIAN_TO_HOST_INT32( if (pll->pixelClock * 10 > B_LENDIAN_TO_HOST_INT32(
ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange)) { ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange)) {
TRACE("%s: pixelClock > targetClockRange!\n", __func__); TRACE("%s: pixelClock > targetClockRange!\n", __func__);
continue; continue;
@@ -260,7 +270,7 @@ pll_asic_ss_probe(pll_info* pll, uint32 ssID)
continue; continue;
} }
TRACE("%s: ss match found\n", __func__); TRACE("%s: ss match found\n", __func__);
if (pll->pixelClock > B_LENDIAN_TO_HOST_INT32( if (pll->pixelClock * 10 > B_LENDIAN_TO_HOST_INT32(
ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange)) { ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange)) {
TRACE("%s: pixelClock > targetClockRange!\n", __func__); TRACE("%s: pixelClock > targetClockRange!\n", __func__);
continue; continue;
@@ -433,11 +443,15 @@ pll_compute(pll_info* pll)
+ (referenceFrequency * pll->feedbackDivFrac)) + (referenceFrequency * pll->feedbackDivFrac))
/ (pll->referenceDiv * pll->postDiv * 10); / (pll->referenceDiv * pll->postDiv * 10);
TRACE("%s: pixel clock: %" B_PRIu32 " gives:" TRACE("%s: Calculated pixel clock of %" B_PRIu32 " based on:\n", __func__,
" feedbackDivider = %" B_PRIu32 ".%" B_PRIu32 calculatedClock);
"; referenceDivider = %" B_PRIu32 "; postDivider = %" B_PRIu32 "\n", TRACE("%s: referenceFrequency: %" B_PRIu32 "; "
__func__, pll->adjustedClock, pll->feedbackDiv, pll->feedbackDivFrac, "referenceDivider: %" B_PRIu32 "\n", __func__, referenceFrequency,
pll->referenceDiv, pll->postDiv); pll->referenceDiv);
TRACE("%s: feedbackDivider: %" B_PRIu32 "; "
"feedbackDividerFrac: %" B_PRIu32 "\n", __func__, pll->feedbackDiv,
pll->feedbackDivFrac);
TRACE("%s: postDivider: %" B_PRIu32 "\n", __func__, pll->postDiv);
if (pll->adjustedClock != 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",
@@ -579,9 +593,10 @@ pll_adjust(pll_info* pll, display_mode* mode, uint8 crtcID)
TRACE("%s: encoderMode is DP\n", __func__); TRACE("%s: encoderMode is DP\n", __func__);
args.v3.sInput.ucDispPllConfig args.v3.sInput.ucDispPllConfig
|= DISPPLL_CONFIG_COHERENT_MODE; |= DISPPLL_CONFIG_COHERENT_MODE;
/* 16200 or 27000 */ /* 162000 or 270000 */
uint32 dpLinkSpeed uint32 dpLinkSpeed
= dp_get_link_rate(connectorIndex, mode); = dp_get_link_rate(connectorIndex, mode);
/* 16200 or 27000 */
args.v3.sInput.usPixelClock args.v3.sInput.usPixelClock
= B_HOST_TO_LENDIAN_INT16(dpLinkSpeed / 10); = B_HOST_TO_LENDIAN_INT16(dpLinkSpeed / 10);
} else if ((connectorFlags & ATOM_DEVICE_DFP_SUPPORT) } else if ((connectorFlags & ATOM_DEVICE_DFP_SUPPORT)
@@ -608,8 +623,7 @@ 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->adjustedClock pll->adjustedClock = B_LENDIAN_TO_HOST_INT32(
= B_LENDIAN_TO_HOST_INT32(
args.v3.sOutput.ulDispPllFreq); args.v3.sOutput.ulDispPllFreq);
pll->adjustedClock *= 10; pll->adjustedClock *= 10;
// convert to kHz for storage // convert to kHz for storage
@@ -650,7 +664,7 @@ 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; uint32 dp_clock = gConnector[connectorIndex]->dpInfo.linkRate;
bool ssEnabled = false; bool ssEnabled = false;
pll->pixelClock = mode->timing.pixel_clock; pll->pixelClock = mode->timing.pixel_clock;
@@ -671,7 +685,7 @@ 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 {
if (dp_clock == 16200) { if (dp_clock == 162000) {
ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID2); ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID2);
if (!ssEnabled) if (!ssEnabled)
// id2 failed, try id1 // id2 failed, try id1
@@ -889,13 +903,14 @@ pll_external_set(uint32 clock)
// If the default DC PLL clock is specified, // If the default DC PLL clock is specified,
// SetPixelClock provides the dividers. // SetPixelClock provides the dividers.
args.v5.ucCRTC = ATOM_CRTC_INVALID; args.v5.ucCRTC = ATOM_CRTC_INVALID;
args.v5.usPixelClock = B_HOST_TO_LENDIAN_INT16(clock); args.v5.usPixelClock = B_HOST_TO_LENDIAN_INT16(clock / 10);
args.v5.ucPpll = ATOM_DCPLL; args.v5.ucPpll = ATOM_DCPLL;
break; break;
case 6: case 6:
// If the default DC PLL clock is specified, // If the default DC PLL clock is specified,
// SetPixelClock provides the dividers. // SetPixelClock provides the dividers.
args.v6.ulDispEngClkFreq = B_HOST_TO_LENDIAN_INT32(clock); args.v6.ulDispEngClkFreq
= B_HOST_TO_LENDIAN_INT32(clock / 10);
if (dceVersion == 601) if (dceVersion == 601)
args.v6.ucPpll = ATOM_EXT_PLL1; args.v6.ucPpll = ATOM_EXT_PLL1;
else if (dceVersion >= 600) else if (dceVersion >= 600)