diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2009-12-09 17:44:25 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-12-10 00:09:05 -0500 |
commit | b27b63750d912e80d61d2120c4a1664062d0f808 (patch) | |
tree | d419533d2b4c7fec1cf4ad89485da755347a33fb /drivers/gpu/drm/radeon/radeon_display.c | |
parent | 69b3b5e59bc763c30d0098ae4bbe1225c0e82a04 (diff) |
drm/radeon/kms/avivo: add support for new pll selection algo
Supported on all AVIVO-based asics.
Can be disabled via the new_pll module parameter:
new_pll=0 - disable
new_pll=1 - enable
enabled by default
[airlied: fixed to use do_div]
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_display.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index f099ce2d4cc3..a133b833e45d 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -560,6 +560,98 @@ void radeon_compute_pll(struct radeon_pll *pll, | |||
560 | *post_div_p = best_post_div; | 560 | *post_div_p = best_post_div; |
561 | } | 561 | } |
562 | 562 | ||
563 | void radeon_compute_pll_avivo(struct radeon_pll *pll, | ||
564 | uint64_t freq, | ||
565 | uint32_t *dot_clock_p, | ||
566 | uint32_t *fb_div_p, | ||
567 | uint32_t *frac_fb_div_p, | ||
568 | uint32_t *ref_div_p, | ||
569 | uint32_t *post_div_p, | ||
570 | int flags) | ||
571 | { | ||
572 | fixed20_12 m, n, frac_n, p, f_vco, f_pclk, best_freq; | ||
573 | fixed20_12 pll_out_max, pll_out_min; | ||
574 | fixed20_12 pll_in_max, pll_in_min; | ||
575 | fixed20_12 reference_freq; | ||
576 | fixed20_12 error, ffreq, a, b; | ||
577 | |||
578 | pll_out_max.full = rfixed_const(pll->pll_out_max); | ||
579 | pll_out_min.full = rfixed_const(pll->pll_out_min); | ||
580 | pll_in_max.full = rfixed_const(pll->pll_in_max); | ||
581 | pll_in_min.full = rfixed_const(pll->pll_in_min); | ||
582 | reference_freq.full = rfixed_const(pll->reference_freq); | ||
583 | do_div(freq, 10); | ||
584 | ffreq.full = rfixed_const(freq); | ||
585 | error.full = rfixed_const(100 * 100); | ||
586 | |||
587 | /* max p */ | ||
588 | p.full = rfixed_div(pll_out_max, ffreq); | ||
589 | p.full = rfixed_floor(p); | ||
590 | |||
591 | /* min m */ | ||
592 | m.full = rfixed_div(reference_freq, pll_in_max); | ||
593 | m.full = rfixed_ceil(m); | ||
594 | |||
595 | while (1) { | ||
596 | n.full = rfixed_div(ffreq, reference_freq); | ||
597 | n.full = rfixed_mul(n, m); | ||
598 | n.full = rfixed_mul(n, p); | ||
599 | |||
600 | f_vco.full = rfixed_div(n, m); | ||
601 | f_vco.full = rfixed_mul(f_vco, reference_freq); | ||
602 | |||
603 | f_pclk.full = rfixed_div(f_vco, p); | ||
604 | |||
605 | if (f_pclk.full > ffreq.full) | ||
606 | error.full = f_pclk.full - ffreq.full; | ||
607 | else | ||
608 | error.full = ffreq.full - f_pclk.full; | ||
609 | error.full = rfixed_div(error, f_pclk); | ||
610 | a.full = rfixed_const(100 * 100); | ||
611 | error.full = rfixed_mul(error, a); | ||
612 | |||
613 | a.full = rfixed_mul(m, p); | ||
614 | a.full = rfixed_div(n, a); | ||
615 | best_freq.full = rfixed_mul(reference_freq, a); | ||
616 | |||
617 | if (rfixed_trunc(error) < 25) | ||
618 | break; | ||
619 | |||
620 | a.full = rfixed_const(1); | ||
621 | m.full = m.full + a.full; | ||
622 | a.full = rfixed_div(reference_freq, m); | ||
623 | if (a.full >= pll_in_min.full) | ||
624 | continue; | ||
625 | |||
626 | m.full = rfixed_div(reference_freq, pll_in_max); | ||
627 | m.full = rfixed_ceil(m); | ||
628 | a.full= rfixed_const(1); | ||
629 | p.full = p.full - a.full; | ||
630 | a.full = rfixed_mul(p, ffreq); | ||
631 | if (a.full >= pll_out_min.full) | ||
632 | continue; | ||
633 | else { | ||
634 | DRM_ERROR("Unable to find pll dividers\n"); | ||
635 | break; | ||
636 | } | ||
637 | } | ||
638 | |||
639 | a.full = rfixed_const(10); | ||
640 | b.full = rfixed_mul(n, a); | ||
641 | |||
642 | frac_n.full = rfixed_floor(n); | ||
643 | frac_n.full = rfixed_mul(frac_n, a); | ||
644 | frac_n.full = b.full - frac_n.full; | ||
645 | |||
646 | *dot_clock_p = rfixed_trunc(best_freq); | ||
647 | *fb_div_p = rfixed_trunc(n); | ||
648 | *frac_fb_div_p = rfixed_trunc(frac_n); | ||
649 | *ref_div_p = rfixed_trunc(m); | ||
650 | *post_div_p = rfixed_trunc(p); | ||
651 | |||
652 | DRM_DEBUG("%u %d.%d, %d, %d\n", *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p); | ||
653 | } | ||
654 | |||
563 | static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) | 655 | static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) |
564 | { | 656 | { |
565 | struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); | 657 | struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); |