From 2354b8ac00da0383f2e8d59620a64afb3118c500 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Thu, 1 May 2014 09:45:06 -0500 Subject: [PATCH] radeon_hd: Finish spread spectrum support * This needs testing and is to remain disabled until we can test on several radeon_hd cards from multiple families --- src/add-ons/accelerants/radeon_hd/pll.cpp | 61 +++++++++++++++++------ src/add-ons/accelerants/radeon_hd/pll.h | 2 + 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/add-ons/accelerants/radeon_hd/pll.cpp b/src/add-ons/accelerants/radeon_hd/pll.cpp index 166896257f..e05cec5a09 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.cpp +++ b/src/add-ons/accelerants/radeon_hd/pll.cpp @@ -251,6 +251,7 @@ pll_asic_ss_probe(pll_info* pll, uint32 ssID) = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode; pll->ssRate = B_LENDIAN_TO_HOST_INT16( ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz); + pll->ssPercentageDiv = 100; return B_OK; } break; @@ -279,6 +280,7 @@ pll_asic_ss_probe(pll_info* pll, uint32 ssID) = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode; pll->ssRate = B_LENDIAN_TO_HOST_INT16( ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz); + pll->ssPercentageDiv = 100; return B_OK; } break; @@ -302,11 +304,21 @@ pll_asic_ss_probe(pll_info* pll, uint32 ssID) ss_info ->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage ); - pll->ssType = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode; pll->ssRate = B_LENDIAN_TO_HOST_INT16( ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz); + + if ((ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode + & SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK) != 0) + pll->ssPercentageDiv = 1000; + else + pll->ssPercentageDiv = 100; + + if (ssID == ASIC_INTERNAL_ENGINE_SS + || ssID == ASIC_INTERNAL_MEMORY_SS) + pll->ssRate /= 100; + return B_OK; } break; @@ -371,6 +383,8 @@ pll_compute_post_divider(pll_info* pll) status_t pll_compute(pll_info* pll) { + radeon_shared_info &info = *gInfo->shared_info; + pll_compute_post_divider(pll); const uint32 targetClock = pll->adjustedClock; @@ -487,6 +501,22 @@ pll_compute(pll_info* pll) pll->pixelClock = calculatedClock; } + // Calcuate needed SS data on DCE4 + if (info.dceMajor >= 4) { + uint32 amount = ((pll->feedbackDiv * 10) + pll->feedbackDivFrac); + amount *= pll->ssPercentage; + amount /= pll->ssPercentageDiv * 100; + pll->ssAmount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; + pll->ssAmount |= ((amount - (amount / 10)) + << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; + + uint32 centerSpreadMultiplier = 2; + if ((pll->ssType & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) != 0) + centerSpreadMultiplier = 4; + pll->ssStep = (centerSpreadMultiplier * amount * pll->referenceDiv + * (pll->ssRate * 2048)) / (125 * 25 * pll->referenceFreq / 100); + } + return B_OK; } @@ -693,7 +723,7 @@ 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; - bool ssEnabled = false; + pll->ssEnabled = false; pll->pixelClock = mode->timing.pixel_clock; @@ -714,32 +744,32 @@ pll_set(display_mode* mode, uint8 crtcID) pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_DP); else { if (dp_clock == 162000) { - ssEnabled = pll_ppll_ss_probe(pll, + pll->ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID2) == B_OK ? true : false; - if (!ssEnabled) - ssEnabled = pll_ppll_ss_probe(pll, + if (!pll->ssEnabled) + pll->ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID1) == B_OK ? true : false; } else - ssEnabled = pll_ppll_ss_probe(pll, + pll->ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID1) == B_OK ? true : false; } break; case ATOM_ENCODER_MODE_LVDS: if (info.dceMajor >= 4) - ssEnabled = pll_asic_ss_probe(pll, + pll->ssEnabled = pll_asic_ss_probe(pll, gInfo->lvdsSpreadSpectrumID) == B_OK ? true : false; else - ssEnabled = pll_ppll_ss_probe(pll, + pll->ssEnabled = pll_ppll_ss_probe(pll, gInfo->lvdsSpreadSpectrumID) == B_OK ? true : false; break; case ATOM_ENCODER_MODE_DVI: if (info.dceMajor >= 4) - ssEnabled = pll_asic_ss_probe(pll, + pll->ssEnabled = pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_TMDS) == B_OK ? true : false; break; case ATOM_ENCODER_MODE_HDMI: if (info.dceMajor >= 4) - ssEnabled = pll_asic_ss_probe(pll, + pll->ssEnabled = pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_HDMI) == B_OK ? true : false; break; } @@ -749,10 +779,7 @@ pll_set(display_mode* mode, uint8 crtcID) pll_adjust(pll, mode, crtcID); // get any needed clock adjustments, set reference/post dividers pll_compute(pll); - // compute dividers - - display_crtc_ss(pll, ATOM_DISABLE); - // disable ss + // compute dividers and spread spectrum uint8 tableMajor; uint8 tableMinor; @@ -892,8 +919,12 @@ pll_set(display_mode* mode, uint8 crtcID) status_t result = atom_execute_table(gAtomContext, index, (uint32*)&args); - if (ssEnabled) + // TODO: PLL forced off until we can test it + pll->ssEnabled = false; + if (pll->ssEnabled) display_crtc_ss(pll, ATOM_ENABLE); + else + display_crtc_ss(pll, ATOM_DISABLE); return result; } diff --git a/src/add-ons/accelerants/radeon_hd/pll.h b/src/add-ons/accelerants/radeon_hd/pll.h index 1a29381082..cd22e94d66 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.h +++ b/src/add-ons/accelerants/radeon_hd/pll.h @@ -84,6 +84,7 @@ struct pll_info { uint32 maxFeedbackDivFrac; /* spread spectrum info */ + bool ssEnabled; uint8 ssType; uint8 ssDelay; uint8 ssRange; @@ -93,6 +94,7 @@ struct pll_info { /* asic spread spectrum */ uint16 ssRate; uint16 ssAmount; + uint16 ssPercentageDiv; /* pixel clock to be used in pll calculations (kHz) */ uint32 adjustedClock;