From 817c114de7e2e71d98adccb66358e94244a1486a Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Tue, 7 Aug 2012 13:20:52 -0500 Subject: [PATCH] radeon_hd: rework some pll code * Force fractional feedback divider on APU's * Spread Spectrum is now probed more correctly across multiple encoders and cards * SS still disabled however. --- .../accelerants/radeon_hd/accelerant.cpp | 3 - .../accelerants/radeon_hd/accelerant.h | 2 + .../accelerants/radeon_hd/connector.cpp | 3 + src/add-ons/accelerants/radeon_hd/display.cpp | 3 +- src/add-ons/accelerants/radeon_hd/gpu.cpp | 68 +++++++++++++------ src/add-ons/accelerants/radeon_hd/gpu.h | 5 +- src/add-ons/accelerants/radeon_hd/pll.cpp | 49 ++++++++++--- src/add-ons/accelerants/radeon_hd/pll.h | 4 +- 8 files changed, 100 insertions(+), 37 deletions(-) diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.cpp b/src/add-ons/accelerants/radeon_hd/accelerant.cpp index fa6b9c4beb..c6bd9f0f79 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.cpp +++ b/src/add-ons/accelerants/radeon_hd/accelerant.cpp @@ -255,9 +255,6 @@ radeon_init_accelerant(int device) // probe firmware information radeon_gpu_probe(); - // disable spread spectrum as it requires lots of extra calculations - radeon_gpu_ss_disable(); - // program external pll clock pll_external_init(); diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.h b/src/add-ons/accelerants/radeon_hd/accelerant.h index 6b3d720ace..4f5379a792 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.h +++ b/src/add-ons/accelerants/radeon_hd/accelerant.h @@ -76,6 +76,8 @@ struct accelerant_info { uint32 displayClockFrequency; uint32 dpExternalClock; + uint32 lvdsSpreadSpectrumID; + RingQueue* ringQueue[RADEON_QUEUE_MAX]; // Ring buffer command processor }; diff --git a/src/add-ons/accelerants/radeon_hd/connector.cpp b/src/add-ons/accelerants/radeon_hd/connector.cpp index 5cc325f82d..31e303f0bf 100644 --- a/src/add-ons/accelerants/radeon_hd/connector.cpp +++ b/src/add-ons/accelerants/radeon_hd/connector.cpp @@ -200,6 +200,9 @@ connector_read_mode_lvds(uint32 connectorIndex, display_mode* mode) // Store special lvds flags the encoder setup needs gConnector[connectorIndex]->lvdsFlags = lvdsInfo->info.ucLVDS_Misc; + // Spread Spectrum ID (in SS table) + gInfo->lvdsSpreadSpectrumID = lvdsInfo->info.ucSS_Id; + uint16 flags = B_LENDIAN_TO_HOST_INT16( lvdsInfo->info.sLCDTiming.susModeMiscInfo.usAccess); diff --git a/src/add-ons/accelerants/radeon_hd/display.cpp b/src/add-ons/accelerants/radeon_hd/display.cpp index 8f3c7479d6..4f79734f30 100644 --- a/src/add-ons/accelerants/radeon_hd/display.cpp +++ b/src/add-ons/accelerants/radeon_hd/display.cpp @@ -951,8 +951,7 @@ display_crtc_ss(uint8 crtcID, int command) } else if (info.dceMajor >= 2) { if ((command == ATOM_DISABLE) || (pll->ssPercentage == 0) || (pll->ssType & ATOM_EXTERNAL_SS_MASK)) { - // TODO: gpu_ss_disable needs pll id - radeon_gpu_ss_disable(); + radeon_gpu_ss_control(pll, false); return; } args.lvds_ss_2.usSpreadSpectrumPercentage diff --git a/src/add-ons/accelerants/radeon_hd/gpu.cpp b/src/add-ons/accelerants/radeon_hd/gpu.cpp index 85c50cac53..3e006b602b 100644 --- a/src/add-ons/accelerants/radeon_hd/gpu.cpp +++ b/src/add-ons/accelerants/radeon_hd/gpu.cpp @@ -16,6 +16,7 @@ #include "accelerant.h" #include "atom.h" #include "bios.h" +#include "pll.h" #include "utility.h" @@ -715,7 +716,7 @@ radeon_gpu_ring_boot(uint32 ringType) status_t -radeon_gpu_ss_disable() +radeon_gpu_ss_control(pll_info* pll, bool enable) { TRACE("%s called\n", __func__); @@ -723,25 +724,52 @@ radeon_gpu_ss_disable() uint32 ssControl; if (info.chipsetID >= RADEON_CEDAR) { - // PLL1 - ssControl = Read32(OUT, EVERGREEN_P1PLL_SS_CNTL); - ssControl &= ~EVERGREEN_PxPLL_SS_EN; - Write32(OUT, EVERGREEN_P1PLL_SS_CNTL, ssControl); - // PLL2 - ssControl = Read32(OUT, EVERGREEN_P2PLL_SS_CNTL); - ssControl &= ~EVERGREEN_PxPLL_SS_EN; - Write32(OUT, EVERGREEN_P2PLL_SS_CNTL, ssControl); + switch (pll->id) { + case ATOM_PPLL1: + // PLL1 + ssControl = Read32(OUT, EVERGREEN_P1PLL_SS_CNTL); + if (enable) + ssControl |= EVERGREEN_PxPLL_SS_EN; + else + ssControl &= ~EVERGREEN_PxPLL_SS_EN; + Write32(OUT, EVERGREEN_P1PLL_SS_CNTL, ssControl); + break; + case ATOM_PPLL2: + // PLL2 + ssControl = Read32(OUT, EVERGREEN_P2PLL_SS_CNTL); + if (enable) + ssControl |= EVERGREEN_PxPLL_SS_EN; + else + ssControl &= ~EVERGREEN_PxPLL_SS_EN; + Write32(OUT, EVERGREEN_P2PLL_SS_CNTL, ssControl); + break; + } + // DCPLL, no action + return B_OK; } else if (info.chipsetID >= RADEON_RS600) { - // PLL1 - ssControl = Read32(OUT, AVIVO_P1PLL_INT_SS_CNTL); - ssControl &= ~1; - Write32(OUT, AVIVO_P1PLL_INT_SS_CNTL, ssControl); - // PLL2 - ssControl = Read32(OUT, AVIVO_P2PLL_INT_SS_CNTL); - ssControl &= ~1; - Write32(OUT, AVIVO_P2PLL_INT_SS_CNTL, ssControl); - } else - return B_ERROR; + switch (pll->id) { + case ATOM_PPLL1: + // PLL1 + ssControl = Read32(OUT, AVIVO_P1PLL_INT_SS_CNTL); + if (enable) + ssControl |= 1; + else + ssControl &= ~1; + Write32(OUT, AVIVO_P1PLL_INT_SS_CNTL, ssControl); + break; + case ATOM_PPLL2: + // PLL2 + ssControl = Read32(OUT, AVIVO_P2PLL_INT_SS_CNTL); + if (enable) + ssControl |= 1; + else + ssControl &= ~1; + Write32(OUT, AVIVO_P2PLL_INT_SS_CNTL, ssControl); + break; + } + // DCPLL, no action + return B_OK; + } - return B_OK; + return B_ERROR; } diff --git a/src/add-ons/accelerants/radeon_hd/gpu.h b/src/add-ons/accelerants/radeon_hd/gpu.h index f0c0fb687b..d39d7a4ca8 100644 --- a/src/add-ons/accelerants/radeon_hd/gpu.h +++ b/src/add-ons/accelerants/radeon_hd/gpu.h @@ -13,6 +13,8 @@ #include +#include "pll.h" + // GPU Control registers. These are combined as // the registers exist on all models, some flags @@ -172,7 +174,8 @@ status_t radeon_gpu_mc_idlewait(); status_t radeon_gpu_mc_setup(); status_t radeon_gpu_ring_setup(); status_t radeon_gpu_ring_boot(uint32 ringType); -status_t radeon_gpu_ss_disable(); +status_t radeon_gpu_ss_control(pll_info* pll, bool enable); + #endif diff --git a/src/add-ons/accelerants/radeon_hd/pll.cpp b/src/add-ons/accelerants/radeon_hd/pll.cpp index 79b0cb7c54..3c0c94fd42 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.cpp +++ b/src/add-ons/accelerants/radeon_hd/pll.cpp @@ -128,7 +128,7 @@ pll_limit_probe(pll_info* pll) status_t -pll_dp_ss_probe(pll_info* pll) +pll_ppll_ss_probe(pll_info* pll, uint32 ssID) { uint8 tableMajor; uint8 tableMinor; @@ -151,7 +151,7 @@ pll_dp_ss_probe(pll_info* pll) int i; for (i = 0; i < indices; i++) { - if (ss_info->asSS_Info[i].ucSS_Id == pll->id) { + if (ss_info->asSS_Info[i].ucSS_Id == ssID) { pll->ssPercentage = B_LENDIAN_TO_HOST_INT16( ss_info->asSS_Info[i].usSpreadSpectrumPercentage); pll->ssType = ss_info->asSS_Info[i].ucSpreadSpectrumType; @@ -175,7 +175,7 @@ pll_dp_ss_probe(pll_info* pll) status_t -pll_asic_ss_probe(pll_info* pll) +pll_asic_ss_probe(pll_info* pll, uint32 ssID) { uint8 tableMajor; uint8 tableMinor; @@ -207,7 +207,7 @@ pll_asic_ss_probe(pll_info* pll) for (i = 0; i < indices; i++) { if (ss_info->info.asSpreadSpectrum[i].ucClockIndication - != pll->id) { + != ssID) { continue; } TRACE("%s: ss match found\n", __func__); @@ -234,7 +234,7 @@ pll_asic_ss_probe(pll_info* pll) for (i = 0; i < indices; i++) { if (ss_info->info_2.asSpreadSpectrum[i].ucClockIndication - != pll->id) { + != ssID) { continue; } TRACE("%s: ss match found\n", __func__); @@ -262,7 +262,7 @@ pll_asic_ss_probe(pll_info* pll) for (i = 0; i < indices; i++) { if (ss_info->info_3.asSpreadSpectrum[i].ucClockIndication - != pll->id) { + != ssID) { continue; } TRACE("%s: ss match found\n", __func__); @@ -492,6 +492,11 @@ pll_setup_flags(pll_info* pll, uint8 crtcID) if ((encoderFlags & ATOM_DEVICE_TV_SUPPORT) != 0) pll->flags |= PLL_PREFER_CLOSEST_LOWER; + + if ((info.chipsetFlags & CHIP_APU) != 0) { + // Use fractional feedback on APU's + pll->flags |= PLL_USE_FRAC_FB_DIV; + } } @@ -657,12 +662,38 @@ pll_set(display_mode* mode, uint8 crtcID) pll_compute(pll); // compute dividers - pll_asic_ss_probe(pll); - // probe spread spectrum metrics (TODO: pll_dp_ss_probe) + radeon_shared_info &info = *gInfo->shared_info; + pll->ssType = 0; + + switch (display_get_encoder_mode(connectorIndex)) { + case ATOM_ENCODER_MODE_DP_MST: + case ATOM_ENCODER_MODE_DP: + 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); + } + break; + case ATOM_ENCODER_MODE_LVDS: + if (info.dceMajor >= 4) + pll_asic_ss_probe(pll, gInfo->lvdsSpreadSpectrumID); + else + 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); + break; + case ATOM_ENCODER_MODE_HDMI: + if (info.dceMajor >= 4) + pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_HDMI); + break; + } + display_crtc_ss(crtcID, ATOM_DISABLE); // disable ss - uint8 tableMajor; uint8 tableMinor; diff --git a/src/add-ons/accelerants/radeon_hd/pll.h b/src/add-ons/accelerants/radeon_hd/pll.h index c04f042597..899aca32ee 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.h +++ b/src/add-ons/accelerants/radeon_hd/pll.h @@ -103,8 +103,8 @@ status_t pll_adjust(pll_info* pll, display_mode* mode, uint8 crtcID); status_t pll_compute(pll_info* pll); void pll_setup_flags(pll_info* pll, uint8 crtcID); status_t pll_limit_probe(pll_info* pll); -status_t pll_dp_ss_probe(pll_info* pll); -status_t pll_asic_ss_probe(pll_info* pll); +status_t pll_ppll_ss_probe(pll_info* pll, uint32 ssID); +status_t pll_asic_ss_probe(pll_info* pll, uint32 ssID); status_t pll_set(display_mode* mode, uint8 crtcID); status_t pll_pick(uint32 connectorIndex);