xf86-video-ati: Branch 'master'

Alex Deucher agd5f at kemper.freedesktop.org
Wed Apr 22 08:45:16 PDT 2009


 src/atombios_crtc.c |   11 ++++--
 src/legacy_crtc.c   |    6 ++-
 src/radeon.h        |    3 +
 src/radeon_crtc.c   |   84 +++++++++++++++++++++++++++++++---------------------
 src/radeon_driver.c |    4 ++
 5 files changed, 69 insertions(+), 39 deletions(-)

New commits:
commit 24e4b73b4fbbb2c790e6120ede3caaa4e7e58359
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Wed Apr 22 11:42:18 2009 -0400

    radeon pll: add support for fractional feedback divs
    
    Allows us to hit dot clocks much closer, especially on
    chips with non-27 Mhz reference clocks like most IGP chips.
    
    This should fix most flickering and blanking problems with
    non-exact dot clocks.

diff --git a/src/atombios_crtc.c b/src/atombios_crtc.c
index 31c032b..01266b6 100644
--- a/src/atombios_crtc.c
+++ b/src/atombios_crtc.c
@@ -259,7 +259,7 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode)
     unsigned char *RADEONMMIO = info->MMIO;
     int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
     uint32_t sclock = mode->Clock;
-    uint32_t ref_div = 0, fb_div = 0, post_div = 0;
+    uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
     int major, minor, i;
     SET_PIXEL_CLOCK_PS_ALLOCATION spc_param;
     PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr;
@@ -311,15 +311,16 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode)
 	    pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
     }
 
-    RADEONComputePLL(&info->pll, mode->Clock, &temp, &fb_div, &ref_div, &post_div, pll_flags);
+    RADEONComputePLL(&info->pll, mode->Clock, &temp, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags);
     sclock = temp;
 
     xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO,
 	       "crtc(%d) Clock: mode %d, PLL %lu\n",
 	       radeon_crtc->crtc_id, mode->Clock, (long unsigned int)sclock * 10);
     xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO,
-	       "crtc(%d) PLL  : refdiv %u, fbdiv 0x%X(%u), pdiv %u\n",
-	       radeon_crtc->crtc_id, (unsigned int)ref_div, (unsigned int)fb_div, (unsigned int)fb_div, (unsigned int)post_div);
+	       "crtc(%d) PLL  : refdiv %u, fbdiv 0x%X(%u), fracfbdiv %u, pdiv %u\n",
+	       radeon_crtc->crtc_id, (unsigned int)ref_div, (unsigned int)fb_div,
+	       (unsigned int)fb_div, (unsigned int)frac_fb_div, (unsigned int)post_div);
 
     /* Can't really do cloning easily on DCE3 cards */
     for (i = 0; i < xf86_config->num_output; i++) {
@@ -353,6 +354,7 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode)
 	    spc2_ptr->usPixelClock = cpu_to_le16(sclock);
 	    spc2_ptr->usRefDiv = cpu_to_le16(ref_div);
 	    spc2_ptr->usFbDiv = cpu_to_le16(fb_div);
+	    spc2_ptr->ucFracFbDiv = frac_fb_div;
 	    spc2_ptr->ucPostDiv = post_div;
 	    spc2_ptr->ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
 	    spc2_ptr->ucCRTC = radeon_crtc->crtc_id;
@@ -364,6 +366,7 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode)
 	    spc3_ptr->usPixelClock = cpu_to_le16(sclock);
 	    spc3_ptr->usRefDiv = cpu_to_le16(ref_div);
 	    spc3_ptr->usFbDiv = cpu_to_le16(fb_div);
+	    spc3_ptr->ucFracFbDiv = frac_fb_div;
 	    spc3_ptr->ucPostDiv = post_div;
 	    spc3_ptr->ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
 	    spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2);
diff --git a/src/legacy_crtc.c b/src/legacy_crtc.c
index 3759f05..7a3a920 100644
--- a/src/legacy_crtc.c
+++ b/src/legacy_crtc.c
@@ -1193,6 +1193,7 @@ RADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save,
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
     uint32_t feedback_div = 0;
+    uint32_t frac_fb_div = 0;
     uint32_t reference_div = 0;
     uint32_t post_divider = 0;
     uint32_t freq = 0;
@@ -1225,7 +1226,7 @@ RADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save,
        return;
     }
 
-    RADEONComputePLL(pll, mode->Clock, &freq, &feedback_div, &reference_div, &post_divider, flags);
+    RADEONComputePLL(pll, mode->Clock, &freq, &feedback_div, &frac_fb_div, &reference_div, &post_divider, flags);
 
     for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
 	if (post_div->divider == post_divider)
@@ -1274,6 +1275,7 @@ RADEONInitPLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save,
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
     uint32_t feedback_div = 0;
+    uint32_t frac_fb_div = 0;
     uint32_t reference_div = 0;
     uint32_t post_divider = 0;
     uint32_t freq = 0;
@@ -1304,7 +1306,7 @@ RADEONInitPLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save,
        return;
     }
 
-    RADEONComputePLL(pll, mode->Clock, &freq, &feedback_div, &reference_div, &post_divider, flags);
+    RADEONComputePLL(pll, mode->Clock, &freq, &feedback_div, &frac_fb_div, &reference_div, &post_divider, flags);
 
     for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
 	if (post_div->divider == post_divider)
diff --git a/src/radeon.h b/src/radeon.h
index 174352d..eaaff25 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -277,6 +277,8 @@ typedef struct {
     uint32_t          max_post_div;
     uint32_t          min_feedback_div;
     uint32_t          max_feedback_div;
+    uint32_t          min_frac_feedback_div;
+    uint32_t          max_frac_feedback_div;
     uint32_t          best_vco;
 } RADEONPLLRec, *RADEONPLLPtr;
 
@@ -1049,6 +1051,7 @@ extern void RADEONBlank(ScrnInfoPtr pScrn);
 extern void RADEONComputePLL(RADEONPLLPtr pll, unsigned long freq,
 			     uint32_t *chosen_dot_clock_freq,
 			     uint32_t *chosen_feedback_div,
+			     uint32_t *chosen_frac_feedback_div,
 			     uint32_t *chosen_reference_div,
 			     uint32_t *chosen_post_div, int flags);
 extern DisplayModePtr RADEONCrtcFindClosestMode(xf86CrtcPtr crtc,
diff --git a/src/radeon_crtc.c b/src/radeon_crtc.c
index cd0d55e..a67d374 100644
--- a/src/radeon_crtc.c
+++ b/src/radeon_crtc.c
@@ -129,6 +129,7 @@ RADEONComputePLL(RADEONPLLPtr pll,
 		 unsigned long freq,
 		 uint32_t *chosen_dot_clock_freq,
 		 uint32_t *chosen_feedback_div,
+		 uint32_t *chosen_frac_feedback_div,
 		 uint32_t *chosen_reference_div,
 		 uint32_t *chosen_post_div,
 		 int flags)
@@ -139,6 +140,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_frac_feedback_div = 0;
     uint32_t best_freq = -1;
     uint32_t best_error = 0xffffffff;
     uint32_t best_vco_diff = 1;
@@ -189,11 +191,15 @@ RADEONComputePLL(RADEONPLLPtr pll,
 
 	    while (min_feed_div < max_feed_div) {
 		uint32_t vco;
+		uint32_t min_frac_feed_div = pll->min_frac_feedback_div;
+                uint32_t max_frac_feed_div = pll->max_frac_feedback_div+1;
+                uint32_t frac_feedback_div;
+                CARD64 tmp;
 
 		feedback_div = (min_feed_div+max_feed_div)/2;
 
-		vco = RADEONDiv((CARD64)pll->reference_freq * feedback_div,
-				ref_div);
+		tmp = (CARD64)pll->reference_freq * feedback_div;
+		vco = RADEONDiv(tmp, ref_div);
 
 		if (vco < pll->pll_out_min) {
 		    min_feed_div = feedback_div+1;
@@ -203,45 +209,55 @@ RADEONComputePLL(RADEONPLLPtr pll,
 		    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)) ||
-			       ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) ||
-			       ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) ||
-			       ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) ||
-			       ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) ||
-			       ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) {
+		while (min_frac_feed_div < max_frac_feed_div) {
+		    frac_feedback_div = (min_frac_feed_div+max_frac_feed_div)/2;
+                    tmp = (CARD64)pll->reference_freq * 10000 * feedback_div;
+                    tmp += (CARD64)pll->reference_freq * 1000 * frac_feedback_div;
+		    current_freq = RADEONDiv(tmp, 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_frac_feedback_div = frac_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_frac_feedback_div = frac_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)) ||
+				   ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) ||
+				   ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) ||
+				   ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) ||
+				   ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) ||
+				   ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) {
+			    best_post_div = post_div;
+			    best_ref_div = ref_div;
+			    best_feedback_div = feedback_div;
+			    best_frac_feedback_div = frac_feedback_div;
+			    best_freq = current_freq;
+			    best_error = error;
+			    best_vco_diff = vco_diff;
+			}
 		    }
+		    if (current_freq < freq)
+                        min_frac_feed_div = frac_feedback_div+1;
+                    else
+                        max_frac_feed_div = frac_feedback_div;
 		}
-
 		if (current_freq < freq)
 		    min_feed_div = feedback_div+1;
 		else
@@ -252,6 +268,7 @@ RADEONComputePLL(RADEONPLLPtr pll,
 
     ErrorF("best_freq: %u\n", (unsigned int)best_freq);
     ErrorF("best_feedback_div: %u\n", (unsigned int)best_feedback_div);
+    ErrorF("best_frac_feedback_div: %u\n", (unsigned int)best_frac_feedback_div);
     ErrorF("best_ref_div: %u\n", (unsigned int)best_ref_div);
     ErrorF("best_post_div: %u\n", (unsigned int)best_post_div);
 
@@ -259,6 +276,7 @@ RADEONComputePLL(RADEONPLLPtr pll,
 	FatalError("Couldn't find valid PLL dividers\n");
     *chosen_dot_clock_freq = best_freq / 10000;
     *chosen_feedback_div = best_feedback_div;
+    *chosen_frac_feedback_div = best_frac_feedback_div;
     *chosen_reference_div = best_ref_div;
     *chosen_post_div = best_post_div;
 
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index db5a0e3..9cbfd0d 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -1206,9 +1206,13 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn)
     if (IS_AVIVO_VARIANT) {
 	pll->min_post_div = 2;
 	pll->max_post_div = 0x7f;
+	pll->min_frac_feedback_div = 0;
+	pll->max_frac_feedback_div = 9;
     } else {
 	pll->min_post_div = 1;
 	pll->max_post_div = 12; //16 on crtc0
+	pll->min_frac_feedback_div = 0;
+	pll->max_frac_feedback_div = 0;
     }
     pll->min_ref_div = 2;
     pll->max_ref_div = 0x3ff;


More information about the xorg-commit mailing list