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 | |
| 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>
| -rw-r--r-- | drivers/gpu/drm/radeon/atombios_crtc.c | 14 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 92 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_drv.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 9 |
6 files changed, 120 insertions, 3 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 6d82417fb903..260fcf59f00c 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
| @@ -499,8 +499,18 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) | |||
| 499 | else | 499 | else |
| 500 | pll = &rdev->clock.p2pll; | 500 | pll = &rdev->clock.p2pll; |
| 501 | 501 | ||
| 502 | radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, | 502 | if (ASIC_IS_AVIVO(rdev)) { |
| 503 | &ref_div, &post_div, pll_flags); | 503 | if (radeon_new_pll) |
| 504 | radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, | ||
| 505 | &fb_div, &frac_fb_div, | ||
| 506 | &ref_div, &post_div, pll_flags); | ||
| 507 | else | ||
| 508 | radeon_compute_pll(pll, adjusted_clock, &pll_clock, | ||
| 509 | &fb_div, &frac_fb_div, | ||
| 510 | &ref_div, &post_div, pll_flags); | ||
| 511 | } else | ||
| 512 | radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, | ||
| 513 | &ref_div, &post_div, pll_flags); | ||
| 504 | 514 | ||
| 505 | index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); | 515 | index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); |
| 506 | atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, | 516 | atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5941e7d2d7ff..c938bb54123c 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
| @@ -88,6 +88,7 @@ extern int radeon_benchmarking; | |||
| 88 | extern int radeon_testing; | 88 | extern int radeon_testing; |
| 89 | extern int radeon_connector_table; | 89 | extern int radeon_connector_table; |
| 90 | extern int radeon_tv; | 90 | extern int radeon_tv; |
| 91 | extern int radeon_new_pll; | ||
| 91 | 92 | ||
| 92 | /* | 93 | /* |
| 93 | * Copy from radeon_drv.h so we don't have to include both and have conflicting | 94 | * Copy from radeon_drv.h so we don't have to include both and have conflicting |
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 8737adf6d386..12a0c760e7ff 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
| @@ -871,7 +871,8 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) | |||
| 871 | * pre-DCE 3.0 r6xx hardware. This might need to be adjusted per | 871 | * pre-DCE 3.0 r6xx hardware. This might need to be adjusted per |
| 872 | * family. | 872 | * family. |
| 873 | */ | 873 | */ |
| 874 | p1pll->pll_out_min = 64800; | 874 | if (!radeon_new_pll) |
| 875 | p1pll->pll_out_min = 64800; | ||
| 875 | } | 876 | } |
| 876 | 877 | ||
| 877 | p1pll->pll_in_min = | 878 | p1pll->pll_in_min = |
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); |
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 7f50fb864af8..28077247f4f3 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c | |||
| @@ -86,6 +86,7 @@ int radeon_benchmarking = 0; | |||
| 86 | int radeon_testing = 0; | 86 | int radeon_testing = 0; |
| 87 | int radeon_connector_table = 0; | 87 | int radeon_connector_table = 0; |
| 88 | int radeon_tv = 1; | 88 | int radeon_tv = 1; |
| 89 | int radeon_new_pll = 1; | ||
| 89 | 90 | ||
| 90 | MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); | 91 | MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); |
| 91 | module_param_named(no_wb, radeon_no_wb, int, 0444); | 92 | module_param_named(no_wb, radeon_no_wb, int, 0444); |
| @@ -120,6 +121,9 @@ module_param_named(connector_table, radeon_connector_table, int, 0444); | |||
| 120 | MODULE_PARM_DESC(tv, "TV enable (0 = disable)"); | 121 | MODULE_PARM_DESC(tv, "TV enable (0 = disable)"); |
| 121 | module_param_named(tv, radeon_tv, int, 0444); | 122 | module_param_named(tv, radeon_tv, int, 0444); |
| 122 | 123 | ||
| 124 | MODULE_PARM_DESC(r4xx_atom, "Select new PLL code for AVIVO chips"); | ||
| 125 | module_param_named(new_pll, radeon_new_pll, int, 0444); | ||
| 126 | |||
| 123 | static int radeon_suspend(struct drm_device *dev, pm_message_t state) | 127 | static int radeon_suspend(struct drm_device *dev, pm_message_t state) |
| 124 | { | 128 | { |
| 125 | drm_radeon_private_t *dev_priv = dev->dev_private; | 129 | drm_radeon_private_t *dev_priv = dev->dev_private; |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 15ec7ca18a95..44d4b652ea12 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
| @@ -437,6 +437,15 @@ extern void radeon_compute_pll(struct radeon_pll *pll, | |||
| 437 | uint32_t *post_div_p, | 437 | uint32_t *post_div_p, |
| 438 | int flags); | 438 | int flags); |
| 439 | 439 | ||
| 440 | extern void radeon_compute_pll_avivo(struct radeon_pll *pll, | ||
| 441 | uint64_t freq, | ||
| 442 | uint32_t *dot_clock_p, | ||
| 443 | uint32_t *fb_div_p, | ||
| 444 | uint32_t *frac_fb_div_p, | ||
| 445 | uint32_t *ref_div_p, | ||
| 446 | uint32_t *post_div_p, | ||
| 447 | int flags); | ||
| 448 | |||
| 440 | extern void radeon_setup_encoder_clones(struct drm_device *dev); | 449 | extern void radeon_setup_encoder_clones(struct drm_device *dev); |
| 441 | 450 | ||
| 442 | struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index); | 451 | struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index); |
