aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2010-02-23 03:24:38 -0500
committerDave Airlie <airlied@redhat.com>2010-02-24 20:38:06 -0500
commit383be5d1789d9a7a2e77dca1cb0aca89507d069e (patch)
treee99787c96586748c9ce78fbd10d8859c648fabc0 /drivers
parent939461d59d6ac4e5142f767d24810c9b4b5caa38 (diff)
drm/radeon/kms: update new pll algo
- add support for pre-avivo chips - add support for fixed post/ref dividers - add support for non-fractional fb dividers By default avivo chips use the new algo and pre-avivo chips use the old algo. Use the "new_pll" module option to toggle between them. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c12
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c12
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c232
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h2
6 files changed, 178 insertions, 89 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 0ec6934c3a26..dd9fdf560611 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -438,12 +438,16 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
438 438
439 /* select the PLL algo */ 439 /* select the PLL algo */
440 if (ASIC_IS_AVIVO(rdev)) { 440 if (ASIC_IS_AVIVO(rdev)) {
441 if (radeon_new_pll) 441 if (radeon_new_pll == 0)
442 pll->algo = PLL_ALGO_AVIVO; 442 pll->algo = PLL_ALGO_LEGACY;
443 else
444 pll->algo = PLL_ALGO_NEW;
445 } else {
446 if (radeon_new_pll == 1)
447 pll->algo = PLL_ALGO_NEW;
443 else 448 else
444 pll->algo = PLL_ALGO_LEGACY; 449 pll->algo = PLL_ALGO_LEGACY;
445 } else 450 }
446 pll->algo = PLL_ALGO_LEGACY;
447 451
448 if (ASIC_IS_AVIVO(rdev)) { 452 if (ASIC_IS_AVIVO(rdev)) {
449 if ((rdev->family == CHIP_RS600) || 453 if ((rdev->family == CHIP_RS600) ||
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 33aed6c2d41a..6f8619cd1a0d 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1191,12 +1191,16 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
1191 lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id); 1191 lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id);
1192 1192
1193 if (ASIC_IS_AVIVO(rdev)) { 1193 if (ASIC_IS_AVIVO(rdev)) {
1194 if (radeon_new_pll) 1194 if (radeon_new_pll == 0)
1195 lvds->pll_algo = PLL_ALGO_AVIVO; 1195 lvds->pll_algo = PLL_ALGO_LEGACY;
1196 else
1197 lvds->pll_algo = PLL_ALGO_NEW;
1198 } else {
1199 if (radeon_new_pll == 1)
1200 lvds->pll_algo = PLL_ALGO_NEW;
1196 else 1201 else
1197 lvds->pll_algo = PLL_ALGO_LEGACY; 1202 lvds->pll_algo = PLL_ALGO_LEGACY;
1198 } else 1203 }
1199 lvds->pll_algo = PLL_ALGO_LEGACY;
1200 1204
1201 /* LVDS quirks */ 1205 /* LVDS quirks */
1202 radeon_atom_apply_lvds_quirks(dev, lvds); 1206 radeon_atom_apply_lvds_quirks(dev, lvds);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 257827806aee..e35cc3da8f22 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -603,95 +603,173 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
603 *post_div_p = best_post_div; 603 *post_div_p = best_post_div;
604} 604}
605 605
606static void radeon_compute_pll_avivo(struct radeon_pll *pll, 606static bool
607 uint64_t freq, 607calc_fb_div(struct radeon_pll *pll,
608 uint32_t *dot_clock_p, 608 uint32_t freq,
609 uint32_t *fb_div_p, 609 uint32_t post_div,
610 uint32_t *frac_fb_div_p, 610 uint32_t ref_div,
611 uint32_t *ref_div_p, 611 uint32_t *fb_div,
612 uint32_t *post_div_p) 612 uint32_t *fb_div_frac)
613{ 613{
614 fixed20_12 m, n, frac_n, p, f_vco, f_pclk, best_freq; 614 fixed20_12 feedback_divider, a, b;
615 fixed20_12 pll_out_max, pll_out_min; 615 u32 vco_freq;
616 fixed20_12 pll_in_max, pll_in_min; 616
617 fixed20_12 reference_freq; 617 vco_freq = freq * post_div;
618 fixed20_12 error, ffreq, a, b; 618 /* feedback_divider = vco_freq * ref_div / pll->reference_freq; */
619 619 a.full = rfixed_const(pll->reference_freq);
620 pll_out_max.full = rfixed_const(pll->pll_out_max); 620 feedback_divider.full = rfixed_const(vco_freq);
621 pll_out_min.full = rfixed_const(pll->pll_out_min); 621 feedback_divider.full = rfixed_div(feedback_divider, a);
622 pll_in_max.full = rfixed_const(pll->pll_in_max); 622 a.full = rfixed_const(ref_div);
623 pll_in_min.full = rfixed_const(pll->pll_in_min); 623 feedback_divider.full = rfixed_mul(feedback_divider, a);
624 reference_freq.full = rfixed_const(pll->reference_freq); 624
625 do_div(freq, 10); 625 if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
626 /* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */
627 a.full = rfixed_const(10);
628 feedback_divider.full = rfixed_mul(feedback_divider, a);
629 feedback_divider.full += rfixed_const_half(0);
630 feedback_divider.full = rfixed_floor(feedback_divider);
631 feedback_divider.full = rfixed_div(feedback_divider, a);
632
633 /* *fb_div = floor(feedback_divider); */
634 a.full = rfixed_floor(feedback_divider);
635 *fb_div = rfixed_trunc(a);
636 /* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */
637 a.full = rfixed_const(10);
638 b.full = rfixed_mul(feedback_divider, a);
639
640 feedback_divider.full = rfixed_floor(feedback_divider);
641 feedback_divider.full = rfixed_mul(feedback_divider, a);
642 feedback_divider.full = b.full - feedback_divider.full;
643 *fb_div_frac = rfixed_trunc(feedback_divider);
644 } else {
645 /* *fb_div = floor(feedback_divider + 0.5); */
646 feedback_divider.full += rfixed_const_half(0);
647 feedback_divider.full = rfixed_floor(feedback_divider);
648
649 *fb_div = rfixed_trunc(feedback_divider);
650 *fb_div_frac = 0;
651 }
652
653 if (((*fb_div) < pll->min_feedback_div) || ((*fb_div) > pll->max_feedback_div))
654 return false;
655 else
656 return true;
657}
658
659static bool
660calc_fb_ref_div(struct radeon_pll *pll,
661 uint32_t freq,
662 uint32_t post_div,
663 uint32_t *fb_div,
664 uint32_t *fb_div_frac,
665 uint32_t *ref_div)
666{
667 fixed20_12 ffreq, max_error, error, pll_out, a;
668 u32 vco;
669
626 ffreq.full = rfixed_const(freq); 670 ffreq.full = rfixed_const(freq);
627 error.full = rfixed_const(100 * 100); 671 /* max_error = ffreq * 0.0025; */
672 a.full = rfixed_const(400);
673 max_error.full = rfixed_div(ffreq, a);
674
675 for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) {
676 if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) {
677 vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
678 vco = vco / ((*ref_div) * 10);
679
680 if ((vco < pll->pll_out_min) || (vco > pll->pll_out_max))
681 continue;
628 682
629 /* max p */ 683 /* pll_out = vco / post_div; */
630 p.full = rfixed_div(pll_out_max, ffreq); 684 a.full = rfixed_const(post_div);
631 p.full = rfixed_floor(p); 685 pll_out.full = rfixed_const(vco);
686 pll_out.full = rfixed_div(pll_out, a);
632 687
633 /* min m */ 688 if (pll_out.full >= ffreq.full) {
634 m.full = rfixed_div(reference_freq, pll_in_max); 689 error.full = pll_out.full - ffreq.full;
635 m.full = rfixed_ceil(m); 690 if (error.full <= max_error.full)
691 return true;
692 }
693 }
694 }
695 return false;
696}
636 697
637 while (1) { 698static void radeon_compute_pll_new(struct radeon_pll *pll,
638 n.full = rfixed_div(ffreq, reference_freq); 699 uint64_t freq,
639 n.full = rfixed_mul(n, m); 700 uint32_t *dot_clock_p,
640 n.full = rfixed_mul(n, p); 701 uint32_t *fb_div_p,
702 uint32_t *frac_fb_div_p,
703 uint32_t *ref_div_p,
704 uint32_t *post_div_p)
705{
706 u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
707 u32 best_freq = 0, vco_frequency;
641 708
642 f_vco.full = rfixed_div(n, m); 709 /* freq = freq / 10; */
643 f_vco.full = rfixed_mul(f_vco, reference_freq); 710 do_div(freq, 10);
644 711
645 f_pclk.full = rfixed_div(f_vco, p); 712 if (pll->flags & RADEON_PLL_USE_POST_DIV) {
713 post_div = pll->post_div;
714 if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div))
715 goto done;
716
717 vco_frequency = freq * post_div;
718 if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max))
719 goto done;
720
721 if (pll->flags & RADEON_PLL_USE_REF_DIV) {
722 ref_div = pll->reference_div;
723 if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
724 goto done;
725 if (!calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
726 goto done;
727 }
728 } else {
729 for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) {
730 if (pll->flags & RADEON_PLL_LEGACY) {
731 if ((post_div == 5) ||
732 (post_div == 7) ||
733 (post_div == 9) ||
734 (post_div == 10) ||
735 (post_div == 11))
736 continue;
737 }
646 738
647 if (f_pclk.full > ffreq.full) 739 if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
648 error.full = f_pclk.full - ffreq.full; 740 continue;
649 else
650 error.full = ffreq.full - f_pclk.full;
651 error.full = rfixed_div(error, f_pclk);
652 a.full = rfixed_const(100 * 100);
653 error.full = rfixed_mul(error, a);
654
655 a.full = rfixed_mul(m, p);
656 a.full = rfixed_div(n, a);
657 best_freq.full = rfixed_mul(reference_freq, a);
658
659 if (rfixed_trunc(error) < 25)
660 break;
661
662 a.full = rfixed_const(1);
663 m.full = m.full + a.full;
664 a.full = rfixed_div(reference_freq, m);
665 if (a.full >= pll_in_min.full)
666 continue;
667 741
668 m.full = rfixed_div(reference_freq, pll_in_max); 742 vco_frequency = freq * post_div;
669 m.full = rfixed_ceil(m); 743 if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max))
670 a.full= rfixed_const(1); 744 continue;
671 p.full = p.full - a.full; 745 if (pll->flags & RADEON_PLL_USE_REF_DIV) {
672 a.full = rfixed_mul(p, ffreq); 746 ref_div = pll->reference_div;
673 if (a.full >= pll_out_min.full) 747 if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
674 continue; 748 goto done;
675 else { 749 if (calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
676 DRM_ERROR("Unable to find pll dividers\n"); 750 break;
677 break; 751 } else {
752 if (calc_fb_ref_div(pll, freq, post_div, &fb_div, &fb_div_frac, &ref_div))
753 break;
754 }
678 } 755 }
679 } 756 }
680 757
681 a.full = rfixed_const(10); 758 best_freq = pll->reference_freq * 10 * fb_div;
682 b.full = rfixed_mul(n, a); 759 best_freq += pll->reference_freq * fb_div_frac;
760 best_freq = best_freq / (ref_div * post_div);
683 761
684 frac_n.full = rfixed_floor(n); 762done:
685 frac_n.full = rfixed_mul(frac_n, a); 763 if (best_freq == 0)
686 frac_n.full = b.full - frac_n.full; 764 DRM_ERROR("Couldn't find valid PLL dividers\n");
687 765
688 *dot_clock_p = rfixed_trunc(best_freq); 766 *dot_clock_p = best_freq / 10;
689 *fb_div_p = rfixed_trunc(n); 767 *fb_div_p = fb_div;
690 *frac_fb_div_p = rfixed_trunc(frac_n); 768 *frac_fb_div_p = fb_div_frac;
691 *ref_div_p = rfixed_trunc(m); 769 *ref_div_p = ref_div;
692 *post_div_p = rfixed_trunc(p); 770 *post_div_p = post_div;
693 771
694 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); 772 DRM_DEBUG("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
695} 773}
696 774
697void radeon_compute_pll(struct radeon_pll *pll, 775void radeon_compute_pll(struct radeon_pll *pll,
@@ -703,9 +781,9 @@ void radeon_compute_pll(struct radeon_pll *pll,
703 uint32_t *post_div_p) 781 uint32_t *post_div_p)
704{ 782{
705 switch (pll->algo) { 783 switch (pll->algo) {
706 case PLL_ALGO_AVIVO: 784 case PLL_ALGO_NEW:
707 radeon_compute_pll_avivo(pll, freq, dot_clock_p, fb_div_p, 785 radeon_compute_pll_new(pll, freq, dot_clock_p, fb_div_p,
708 frac_fb_div_p, ref_div_p, post_div_p); 786 frac_fb_div_p, ref_div_p, post_div_p);
709 break; 787 break;
710 case PLL_ALGO_LEGACY: 788 case PLL_ALGO_LEGACY:
711 default: 789 default:
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index a9572e6d4d64..be99d4e55a34 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -86,7 +86,7 @@ int radeon_benchmarking = 0;
86int radeon_testing = 0; 86int radeon_testing = 0;
87int radeon_connector_table = 0; 87int radeon_connector_table = 0;
88int radeon_tv = 1; 88int radeon_tv = 1;
89int radeon_new_pll = 1; 89int radeon_new_pll = -1;
90int radeon_dynpm = -1; 90int radeon_dynpm = -1;
91int radeon_audio = 1; 91int radeon_audio = 1;
92 92
@@ -123,7 +123,7 @@ module_param_named(connector_table, radeon_connector_table, int, 0444);
123MODULE_PARM_DESC(tv, "TV enable (0 = disable)"); 123MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
124module_param_named(tv, radeon_tv, int, 0444); 124module_param_named(tv, radeon_tv, int, 0444);
125 125
126MODULE_PARM_DESC(new_pll, "Select new PLL code for AVIVO chips"); 126MODULE_PARM_DESC(new_pll, "Select new PLL code");
127module_param_named(new_pll, radeon_new_pll, int, 0444); 127module_param_named(new_pll, radeon_new_pll, int, 0444);
128 128
129MODULE_PARM_DESC(dynpm, "Disable/Enable dynamic power management (1 = enable)"); 129MODULE_PARM_DESC(dynpm, "Disable/Enable dynamic power management (1 = enable)");
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 643251719f1c..df23d6a01d02 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -703,7 +703,10 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
703 pll = &rdev->clock.p1pll; 703 pll = &rdev->clock.p1pll;
704 704
705 pll->flags = RADEON_PLL_LEGACY; 705 pll->flags = RADEON_PLL_LEGACY;
706 pll->algo = PLL_ALGO_LEGACY; 706 if (radeon_new_pll == 1)
707 pll->algo = PLL_ALGO_NEW;
708 else
709 pll->algo = PLL_ALGO_LEGACY;
707 710
708 if (mode->clock > 200000) /* range limits??? */ 711 if (mode->clock > 200000) /* range limits??? */
709 pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 712 pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 8912f2e8e640..1702b820aa4d 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -133,7 +133,7 @@ struct radeon_tmds_pll {
133/* pll algo */ 133/* pll algo */
134enum radeon_pll_algo { 134enum radeon_pll_algo {
135 PLL_ALGO_LEGACY, 135 PLL_ALGO_LEGACY,
136 PLL_ALGO_AVIVO 136 PLL_ALGO_NEW
137}; 137};
138 138
139struct radeon_pll { 139struct radeon_pll {