diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2009-12-09 12:55:25 -0500 |
---|---|---|
committer | Alex Deucher <alexdeucher@gmail.com> | 2009-12-09 12:55:25 -0500 |
commit | 46630da5fd6f45bb8ea150b870162997480d69c7 (patch) | |
tree | 80082feaa802872b4fe343f00cbe61787170e81f /src/radeon_crtc.c | |
parent | f082b1693d6f7f763ccf5a8436a89890ca2c6129 (diff) |
AVIVO: add new PLL code
This should hopefully help the problems with flickering
and blinking monitors reported on some systems. If there
are problems, the old PLL algorithm can be selected with:
Option "NewPLL" "FALSE"
in the device section of your X config.
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Diffstat (limited to 'src/radeon_crtc.c')
-rw-r--r-- | src/radeon_crtc.c | 75 |
1 files changed, 75 insertions, 0 deletions
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) |