radeon_hd: Improve pll probing. Let probe calls enable ss

This commit is contained in:
Alexander von Gluck IV 2014-05-24 16:38:56 -05:00
parent 6b6ff33d60
commit a8307efa46

View File

@ -171,6 +171,7 @@ pll_ppll_ss_probe(pll_info* pll, uint32 ssID)
if (atom_parse_data_header(gAtomContext, index, &headerSize, if (atom_parse_data_header(gAtomContext, index, &headerSize,
&tableMajor, &tableMinor, &headerOffset) != B_OK) { &tableMajor, &tableMinor, &headerOffset) != B_OK) {
ERROR("%s: Couldn't parse data header\n", __func__); ERROR("%s: Couldn't parse data header\n", __func__);
pll->ssEnabled = false;
return B_ERROR; return B_ERROR;
} }
@ -192,10 +193,12 @@ pll_ppll_ss_probe(pll_info* pll, uint32 ssID)
pll->ssRange = ss_info->asSS_Info[i].ucSS_Range; pll->ssRange = ss_info->asSS_Info[i].ucSS_Range;
pll->ssReferenceDiv pll->ssReferenceDiv
= ss_info->asSS_Info[i].ucRecommendedRef_Div; = ss_info->asSS_Info[i].ucRecommendedRef_Div;
pll->ssEnabled = true;
return B_OK; return B_OK;
} }
} }
pll->ssEnabled = false;
return B_ERROR; return B_ERROR;
} }
@ -212,6 +215,7 @@ pll_asic_ss_probe(pll_info* pll, uint32 ssID)
if (atom_parse_data_header(gAtomContext, index, &headerSize, if (atom_parse_data_header(gAtomContext, index, &headerSize,
&tableMajor, &tableMinor, &headerOffset) != B_OK) { &tableMajor, &tableMinor, &headerOffset) != B_OK) {
ERROR("%s: Couldn't parse data header\n", __func__); ERROR("%s: Couldn't parse data header\n", __func__);
pll->ssEnabled = false;
return B_ERROR; return B_ERROR;
} }
@ -252,6 +256,7 @@ pll_asic_ss_probe(pll_info* pll, uint32 ssID)
pll->ssRate = B_LENDIAN_TO_HOST_INT16( pll->ssRate = B_LENDIAN_TO_HOST_INT16(
ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz); ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz);
pll->ssPercentageDiv = 100; pll->ssPercentageDiv = 100;
pll->ssEnabled = true;
return B_OK; return B_OK;
} }
break; break;
@ -281,6 +286,7 @@ pll_asic_ss_probe(pll_info* pll, uint32 ssID)
pll->ssRate = B_LENDIAN_TO_HOST_INT16( pll->ssRate = B_LENDIAN_TO_HOST_INT16(
ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz); ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
pll->ssPercentageDiv = 100; pll->ssPercentageDiv = 100;
pll->ssEnabled = true;
return B_OK; return B_OK;
} }
break; break;
@ -319,15 +325,18 @@ pll_asic_ss_probe(pll_info* pll, uint32 ssID)
|| ssID == ASIC_INTERNAL_MEMORY_SS) || ssID == ASIC_INTERNAL_MEMORY_SS)
pll->ssRate /= 100; pll->ssRate /= 100;
pll->ssEnabled = true;
return B_OK; return B_OK;
} }
break; break;
default: default:
ERROR("%s: Unknown SS table version!\n", __func__); ERROR("%s: Unknown SS table version!\n", __func__);
pll->ssEnabled = false;
return B_ERROR; return B_ERROR;
} }
ERROR("%s: No potential spread spectrum data found!\n", __func__); ERROR("%s: No potential spread spectrum data found!\n", __func__);
pll->ssEnabled = false;
return B_ERROR; return B_ERROR;
} }
@ -391,7 +400,6 @@ pll_compute(pll_info* pll)
pll->feedbackDiv = 0; pll->feedbackDiv = 0;
pll->feedbackDivFrac = 0; pll->feedbackDivFrac = 0;
const uint32 referenceFrequency = pll->referenceFreq;
if ((pll->flags & PLL_USE_REF_DIV) != 0) { if ((pll->flags & PLL_USE_REF_DIV) != 0) {
TRACE("%s: using AtomBIOS reference divider\n", __func__); TRACE("%s: using AtomBIOS reference divider\n", __func__);
@ -405,8 +413,8 @@ pll_compute(pll_info* pll)
const uint32 numerator = pll->postDiv * pll->referenceDiv const uint32 numerator = pll->postDiv * pll->referenceDiv
* targetClock; * targetClock;
pll->feedbackDiv = numerator / referenceFrequency; pll->feedbackDiv = numerator / pll->referenceFreq;
pll->feedbackDivFrac = numerator % referenceFrequency; pll->feedbackDivFrac = numerator % pll->referenceFreq;
if (pll->feedbackDiv > pll->maxFeedbackDiv) if (pll->feedbackDiv > pll->maxFeedbackDiv)
pll->feedbackDiv = pll->maxFeedbackDiv; pll->feedbackDiv = pll->maxFeedbackDiv;
@ -415,7 +423,7 @@ pll_compute(pll_info* pll)
// Put first 2 digits after the decimal point into feedbackDivFrac // Put first 2 digits after the decimal point into feedbackDivFrac
pll->feedbackDivFrac pll->feedbackDivFrac
= (100 * pll->feedbackDivFrac) / referenceFrequency; = (100 * pll->feedbackDivFrac) / pll->referenceFreq;
// Now round it to one digit // Now round it to one digit
if (pll->feedbackDivFrac >= 5) { if (pll->feedbackDivFrac >= 5) {
@ -435,16 +443,16 @@ pll_compute(pll_info* pll)
uint32 retroEncabulator = pll->postDiv * pll->referenceDiv; uint32 retroEncabulator = pll->postDiv * pll->referenceDiv;
retroEncabulator *= targetClock; retroEncabulator *= targetClock;
pll->feedbackDiv = retroEncabulator / referenceFrequency; pll->feedbackDiv = retroEncabulator / pll->referenceFreq;
pll->feedbackDivFrac pll->feedbackDivFrac
= retroEncabulator % referenceFrequency; = retroEncabulator % pll->referenceFreq;
if (pll->feedbackDiv > pll->maxFeedbackDiv) if (pll->feedbackDiv > pll->maxFeedbackDiv)
pll->feedbackDiv = pll->maxFeedbackDiv; pll->feedbackDiv = pll->maxFeedbackDiv;
else if (pll->feedbackDiv < pll->minFeedbackDiv) else if (pll->feedbackDiv < pll->minFeedbackDiv)
pll->feedbackDiv = pll->minFeedbackDiv; pll->feedbackDiv = pll->minFeedbackDiv;
if (pll->feedbackDivFrac >= (referenceFrequency / 2)) if (pll->feedbackDivFrac >= (pll->referenceFreq / 2))
pll->feedbackDiv++; pll->feedbackDiv++;
pll->feedbackDivFrac = 0; pll->feedbackDivFrac = 0;
@ -461,7 +469,7 @@ pll_compute(pll_info* pll)
__func__, targetClock); __func__, targetClock);
return B_ERROR; return B_ERROR;
} }
uint32 tmp = (referenceFrequency * pll->feedbackDiv) uint32 tmp = (pll->referenceFreq * pll->feedbackDiv)
/ (pll->postDiv * pll->referenceDiv); / (pll->postDiv * pll->referenceDiv);
tmp = (tmp * 1000) / targetClock; tmp = (tmp * 1000) / targetClock;
@ -481,14 +489,14 @@ pll_compute(pll_info* pll)
} }
uint32 calculatedClock uint32 calculatedClock
= ((referenceFrequency * pll->feedbackDiv * 10) = ((pll->referenceFreq * pll->feedbackDiv * 10)
+ (referenceFrequency * pll->feedbackDivFrac)) + (pll->referenceFreq * pll->feedbackDivFrac))
/ (pll->referenceDiv * pll->postDiv * 10); / (pll->referenceDiv * pll->postDiv * 10);
TRACE("%s: Calculated pixel clock of %" B_PRIu32 " based on:\n", __func__, TRACE("%s: Calculated pixel clock of %" B_PRIu32 " based on:\n", __func__,
calculatedClock); calculatedClock);
TRACE("%s: referenceFrequency: %" B_PRIu32 "; " TRACE("%s: referenceFrequency: %" B_PRIu32 "; "
"referenceDivider: %" B_PRIu32 "\n", __func__, referenceFrequency, "referenceDivider: %" B_PRIu32 "\n", __func__, pll->referenceFreq,
pll->referenceDiv); pll->referenceDiv);
TRACE("%s: feedbackDivider: %" B_PRIu32 "; " TRACE("%s: feedbackDivider: %" B_PRIu32 "; "
"feedbackDividerFrac: %" B_PRIu32 "\n", __func__, pll->feedbackDiv, "feedbackDividerFrac: %" B_PRIu32 "\n", __func__, pll->feedbackDiv,
@ -502,7 +510,14 @@ pll_compute(pll_info* pll)
} }
// Calcuate needed SS data on DCE4 // Calcuate needed SS data on DCE4
if (info.dceMajor >= 4) { if (info.dceMajor >= 4 && pll->ssEnabled) {
if (pll->ssPercentageDiv == 0) {
// Avoid div by 0, shouldn't happen but be mindful of it
TRACE("%s: ssPercentageDiv is less than 0, aborting SS calcualation",
__func__);
pll->ssEnabled = false;
return B_OK;
}
uint32 amount = ((pll->feedbackDiv * 10) + pll->feedbackDivFrac); uint32 amount = ((pll->feedbackDiv * 10) + pll->feedbackDivFrac);
amount *= pll->ssPercentage; amount *= pll->ssPercentage;
amount /= pll->ssPercentageDiv * 100; amount /= pll->ssPercentageDiv * 100;
@ -744,33 +759,26 @@ pll_set(display_mode* mode, uint8 crtcID)
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 == 162000) { if (dp_clock == 162000) {
pll->ssEnabled = pll_ppll_ss_probe(pll, pll_ppll_ss_probe(pll, ATOM_DP_SS_ID2);
ATOM_DP_SS_ID2) == B_OK ? true : false;
if (!pll->ssEnabled) if (!pll->ssEnabled)
pll->ssEnabled = pll_ppll_ss_probe(pll, pll_ppll_ss_probe(pll, ATOM_DP_SS_ID1);
ATOM_DP_SS_ID1) == B_OK ? true : false;
} else } else
pll->ssEnabled = pll_ppll_ss_probe(pll, pll_ppll_ss_probe(pll, ATOM_DP_SS_ID1);
ATOM_DP_SS_ID1) == B_OK ? true : false;
} }
break; break;
case ATOM_ENCODER_MODE_LVDS: case ATOM_ENCODER_MODE_LVDS:
if (info.dceMajor >= 4) if (info.dceMajor >= 4)
pll->ssEnabled = pll_asic_ss_probe(pll, pll_asic_ss_probe(pll, gInfo->lvdsSpreadSpectrumID);
gInfo->lvdsSpreadSpectrumID) == B_OK ? true : false;
else else
pll->ssEnabled = pll_ppll_ss_probe(pll, pll_ppll_ss_probe(pll, gInfo->lvdsSpreadSpectrumID);
gInfo->lvdsSpreadSpectrumID) == B_OK ? true : false;
break; break;
case ATOM_ENCODER_MODE_DVI: case ATOM_ENCODER_MODE_DVI:
if (info.dceMajor >= 4) if (info.dceMajor >= 4)
pll->ssEnabled = pll_asic_ss_probe(pll, pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_TMDS);
ASIC_INTERNAL_SS_ON_TMDS) == B_OK ? true : false;
break; break;
case ATOM_ENCODER_MODE_HDMI: case ATOM_ENCODER_MODE_HDMI:
if (info.dceMajor >= 4) if (info.dceMajor >= 4)
pll->ssEnabled = pll_asic_ss_probe(pll, pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_HDMI);
ASIC_INTERNAL_SS_ON_HDMI) == B_OK ? true : false;
break; break;
} }
@ -919,8 +927,6 @@ 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);
// TODO: PLL forced off until we can test it
pll->ssEnabled = false;
if (pll->ssEnabled) if (pll->ssEnabled)
display_crtc_ss(pll, ATOM_ENABLE); display_crtc_ss(pll, ATOM_ENABLE);
else else