diff options
-rw-r--r-- | src/atombios_crtc.c | 8 | ||||
-rw-r--r-- | src/radeon.h | 11 | ||||
-rw-r--r-- | src/radeon_atombios.c | 7 | ||||
-rw-r--r-- | src/radeon_crtc.c | 75 | ||||
-rw-r--r-- | src/radeon_driver.c | 1 |
5 files changed, 98 insertions, 4 deletions
diff --git a/src/atombios_crtc.c b/src/atombios_crtc.c index f9698f3f..8cccba62 100644 --- a/src/atombios_crtc.c +++ b/src/atombios_crtc.c @@ -407,7 +407,13 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode) ErrorF("after %d\n", adjust_pll_param.usPixelClock); } - RADEONComputePLL(&info->pll, sclock, &temp, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags); + if (IS_AVIVO_VARIANT) { + if (xf86ReturnOptValBool(info->Options, OPTION_NEW_PLL, TRUE)) + RADEONComputePLL_AVIVO(&info->pll, sclock, &temp, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags); + else + RADEONComputePLL(&info->pll, sclock, &temp, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags); + } else + RADEONComputePLL(&info->pll, sclock, &temp, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags); sclock = temp; /* 10 khz */ xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO, diff --git a/src/radeon.h b/src/radeon.h index 182e946e..10710a83 100644 --- a/src/radeon.h +++ b/src/radeon.h @@ -222,7 +222,8 @@ typedef enum { OPTION_ATOM_TVOUT, OPTION_R4XX_ATOM, OPTION_FORCE_LOW_POWER, - OPTION_DYNAMIC_PM + OPTION_DYNAMIC_PM, + OPTION_NEW_PLL } RADEONOpts; @@ -1164,6 +1165,14 @@ extern void RADEONComputePLL(RADEONPLLPtr pll, unsigned long freq, uint32_t *chosen_frac_feedback_div, uint32_t *chosen_reference_div, uint32_t *chosen_post_div, int flags); +extern void RADEONComputePLL_AVIVO(RADEONPLLPtr pll, + unsigned long freq, + uint32_t *chosen_dot_clock_freq, + uint32_t *chosen_feedback_div, + uint32_t *chosen_frac_feedback_div, + uint32_t *chosen_reference_div, + uint32_t *chosen_post_div, + int flags); extern DisplayModePtr RADEONCrtcFindClosestMode(xf86CrtcPtr crtc, DisplayModePtr pMode); extern void RADEONUnblank(ScrnInfoPtr pScrn); diff --git a/src/radeon_atombios.c b/src/radeon_atombios.c index 72fbe214..c272c9a5 100644 --- a/src/radeon_atombios.c +++ b/src/radeon_atombios.c @@ -2204,14 +2204,17 @@ RADEONGetATOMClockInfo(ScrnInfoPtr pScrn) if (pll->pll_out_min == 0) pll->pll_out_min = 64800; + /* limiting the range is a good thing in most cases * as it limits the number of matching pll combinations, * however, some duallink DVI monitors seem to prefer combinations that * would be limited by this. This may need to be revisited * per chip family. */ - if (pll->pll_out_min > 64800) - pll->pll_out_min = 64800; + if (!xf86ReturnOptValBool(info->Options, OPTION_NEW_PLL, TRUE)) { + if (pll->pll_out_min > 64800) + pll->pll_out_min = 64800; + } return TRUE; } diff --git a/src/radeon_crtc.c b/src/radeon_crtc.c index 3899064f..4e8b490b 100644 --- a/src/radeon_crtc.c +++ b/src/radeon_crtc.c @@ -301,6 +301,81 @@ RADEONComputePLL(RADEONPLLPtr pll, } +void +RADEONComputePLL_AVIVO(RADEONPLLPtr pll, + unsigned long freq, + uint32_t *chosen_dot_clock_freq, + uint32_t *chosen_feedback_div, + uint32_t *chosen_frac_feedback_div, + uint32_t *chosen_reference_div, + uint32_t *chosen_post_div, + int flags) +{ + float m, n, frac_n, p, f_vco, f_pclk, best_freq; + float pll_out_max = pll->pll_out_max; + float pll_out_min = pll->pll_out_min; + float reference_freq = pll->reference_freq; + float pll_in_max = pll->pll_in_max; + float pll_in_min = pll->pll_in_min; + float ffreq = freq / 10; + float error = 100; + + ErrorF("ffreq: %f\n", ffreq * 10); + + /* 1 - max p */ + p = floor(pll_out_max / ffreq); + + /* 2 - min m */ + m = ceil(reference_freq / pll_in_max); + + while (error > 0.25) { + /* 3 - n */ + n = (ffreq / reference_freq) * m * p; + + /* 4 - vco out freq */ + f_vco = (n / m) * reference_freq; + + /* 5 - pclk freq */ + f_pclk = f_vco / p; + + /* 6 - error */ + error = (abs(f_pclk - ffreq) / f_pclk) * 100; + + best_freq = reference_freq * (n / (m * p)); + + /* min error 0.25% */ + if (error < 0.25) + break; + + /* 7 - check m */ + m++; + if ((reference_freq / m) >= pll_in_min) + continue; + + /* 8 - check p */ + m = ceil(reference_freq / pll_in_max); + p--; + if ((p * ffreq) >= pll_out_min) + continue; + else + FatalError("Couldn't find valid PLL dividers\n"); + } + + frac_n = (n - (int)n) * 10; + + ErrorF("best_freq: %u\n", (unsigned int)best_freq * 10); + ErrorF("best_feedback_div: %d.%d\n", (int)n, (int)frac_n); + ErrorF("best_ref_div: %d\n", (int)m); + ErrorF("best_post_div: %d\n", (int)p); + + *chosen_dot_clock_freq = best_freq; + *chosen_feedback_div = (uint32_t)n; + *chosen_frac_feedback_div = (uint32_t)frac_n; + *chosen_reference_div = (uint32_t)m; + *chosen_post_div = (uint32_t)p; + +} + static void radeon_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, int x, int y) diff --git a/src/radeon_driver.c b/src/radeon_driver.c index bf560f7d..ae4993bc 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -205,6 +205,7 @@ static const OptionInfoRec RADEONOptions[] = { { OPTION_R4XX_ATOM, "R4xxATOM", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_FORCE_LOW_POWER, "ForceLowPowerMode", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_DYNAMIC_PM, "DynamicPM", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_NEW_PLL, "NewPLL", OPTV_BOOLEAN, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; |