summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/radeon/radeon_display.c
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2010-09-29 11:37:41 -0400
committerDave Airlie <airlied@redhat.com>2010-10-06 11:46:25 +1000
commit48dfaaeb6637240af3089bf9b7a00a6cf24e0182 (patch)
tree7f82ed838581ff1f8db41e4a9d3c41cb47dc46cc /drivers/gpu/drm/radeon/radeon_display.c
parentf28488c282d8916b9b6190cc41714815bbaf97d5 (diff)
drm/radeon/kms: remove new pll algo
The recent changes to the old algo (prefer high post div) coupled with the range and precision limitations of using fixed point with the new algo make the new algo less useful. So drop the new algo. This should work as well or better than the old new/old combinations and simplifies the code a lot. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=30218 among others. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_display.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c222
1 files changed, 7 insertions, 215 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 20464659d3fa..325a07391b3c 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -454,13 +454,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
return n;
}
-static void radeon_compute_pll_legacy(struct radeon_pll *pll,
- uint64_t freq,
- uint32_t *dot_clock_p,
- uint32_t *fb_div_p,
- uint32_t *frac_fb_div_p,
- uint32_t *ref_div_p,
- uint32_t *post_div_p)
+void radeon_compute_pll(struct radeon_pll *pll,
+ uint64_t freq,
+ uint32_t *dot_clock_p,
+ uint32_t *fb_div_p,
+ uint32_t *frac_fb_div_p,
+ uint32_t *ref_div_p,
+ uint32_t *post_div_p)
{
uint32_t min_ref_div = pll->min_ref_div;
uint32_t max_ref_div = pll->max_ref_div;
@@ -609,214 +609,6 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
*post_div_p = best_post_div;
}
-static bool
-calc_fb_div(struct radeon_pll *pll,
- uint32_t freq,
- uint32_t post_div,
- uint32_t ref_div,
- uint32_t *fb_div,
- uint32_t *fb_div_frac)
-{
- fixed20_12 feedback_divider, a, b;
- u32 vco_freq;
-
- vco_freq = freq * post_div;
- /* feedback_divider = vco_freq * ref_div / pll->reference_freq; */
- a.full = dfixed_const(pll->reference_freq);
- feedback_divider.full = dfixed_const(vco_freq);
- feedback_divider.full = dfixed_div(feedback_divider, a);
- a.full = dfixed_const(ref_div);
- feedback_divider.full = dfixed_mul(feedback_divider, a);
-
- if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
- /* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */
- a.full = dfixed_const(10);
- feedback_divider.full = dfixed_mul(feedback_divider, a);
- feedback_divider.full += dfixed_const_half(0);
- feedback_divider.full = dfixed_floor(feedback_divider);
- feedback_divider.full = dfixed_div(feedback_divider, a);
-
- /* *fb_div = floor(feedback_divider); */
- a.full = dfixed_floor(feedback_divider);
- *fb_div = dfixed_trunc(a);
- /* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */
- a.full = dfixed_const(10);
- b.full = dfixed_mul(feedback_divider, a);
-
- feedback_divider.full = dfixed_floor(feedback_divider);
- feedback_divider.full = dfixed_mul(feedback_divider, a);
- feedback_divider.full = b.full - feedback_divider.full;
- *fb_div_frac = dfixed_trunc(feedback_divider);
- } else {
- /* *fb_div = floor(feedback_divider + 0.5); */
- feedback_divider.full += dfixed_const_half(0);
- feedback_divider.full = dfixed_floor(feedback_divider);
-
- *fb_div = dfixed_trunc(feedback_divider);
- *fb_div_frac = 0;
- }
-
- if (((*fb_div) < pll->min_feedback_div) || ((*fb_div) > pll->max_feedback_div))
- return false;
- else
- return true;
-}
-
-static bool
-calc_fb_ref_div(struct radeon_pll *pll,
- uint32_t freq,
- uint32_t post_div,
- uint32_t *fb_div,
- uint32_t *fb_div_frac,
- uint32_t *ref_div)
-{
- fixed20_12 ffreq, max_error, error, pll_out, a;
- u32 vco;
- u32 pll_out_min, pll_out_max;
-
- if (pll->flags & RADEON_PLL_IS_LCD) {
- pll_out_min = pll->lcd_pll_out_min;
- pll_out_max = pll->lcd_pll_out_max;
- } else {
- pll_out_min = pll->pll_out_min;
- pll_out_max = pll->pll_out_max;
- }
-
- ffreq.full = dfixed_const(freq);
- /* max_error = ffreq * 0.0025; */
- a.full = dfixed_const(400);
- max_error.full = dfixed_div(ffreq, a);
-
- for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) {
- if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) {
- vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
- vco = vco / ((*ref_div) * 10);
-
- if ((vco < pll_out_min) || (vco > pll_out_max))
- continue;
-
- /* pll_out = vco / post_div; */
- a.full = dfixed_const(post_div);
- pll_out.full = dfixed_const(vco);
- pll_out.full = dfixed_div(pll_out, a);
-
- if (pll_out.full >= ffreq.full) {
- error.full = pll_out.full - ffreq.full;
- if (error.full <= max_error.full)
- return true;
- }
- }
- }
- return false;
-}
-
-static void radeon_compute_pll_new(struct radeon_pll *pll,
- uint64_t freq,
- uint32_t *dot_clock_p,
- uint32_t *fb_div_p,
- uint32_t *frac_fb_div_p,
- uint32_t *ref_div_p,
- uint32_t *post_div_p)
-{
- u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
- u32 best_freq = 0, vco_frequency;
- u32 pll_out_min, pll_out_max;
-
- if (pll->flags & RADEON_PLL_IS_LCD) {
- pll_out_min = pll->lcd_pll_out_min;
- pll_out_max = pll->lcd_pll_out_max;
- } else {
- pll_out_min = pll->pll_out_min;
- pll_out_max = pll->pll_out_max;
- }
-
- /* freq = freq / 10; */
- do_div(freq, 10);
-
- if (pll->flags & RADEON_PLL_USE_POST_DIV) {
- post_div = pll->post_div;
- if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div))
- goto done;
-
- vco_frequency = freq * post_div;
- if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
- goto done;
-
- if (pll->flags & RADEON_PLL_USE_REF_DIV) {
- ref_div = pll->reference_div;
- if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
- goto done;
- if (!calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
- goto done;
- }
- } else {
- for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) {
- if (pll->flags & RADEON_PLL_LEGACY) {
- if ((post_div == 5) ||
- (post_div == 7) ||
- (post_div == 9) ||
- (post_div == 10) ||
- (post_div == 11))
- continue;
- }
-
- if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
- continue;
-
- vco_frequency = freq * post_div;
- if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
- continue;
- if (pll->flags & RADEON_PLL_USE_REF_DIV) {
- ref_div = pll->reference_div;
- if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
- goto done;
- if (calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
- break;
- } else {
- if (calc_fb_ref_div(pll, freq, post_div, &fb_div, &fb_div_frac, &ref_div))
- break;
- }
- }
- }
-
- best_freq = pll->reference_freq * 10 * fb_div;
- best_freq += pll->reference_freq * fb_div_frac;
- best_freq = best_freq / (ref_div * post_div);
-
-done:
- if (best_freq == 0)
- DRM_ERROR("Couldn't find valid PLL dividers\n");
-
- *dot_clock_p = best_freq / 10;
- *fb_div_p = fb_div;
- *frac_fb_div_p = fb_div_frac;
- *ref_div_p = ref_div;
- *post_div_p = post_div;
-
- DRM_DEBUG_KMS("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
-}
-
-void radeon_compute_pll(struct radeon_pll *pll,
- uint64_t freq,
- uint32_t *dot_clock_p,
- uint32_t *fb_div_p,
- uint32_t *frac_fb_div_p,
- uint32_t *ref_div_p,
- uint32_t *post_div_p)
-{
- switch (pll->algo) {
- case PLL_ALGO_NEW:
- radeon_compute_pll_new(pll, freq, dot_clock_p, fb_div_p,
- frac_fb_div_p, ref_div_p, post_div_p);
- break;
- case PLL_ALGO_LEGACY:
- default:
- radeon_compute_pll_legacy(pll, freq, dot_clock_p, fb_div_p,
- frac_fb_div_p, ref_div_p, post_div_p);
- break;
- }
-}
-
static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
{
struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);