diff options
author | Alex Deucher <alex@samba.(none)> | 2007-12-13 18:45:09 -0500 |
---|---|---|
committer | Alex Deucher <alex@samba.(none)> | 2007-12-13 18:45:09 -0500 |
commit | 814c6c48aebba2e45ce257289b922cd7e92caf2a (patch) | |
tree | b6421082b5c6fe80591ce208f9c8feaf4313616e | |
parent | f5ac34983411e4c4f41ab1817dce582830f398fd (diff) |
RADEON: rework PLL calculation
- Take into account the limits from the bios tables
- Unify the PLL calculation between legacy and avivo chips
-rw-r--r-- | src/atombios_crtc.c | 89 | ||||
-rw-r--r-- | src/radeon.h | 10 | ||||
-rw-r--r-- | src/radeon_bios.c | 28 | ||||
-rw-r--r-- | src/radeon_crtc.c | 12 | ||||
-rw-r--r-- | src/radeon_driver.c | 34 |
5 files changed, 60 insertions, 113 deletions
diff --git a/src/atombios_crtc.c b/src/atombios_crtc.c index 5b09107..2297316 100644 --- a/src/atombios_crtc.c +++ b/src/atombios_crtc.c @@ -148,82 +148,6 @@ atombios_set_crtc_timing(atomBiosHandlePtr atomBIOS, SET_CRTC_TIMING_PARAMETERS_ return ATOM_NOT_IMPLEMENTED; } -/* - * Calculate the PLL parameters for a given dotclock. - */ -#define RADEON_PLL_DEFAULT_PLLOUT_MIN 64800 /* experimental. - taken from rhd divided by 10 */ - -static Bool -PLLCalculate(ScrnInfoPtr pScrn, CARD32 PixelClock, - CARD16 *RefDivider, CARD16 *FBDivider, CARD8 *PostDivider) -{ -/* limited by the number of bits available */ -#define FB_DIV_LIMIT 1024 /* rv6x0 doesn't like 2048 */ -#define REF_DIV_LIMIT 1024 -#define POST_DIV_LIMIT 128 - RADEONInfoPtr info = RADEONPTR (pScrn); - RADEONPLLPtr pll = &info->pll; - CARD32 FBDiv, RefDiv, PostDiv, BestDiff = 0xFFFFFFFF; - float Ratio; - - Ratio = ((float) PixelClock) / ((float) pll->reference_freq * 10); - - if (pll->min_pll_freq == 0) - pll->min_pll_freq = RADEON_PLL_DEFAULT_PLLOUT_MIN; - for (PostDiv = 2; PostDiv < POST_DIV_LIMIT; PostDiv++) { - CARD32 VCOOut = PixelClock * PostDiv; - - /* we are conservative and avoid the limits */ - if (VCOOut <= pll->min_pll_freq * 10) - continue; - if (VCOOut >= pll->max_pll_freq * 10) - break; - - for (RefDiv = 1; RefDiv <= REF_DIV_LIMIT; RefDiv++) - { - CARD32 Diff; - - FBDiv = (CARD32) ((Ratio * PostDiv * RefDiv) + 0.5); - - if (FBDiv >= FB_DIV_LIMIT) - break; - - if (FBDiv > (500 + (13 * RefDiv))) /* rv6x0 limit */ - break; - - Diff = abs( PixelClock - (FBDiv * pll->reference_freq * 10) / (PostDiv * RefDiv) ); - - if (Diff < BestDiff) { - *FBDivider = FBDiv; - *RefDivider = RefDiv; - *PostDivider = PostDiv; - BestDiff = Diff; - } - - if (BestDiff == 0) - break; - } - if (BestDiff == 0) - break; - } - - if (BestDiff != 0xFFFFFFFF) { - ErrorF("PLL Calculation: %dkHz = " - "(((0x%X / 0x%X) * 0x%X) / 0x%X) (%dkHz off)\n", - (int) PixelClock, (unsigned int) pll->reference_freq * 10, *RefDivider, - *FBDivider, *PostDivider, (int) BestDiff); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PLL for %dkHz uses %dkHz internally.\n", - (int) PixelClock, - (int) (pll->reference_freq * 10 * *FBDivider) / *RefDivider); - return TRUE; - } else { /* Should never happen */ - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "%s: Failed to get a valid PLL setting for %dkHz\n", - __func__, (int) PixelClock); - return FALSE; - } -} - void atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode) { @@ -231,7 +155,7 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode) RADEONInfoPtr info = RADEONPTR(crtc->scrn); unsigned char *RADEONMMIO = info->MMIO; int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); - int sclock = mode->Clock; + CARD32 sclock = mode->Clock; uint16_t ref_div = 0, fb_div = 0; uint8_t post_div = 0; int major, minor; @@ -240,10 +164,11 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode) AtomBiosArgRec data; unsigned char *space; RADEONSavePtr save = info->ModeReg; - + if (IS_AVIVO_VARIANT) { - CARD32 temp; - PLLCalculate(crtc->scrn, sclock, &ref_div, &fb_div, &post_div); + CARD32 temp; + RADEONComputePLL(&info->pll, mode->Clock * 1000, &sclock, &fb_div, &ref_div, &post_div); + sclock /= 1000; /* disable spread spectrum clocking for now -- thanks Hedy Lamarr */ if (radeon_crtc->crtc_id == 0) { @@ -268,7 +193,7 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode) radeon_crtc->crtc_id, ref_div, fb_div, fb_div, post_div); atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); - + ErrorF("table is %d %d\n", major, minor); switch(major) { case 1: @@ -304,7 +229,7 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode) ErrorF("Set CRTC PLL success\n"); return; } - + ErrorF("Set CRTC PLL failed\n"); return; } diff --git a/src/radeon.h b/src/radeon.h index 038fcc7..6c38826 100644 --- a/src/radeon.h +++ b/src/radeon.h @@ -203,16 +203,18 @@ typedef struct { typedef struct { CARD16 reference_freq; CARD16 reference_div; - CARD32 min_pll_freq; - CARD32 max_pll_freq; + CARD32 pll_in_min; + CARD32 pll_in_max; + CARD32 pll_out_min; + CARD32 pll_out_max; CARD16 xclk; CARD32 min_ref_div; CARD32 max_ref_div; + CARD32 min_post_div; + CARD32 max_post_div; CARD32 min_feedback_div; CARD32 max_feedback_div; - CARD32 pll_in_min; - CARD32 pll_in_max; CARD32 best_vco; } RADEONPLLRec, *RADEONPLLPtr; diff --git a/src/radeon_bios.c b/src/radeon_bios.c index 7b4eafb..9730119 100644 --- a/src/radeon_bios.c +++ b/src/radeon_bios.c @@ -611,8 +611,19 @@ Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn) or use a new algorithm to calculate from min_input and max_input */ - pll->min_pll_freq = RADEON_BIOS16 (pll_info_block + 78); - pll->max_pll_freq = RADEON_BIOS32 (pll_info_block + 32); + pll->pll_out_min = RADEON_BIOS16 (pll_info_block + 78); + pll->pll_out_max = RADEON_BIOS32 (pll_info_block + 32); + + if (pll->pll_out_min == 0) { + if (IS_AVIVO_VARIANT) + pll->pll_out_min = 64800; + else + pll->pll_out_min = 20000; + } + + pll->pll_in_min = RADEON_BIOS16 (pll_info_block + 74); + pll->pll_in_max = RADEON_BIOS16 (pll_info_block + 76); + pll->xclk = RADEON_BIOS16 (pll_info_block + 72); info->sclk = RADEON_BIOS32(pll_info_block + 8) / 100.0; @@ -622,8 +633,13 @@ Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn) pll->reference_freq = RADEON_BIOS16 (pll_info_block + 0x0e); pll->reference_div = RADEON_BIOS16 (pll_info_block + 0x10); - pll->min_pll_freq = RADEON_BIOS32 (pll_info_block + 0x12); - pll->max_pll_freq = RADEON_BIOS32 (pll_info_block + 0x16); + pll->pll_out_min = RADEON_BIOS32 (pll_info_block + 0x12); + pll->pll_out_max = RADEON_BIOS32 (pll_info_block + 0x16); + + /* not available in the bios */ + pll->pll_in_min = 40; + pll->pll_in_max = 100; + pll->xclk = RADEON_BIOS16 (pll_info_block + 0x08); info->sclk = RADEON_BIOS16(pll_info_block + 8) / 100.0; @@ -636,8 +652,8 @@ Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ref_freq: %d, min_pll: %u, " "max_pll: %u, xclk: %d, sclk: %f, mclk: %f\n", - pll->reference_freq, (unsigned)pll->min_pll_freq, - (unsigned)pll->max_pll_freq, pll->xclk, info->sclk, + pll->reference_freq, (unsigned)pll->pll_out_min, + (unsigned)pll->pll_out_max, pll->xclk, info->sclk, info->mclk); return TRUE; diff --git a/src/radeon_crtc.c b/src/radeon_crtc.c index cf78e2c..45eb1ac 100644 --- a/src/radeon_crtc.c +++ b/src/radeon_crtc.c @@ -631,7 +631,7 @@ static CARD32 RADEONDiv64(CARD64 n, CARD32 d) return (n + (d / 2)) / d; } -static void +void RADEONComputePLL(RADEONPLLPtr pll, unsigned long freq, CARD32 *chosen_dot_clock_freq, @@ -639,10 +639,6 @@ RADEONComputePLL(RADEONPLLPtr pll, CARD32 *chosen_reference_div, CARD32 *chosen_post_div) { - int post_divs[] = {1, 2, 4, 8, 3, 6, 12, 0}; - - int i; - CARD32 best_vco = pll->best_vco; CARD32 best_post_div = 1; CARD32 best_ref_div = 1; @@ -650,15 +646,15 @@ RADEONComputePLL(RADEONPLLPtr pll, CARD32 best_freq = 1; CARD32 best_error = 0xffffffff; CARD32 best_vco_diff = 1; + CARD32 post_div; ErrorF("freq: %lu\n", freq); - for (i = 0; post_divs[i]; i++) { - int post_div = post_divs[i]; + for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) { CARD32 ref_div; CARD32 vco = (freq / 10000) * post_div; - if (vco < pll->min_pll_freq || vco > pll->max_pll_freq) + if (vco < pll->pll_out_min || vco > pll->pll_out_max) continue; for (ref_div = pll->min_ref_div; ref_div <= pll->max_ref_div; ++ref_div) { diff --git a/src/radeon_driver.c b/src/radeon_driver.c index 2c5e64f..16d758b 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -1162,22 +1162,25 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn) if (pll->reference_div < 2) pll->reference_div = 12; } - } else { xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "Video BIOS not detected, using default clock settings!\n"); /* Default min/max PLL values */ if (info->ChipFamily == CHIP_FAMILY_R420 || info->ChipFamily == CHIP_FAMILY_RV410) { - pll->min_pll_freq = 20000; - pll->max_pll_freq = 50000; + pll->pll_in_min = 100; + pll->pll_in_max = 1350; + pll->pll_out_min = 20000; + pll->pll_out_max = 50000; } else { - pll->min_pll_freq = 12500; - pll->max_pll_freq = 35000; + pll->pll_in_min = 40; + pll->pll_in_max = 100; + pll->pll_out_min = 12500; + pll->pll_out_max = 35000; } if (RADEONProbePLLParameters(pScrn)) - return; + return; if (info->IsIGP) pll->reference_freq = 1432; @@ -1198,25 +1201,30 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn) * Empirical value changed to 24 to raise pixel clock limit and * allow higher resolution modes on capable monitors */ - pll->max_pll_freq = min(pll->max_pll_freq, + pll->pll_out_max = min(pll->pll_out_max, 24 * info->mclk * 100 / pScrn->bitsPerPixel * info->RamWidth / 16); } /* card limits for computing PLLs */ + if (IS_AVIVO_VARIANT) { + pll->min_post_div = 2; + pll->max_post_div = 0x7f; + } else { + pll->min_post_div = 2; + pll->max_post_div = 12; //16 on crtc0 + } pll->min_ref_div = 2; pll->max_ref_div = 0x3ff; pll->min_feedback_div = 4; pll->max_feedback_div = 0x7ff; - pll->pll_in_min = 40; - pll->pll_in_max = 100; pll->best_vco = 0; xf86DrvMsg (pScrn->scrnIndex, X_INFO, "PLL parameters: rf=%u rd=%u min=%u max=%u; xclk=%u\n", pll->reference_freq, pll->reference_div, - (unsigned)pll->min_pll_freq, (unsigned)pll->max_pll_freq, + (unsigned)pll->pll_out_min, (unsigned)pll->pll_out_max, pll->xclk); /* (Some?) Radeon BIOSes seem too lie about their minimum dot @@ -1225,7 +1233,7 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn) */ if (xf86GetOptValFreq(info->Options, OPTION_MIN_DOTCLOCK, OPTUNITS_MHZ, &min_dotclock)) { - if (min_dotclock < 12 || min_dotclock*100 >= pll->max_pll_freq) { + if (min_dotclock < 12 || min_dotclock*100 >= pll->pll_out_max) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Illegal minimum dotclock specified %.2f MHz " "(option ignored)\n", @@ -1234,8 +1242,8 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Forced minimum dotclock to %.2f MHz " "(instead of detected %.2f MHz)\n", - min_dotclock, ((double)pll->min_pll_freq/1000)); - pll->min_pll_freq = min_dotclock * 1000; + min_dotclock, ((double)pll->pll_out_min/1000)); + pll->pll_out_min = min_dotclock * 1000; } } } |