New PLL algo for avivo cards.  Hopefully will help with
blinking/flashing problems due to bad plls.  Depends on the fixed
point floor and ceil functions provided in the avivo bandwidth patch
from earlier today.  Please test and let me know how it goes.  I
haven't seen any regressions here on my hardware, but I don't have any
problematic monitors. new_pll module option can be set to 0 to restore
the old behavior.

Alex

>From c2d895883eabe1fdff267ba22befe23f6b59918f Mon Sep 17 00:00:00 2001
From: Alex Deucher <alexdeuc...@gmail.com>
Date: Wed, 9 Dec 2009 17:44:25 -0500
Subject: [PATCH] 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

Signed-off-by: Alex Deucher <alexdeuc...@gmail.com>
---
 drivers/gpu/drm/radeon/atombios_crtc.c   |   14 ++++-
 drivers/gpu/drm/radeon/radeon.h          |    1 +
 drivers/gpu/drm/radeon/radeon_atombios.c |    3 +-
 drivers/gpu/drm/radeon/radeon_display.c  |   93 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon_drv.c      |    4 +
 drivers/gpu/drm/radeon/radeon_mode.h     |    9 +++
 6 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c
b/drivers/gpu/drm/radeon/atombios_crtc.c
index 3b8d079..5f97dd2 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -530,8 +530,18 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc,
struct drm_display_mode *mode)
        else
                pll = &rdev->clock.p2pll;

-       radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, 
&frac_fb_div,
-                          &ref_div, &post_div, pll_flags);
+       if (ASIC_IS_AVIVO(rdev)) {
+               if (radeon_new_pll)
+                       radeon_compute_pll_avivo(pll, adjusted_clock, 
&pll_clock,
+                                                &fb_div, &frac_fb_div,
+                                                &ref_div, &post_div, 
pll_flags);
+               else
+                       radeon_compute_pll(pll, adjusted_clock, &pll_clock,
+                                          &fb_div, &frac_fb_div,
+                                          &ref_div, &post_div, pll_flags);
+       } else
+               radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, 
&frac_fb_div,
+                                  &ref_div, &post_div, pll_flags);

        index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
        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 a33e379..e17a3b9 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -88,6 +88,7 @@ extern int radeon_benchmarking;
 extern int radeon_testing;
 extern int radeon_connector_table;
 extern int radeon_tv;
+extern int radeon_new_pll;

 /*
  * 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 b762a57..6b9dc6c 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -867,7 +867,8 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
                         * pre-DCE 3.0 r6xx hardware.  This might need to be 
adjusted per
                         * family.
                         */
-                       p1pll->pll_out_min = 64800;
+                       if (!radeon_new_pll)
+                               p1pll->pll_out_min = 64800;
                }

                p1pll->pll_in_min =
diff --git a/drivers/gpu/drm/radeon/radeon_display.c
b/drivers/gpu/drm/radeon/radeon_display.c
index a2d40d8..50b4676 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -560,6 +560,99 @@ void radeon_compute_pll(struct radeon_pll *pll,
        *post_div_p = best_post_div;
 }

+void radeon_compute_pll_avivo(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,
+                             int flags)
+{
+       fixed20_12 m, n, frac_n, p, f_vco, f_pclk, best_freq;
+       fixed20_12 pll_out_max, pll_out_min;
+       fixed20_12 pll_in_max, pll_in_min;
+       fixed20_12 reference_freq;
+       fixed20_12 error, ffreq, a, b;
+
+       DRM_DEBUG("requested freq: %u\n", freq);
+
+       pll_out_max.full = rfixed_const(pll->pll_out_max);
+       pll_out_min.full = rfixed_const(pll->pll_out_min);
+       pll_in_max.full = rfixed_const(pll->pll_in_max);
+       pll_in_min.full = rfixed_const(pll->pll_in_min);
+       reference_freq.full = rfixed_const(pll->reference_freq);
+       ffreq.full = rfixed_const(freq / 10);
+       error.full = rfixed_const(100 * 100);
+
+       /* max p */
+       p.full = rfixed_div(pll_out_max, ffreq);
+       p.full = rfixed_floor(p);
+
+       /* min m */
+       m.full = rfixed_div(reference_freq, pll_in_max);
+       m.full = rfixed_ceil(m);
+
+       while (1) {
+               n.full = rfixed_div(ffreq, reference_freq);
+               n.full = rfixed_mul(n, m);
+               n.full = rfixed_mul(n, p);
+
+               f_vco.full = rfixed_div(n, m);
+               f_vco.full = rfixed_mul(f_vco, reference_freq);
+
+               f_pclk.full = rfixed_div(f_vco, p);
+
+               if (f_pclk.full > ffreq.full)
+                       error.full = f_pclk.full - ffreq.full;
+               else
+                       error.full = ffreq.full - f_pclk.full;
+               error.full = rfixed_div(error, f_pclk);
+               a.full = rfixed_const(100 * 100);
+               error.full = rfixed_mul(error, a);
+
+               a.full = rfixed_mul(m, p);
+               a.full = rfixed_div(n, a);
+               best_freq.full = rfixed_mul(reference_freq, a);
+
+               if (rfixed_trunc(error) < 25)
+                       break;
+
+               a.full = rfixed_const(1);
+               m.full = m.full + a.full;
+               a.full = rfixed_div(reference_freq, m);
+               if (a.full >= pll_in_min.full)
+                       continue;
+
+               m.full = rfixed_div(reference_freq, pll_in_max);
+               m.full = rfixed_ceil(m);
+               a.full= rfixed_const(1);
+               p.full = p.full - a.full;
+               a.full = rfixed_mul(p, ffreq);
+               if (a.full >= pll_out_min.full)
+                       continue;
+               else {
+                       DRM_ERROR("Unable to find pll dividers\n");
+                       break;
+               }
+       }
+
+       a.full = rfixed_const(10);
+       b.full = rfixed_mul(n, a);
+
+       frac_n.full = rfixed_floor(n);
+       frac_n.full = rfixed_mul(frac_n, a);
+       frac_n.full = b.full - frac_n.full;
+
+       *dot_clock_p = rfixed_trunc(best_freq);
+       *fb_div_p = rfixed_trunc(n);
+       *frac_fb_div_p = rfixed_trunc(frac_n);
+       *ref_div_p = rfixed_trunc(m);
+       *post_div_p = rfixed_trunc(p);
+
+       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);
+}
+
 static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
        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 7f50fb8..2807724 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;
 int radeon_testing = 0;
 int radeon_connector_table = 0;
 int radeon_tv = 1;
+int radeon_new_pll = 1;

 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -120,6 +121,9 @@ module_param_named(connector_table,
radeon_connector_table, int, 0444);
 MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
 module_param_named(tv, radeon_tv, int, 0444);

+MODULE_PARM_DESC(r4xx_atom, "Select new PLL code for AVIVO chips");
+module_param_named(new_pll, radeon_new_pll, int, 0444);
+
 static int radeon_suspend(struct drm_device *dev, pm_message_t state)
 {
        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 42fa3b0..ced1fa4 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -445,6 +445,15 @@ extern void radeon_compute_pll(struct radeon_pll *pll,
                               uint32_t *post_div_p,
                               int flags);

+extern void radeon_compute_pll_avivo(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,
+                                    int flags);
+
 extern void radeon_setup_encoder_clones(struct drm_device *dev);

 struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device
*dev, int bios_index);
-- 
1.5.6.3
From c2d895883eabe1fdff267ba22befe23f6b59918f Mon Sep 17 00:00:00 2001
From: Alex Deucher <alexdeuc...@gmail.com>
Date: Wed, 9 Dec 2009 17:44:25 -0500
Subject: [PATCH] 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

Signed-off-by: Alex Deucher <alexdeuc...@gmail.com>
---
 drivers/gpu/drm/radeon/atombios_crtc.c   |   14 ++++-
 drivers/gpu/drm/radeon/radeon.h          |    1 +
 drivers/gpu/drm/radeon/radeon_atombios.c |    3 +-
 drivers/gpu/drm/radeon/radeon_display.c  |   93 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon_drv.c      |    4 +
 drivers/gpu/drm/radeon/radeon_mode.h     |    9 +++
 6 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 3b8d079..5f97dd2 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -530,8 +530,18 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
 	else
 		pll = &rdev->clock.p2pll;
 
-	radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
-			   &ref_div, &post_div, pll_flags);
+	if (ASIC_IS_AVIVO(rdev)) {
+		if (radeon_new_pll)
+			radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock,
+						 &fb_div, &frac_fb_div,
+						 &ref_div, &post_div, pll_flags);
+		else
+			radeon_compute_pll(pll, adjusted_clock, &pll_clock,
+					   &fb_div, &frac_fb_div,
+					   &ref_div, &post_div, pll_flags);
+	} else
+		radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
+				   &ref_div, &post_div, pll_flags);
 
 	index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
 	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 a33e379..e17a3b9 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -88,6 +88,7 @@ extern int radeon_benchmarking;
 extern int radeon_testing;
 extern int radeon_connector_table;
 extern int radeon_tv;
+extern int radeon_new_pll;
 
 /*
  * 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 b762a57..6b9dc6c 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -867,7 +867,8 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
 			 * pre-DCE 3.0 r6xx hardware.  This might need to be adjusted per
 			 * family.
 			 */
-			p1pll->pll_out_min = 64800;
+			if (!radeon_new_pll)
+				p1pll->pll_out_min = 64800;
 		}
 
 		p1pll->pll_in_min =
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index a2d40d8..50b4676 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -560,6 +560,99 @@ void radeon_compute_pll(struct radeon_pll *pll,
 	*post_div_p = best_post_div;
 }
 
+void radeon_compute_pll_avivo(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,
+			      int flags)
+{
+	fixed20_12 m, n, frac_n, p, f_vco, f_pclk, best_freq;
+	fixed20_12 pll_out_max, pll_out_min;
+	fixed20_12 pll_in_max, pll_in_min;
+	fixed20_12 reference_freq;
+	fixed20_12 error, ffreq, a, b;
+
+	DRM_DEBUG("requested freq: %u\n", freq);
+
+	pll_out_max.full = rfixed_const(pll->pll_out_max);
+	pll_out_min.full = rfixed_const(pll->pll_out_min);
+	pll_in_max.full = rfixed_const(pll->pll_in_max);
+	pll_in_min.full = rfixed_const(pll->pll_in_min);
+	reference_freq.full = rfixed_const(pll->reference_freq);
+	ffreq.full = rfixed_const(freq / 10);
+	error.full = rfixed_const(100 * 100);
+
+	/* max p */
+	p.full = rfixed_div(pll_out_max, ffreq);
+	p.full = rfixed_floor(p);
+
+	/* min m */
+	m.full = rfixed_div(reference_freq, pll_in_max);
+	m.full = rfixed_ceil(m);
+
+	while (1) {
+		n.full = rfixed_div(ffreq, reference_freq);
+		n.full = rfixed_mul(n, m);
+		n.full = rfixed_mul(n, p);
+
+		f_vco.full = rfixed_div(n, m);
+		f_vco.full = rfixed_mul(f_vco, reference_freq);
+
+		f_pclk.full = rfixed_div(f_vco, p);
+
+		if (f_pclk.full > ffreq.full)
+			error.full = f_pclk.full - ffreq.full;
+		else
+			error.full = ffreq.full - f_pclk.full;
+		error.full = rfixed_div(error, f_pclk);
+		a.full = rfixed_const(100 * 100);
+		error.full = rfixed_mul(error, a);
+
+		a.full = rfixed_mul(m, p);
+		a.full = rfixed_div(n, a);
+		best_freq.full = rfixed_mul(reference_freq, a);
+
+		if (rfixed_trunc(error) < 25)
+			break;
+
+		a.full = rfixed_const(1);
+		m.full = m.full + a.full;
+		a.full = rfixed_div(reference_freq, m);
+		if (a.full >= pll_in_min.full)
+			continue;
+
+		m.full = rfixed_div(reference_freq, pll_in_max);
+		m.full = rfixed_ceil(m);
+		a.full= rfixed_const(1);
+		p.full = p.full - a.full;
+		a.full = rfixed_mul(p, ffreq);
+		if (a.full >= pll_out_min.full)
+			continue;
+		else {
+			DRM_ERROR("Unable to find pll dividers\n");
+			break;
+		}
+	}
+
+	a.full = rfixed_const(10);
+	b.full = rfixed_mul(n, a);
+
+	frac_n.full = rfixed_floor(n);
+	frac_n.full = rfixed_mul(frac_n, a);
+	frac_n.full = b.full - frac_n.full;
+
+	*dot_clock_p = rfixed_trunc(best_freq);
+	*fb_div_p = rfixed_trunc(n);
+	*frac_fb_div_p = rfixed_trunc(frac_n);
+	*ref_div_p = rfixed_trunc(m);
+	*post_div_p = rfixed_trunc(p);
+
+	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);
+}
+
 static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
 	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 7f50fb8..2807724 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;
 int radeon_testing = 0;
 int radeon_connector_table = 0;
 int radeon_tv = 1;
+int radeon_new_pll = 1;
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -120,6 +121,9 @@ module_param_named(connector_table, radeon_connector_table, int, 0444);
 MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
 module_param_named(tv, radeon_tv, int, 0444);
 
+MODULE_PARM_DESC(r4xx_atom, "Select new PLL code for AVIVO chips");
+module_param_named(new_pll, radeon_new_pll, int, 0444);
+
 static int radeon_suspend(struct drm_device *dev, pm_message_t state)
 {
 	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 42fa3b0..ced1fa4 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -445,6 +445,15 @@ extern void radeon_compute_pll(struct radeon_pll *pll,
 			       uint32_t *post_div_p,
 			       int flags);
 
+extern void radeon_compute_pll_avivo(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,
+				     int flags);
+
 extern void radeon_setup_encoder_clones(struct drm_device *dev);
 
 struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index);
-- 
1.5.6.3

------------------------------------------------------------------------------
Return on Information:
Google Enterprise Search pays you back
Get the facts.
http://p.sf.net/sfu/google-dev2dev
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to