xf86-video-ati: Branch 'master'

Alex Deucher agd5f at kemper.freedesktop.org
Mon Jun 23 12:54:06 PDT 2008


 src/atombios_crtc.c |    3 -
 src/legacy_crtc.c   |    2 -
 src/radeon.h        |    2 -
 src/radeon_crtc.c   |   99 ++++++++++++++++++++++++++++++++++++----------------
 4 files changed, 72 insertions(+), 34 deletions(-)

New commits:
commit 72feaa37ea07620f5f2ead438dbc72a1c8883cd3
Author: Jiří Paleček <jpalecek at web.de>
Date:   Mon Jun 23 15:53:58 2008 -0400

    RADEON: PLL tweaks
    
    Patch from Jiří Paleček (see debian bug 465864) with some tweaks
    by me.
    
    - abort rather than programming bad dividers if no pll dividers can be found
    - improve the pll selection algorithm
    - in general, prefer lower ref dividers
    
    I've tested this patch on a wide variety of chips (r1xx-r6xx) and clocks.

diff --git a/src/atombios_crtc.c b/src/atombios_crtc.c
index b5b7ca8..363addf 100644
--- a/src/atombios_crtc.c
+++ b/src/atombios_crtc.c
@@ -185,8 +185,7 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode, int pll_flags)
     if (IS_AVIVO_VARIANT) {
 	uint32_t temp;
 
-	if (IS_DCE3_VARIANT)
-	    pll_flags |= RADEON_PLL_DCE3;
+	pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
 
 	RADEONComputePLL(&info->pll, mode->Clock, &temp, &fb_div, &ref_div, &post_div, pll_flags);
 	sclock = temp;
diff --git a/src/legacy_crtc.c b/src/legacy_crtc.c
index 747bc6e..17ae8c4 100644
--- a/src/legacy_crtc.c
+++ b/src/legacy_crtc.c
@@ -1730,7 +1730,7 @@ legacy_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
     RADEONInfoPtr info = RADEONPTR(pScrn);
     int i = 0;
     double dot_clock = 0;
-    int pll_flags = RADEON_PLL_LEGACY;
+    int pll_flags = RADEON_PLL_LEGACY | RADEON_PLL_PREFER_LOW_REF_DIV;
     Bool update_tv_routing = FALSE;
     Bool tilingChanged = FALSE;
 
diff --git a/src/radeon.h b/src/radeon.h
index cdd84ea..4f77c3b 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -220,7 +220,7 @@ typedef struct {
 #define RADEON_PLL_NO_ODD_POST_DIV (1 << 1)
 #define RADEON_PLL_USE_REF_DIV     (1 << 2)
 #define RADEON_PLL_LEGACY          (1 << 3)
-#define RADEON_PLL_DCE3            (1 << 4)
+#define RADEON_PLL_PREFER_LOW_REF_DIV (1 << 4)
 
 typedef struct {
     uint16_t          reference_freq;
diff --git a/src/radeon_crtc.c b/src/radeon_crtc.c
index 9eb36ed..8f2d4fc 100644
--- a/src/radeon_crtc.c
+++ b/src/radeon_crtc.c
@@ -132,7 +132,7 @@ RADEONComputePLL(RADEONPLLPtr pll,
     uint32_t best_post_div = 1;
     uint32_t best_ref_div = 1;
     uint32_t best_feedback_div = 1;
-    uint32_t best_freq = 1;
+    uint32_t best_freq = -1;
     uint32_t best_error = 0xffffffff;
     uint32_t best_vco_diff = 1;
     uint32_t post_div;
@@ -143,10 +143,21 @@ RADEONComputePLL(RADEONPLLPtr pll,
 
     if (flags & RADEON_PLL_USE_REF_DIV)
 	min_ref_div = max_ref_div = pll->reference_div;
+    else {
+	max_ref_div = 2*max_ref_div - min_ref_div;
+	while (min_ref_div < max_ref_div-1) {
+	    uint32_t mid=(min_ref_div+max_ref_div)/2;
+	    uint32_t pll_in = pll->reference_freq / mid;
+	    if (pll_in < pll->pll_in_min)
+		max_ref_div = mid;
+	    else if (pll_in > pll->pll_in_max)
+		min_ref_div = mid;
+	    else break;
+	}
+    }
 
     for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) {
 	uint32_t ref_div;
-	uint32_t vco = (freq / 10000) * post_div;
 
 	if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
 	    continue;
@@ -161,45 +172,71 @@ RADEONComputePLL(RADEONPLLPtr pll,
 		continue;
 	}
 
-	if (vco < pll->pll_out_min || vco > pll->pll_out_max)
-	    continue;
-
 	for (ref_div = min_ref_div; ref_div <= max_ref_div; ++ref_div) {
 	    uint32_t feedback_div, current_freq, error, vco_diff;
 	    uint32_t pll_in = pll->reference_freq / ref_div;
+	    uint32_t min_feed_div = pll->min_feedback_div;
+	    uint32_t max_feed_div = pll->max_feedback_div+1;
 
 	    if (pll_in < pll->pll_in_min || pll_in > pll->pll_in_max)
 		continue;
 
-	    feedback_div = RADEONDiv((CARD64)freq * ref_div * post_div,
-				     pll->reference_freq * 10000);
+	    while (min_feed_div < max_feed_div) {
+		uint32_t vco;
 
-	    if (feedback_div < pll->min_feedback_div || feedback_div > pll->max_feedback_div)
-		continue;
+		feedback_div = (min_feed_div+max_feed_div)/2;
+
+		vco = RADEONDiv((CARD64)pll->reference_freq * feedback_div,
+				ref_div);
 
-	    current_freq = RADEONDiv((CARD64)pll->reference_freq * 10000 * feedback_div,
-				     ref_div * post_div);
-
-	    error = abs(current_freq - freq);
-	    vco_diff = abs(vco - best_vco);
-
-	    if ((best_vco == 0 && error < best_error) ||
-		(ref_div == pll->reference_div) ||
-		(best_vco != 0 &&
-		 (error < best_error - 100 ||
-		  (abs(error - best_error) < 100 && vco_diff < best_vco_diff )))) {
-		best_post_div = post_div;
-		best_ref_div = ref_div;
-		best_feedback_div = feedback_div;
-		best_freq = current_freq;
-		best_error = error;
-		best_vco_diff = vco_diff;
+		if (vco < pll->pll_out_min) {
+		    min_feed_div = feedback_div+1;
+		    continue;
+		} else if(vco > pll->pll_out_max) {
+		    max_feed_div = feedback_div;
+		    continue;
+		}
+
+		current_freq = RADEONDiv((CARD64)pll->reference_freq * 10000 * feedback_div,
+					 ref_div * post_div);
+
+		error = abs(current_freq - freq);
+		vco_diff = abs(vco - best_vco);
+
+		if ((best_vco == 0 && error < best_error) ||
+		    (best_vco != 0 &&
+		     (error < best_error - 100 ||
+		      (abs(error - best_error) < 100 && vco_diff < best_vco_diff )))) {
+		    best_post_div = post_div;
+		    best_ref_div = ref_div;
+		    best_feedback_div = feedback_div;
+		    best_freq = current_freq;
+		    best_error = error;
+		    best_vco_diff = vco_diff;
+		} else if (current_freq == freq) {
+		    if (best_freq == -1) {
+			best_post_div = post_div;
+			best_ref_div = ref_div;
+			best_feedback_div = feedback_div;
+			best_freq = current_freq;
+			best_error = error;
+			best_vco_diff = vco_diff;
+		    } else if ((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) {
+			best_post_div = post_div;
+			best_ref_div = ref_div;
+			best_feedback_div = feedback_div;
+			best_freq = current_freq;
+			best_error = error;
+			best_vco_diff = vco_diff;
+		    }
+		}
+
+		if (current_freq < freq)
+		    min_feed_div = feedback_div+1;
+		else
+		    max_feed_div = feedback_div;
 	    }
 	}
-	if (!(flags & RADEON_PLL_DCE3)) {
-	    if (best_freq == freq)
-		break;
-	}
     }
 
     ErrorF("best_freq: %u\n", (unsigned int)best_freq);
@@ -207,6 +244,8 @@ RADEONComputePLL(RADEONPLLPtr pll,
     ErrorF("best_ref_div: %u\n", (unsigned int)best_ref_div);
     ErrorF("best_post_div: %u\n", (unsigned int)best_post_div);
 
+    if (best_freq == -1)
+	FatalError("Couldn't find valid PLL dividers\n");
     *chosen_dot_clock_freq = best_freq / 10000;
     *chosen_feedback_div = best_feedback_div;
     *chosen_reference_div = best_ref_div;


More information about the xorg-commit mailing list