summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/atombios_crtc.c8
-rw-r--r--src/radeon.h11
-rw-r--r--src/radeon_atombios.c7
-rw-r--r--src/radeon_crtc.c75
-rw-r--r--src/radeon_driver.c1
5 files changed, 98 insertions, 4 deletions
diff --git a/src/atombios_crtc.c b/src/atombios_crtc.c
index f9698f3f..8cccba62 100644
--- a/src/atombios_crtc.c
+++ b/src/atombios_crtc.c
@@ -407,7 +407,13 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode)
ErrorF("after %d\n", adjust_pll_param.usPixelClock);
}
- RADEONComputePLL(&info->pll, sclock, &temp, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags);
+ if (IS_AVIVO_VARIANT) {
+ if (xf86ReturnOptValBool(info->Options, OPTION_NEW_PLL, TRUE))
+ RADEONComputePLL_AVIVO(&info->pll, sclock, &temp, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags);
+ else
+ RADEONComputePLL(&info->pll, sclock, &temp, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags);
+ } else
+ RADEONComputePLL(&info->pll, sclock, &temp, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags);
sclock = temp; /* 10 khz */
xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO,
diff --git a/src/radeon.h b/src/radeon.h
index 182e946e..10710a83 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -222,7 +222,8 @@ typedef enum {
OPTION_ATOM_TVOUT,
OPTION_R4XX_ATOM,
OPTION_FORCE_LOW_POWER,
- OPTION_DYNAMIC_PM
+ OPTION_DYNAMIC_PM,
+ OPTION_NEW_PLL
} RADEONOpts;
@@ -1164,6 +1165,14 @@ extern void RADEONComputePLL(RADEONPLLPtr pll, unsigned long freq,
uint32_t *chosen_frac_feedback_div,
uint32_t *chosen_reference_div,
uint32_t *chosen_post_div, int flags);
+extern void RADEONComputePLL_AVIVO(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,
DisplayModePtr pMode);
extern void RADEONUnblank(ScrnInfoPtr pScrn);
diff --git a/src/radeon_atombios.c b/src/radeon_atombios.c
index 72fbe214..c272c9a5 100644
--- a/src/radeon_atombios.c
+++ b/src/radeon_atombios.c
@@ -2204,14 +2204,17 @@ RADEONGetATOMClockInfo(ScrnInfoPtr pScrn)
if (pll->pll_out_min == 0)
pll->pll_out_min = 64800;
+
/* limiting the range is a good thing in most cases
* as it limits the number of matching pll combinations,
* however, some duallink DVI monitors seem to prefer combinations that
* would be limited by this. This may need to be revisited
* per chip family.
*/
- if (pll->pll_out_min > 64800)
- pll->pll_out_min = 64800;
+ if (!xf86ReturnOptValBool(info->Options, OPTION_NEW_PLL, TRUE)) {
+ if (pll->pll_out_min > 64800)
+ pll->pll_out_min = 64800;
+ }
return TRUE;
}
diff --git a/src/radeon_crtc.c b/src/radeon_crtc.c
index 3899064f..4e8b490b 100644
--- a/src/radeon_crtc.c
+++ b/src/radeon_crtc.c
@@ -301,6 +301,81 @@ RADEONComputePLL(RADEONPLLPtr pll,
}
+void
+RADEONComputePLL_AVIVO(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)
+{
+ float m, n, frac_n, p, f_vco, f_pclk, best_freq;
+ float pll_out_max = pll->pll_out_max;
+ float pll_out_min = pll->pll_out_min;
+ float reference_freq = pll->reference_freq;
+ float pll_in_max = pll->pll_in_max;
+ float pll_in_min = pll->pll_in_min;
+ float ffreq = freq / 10;
+ float error = 100;
+
+ ErrorF("ffreq: %f\n", ffreq * 10);
+
+ /* 1 - max p */
+ p = floor(pll_out_max / ffreq);
+
+ /* 2 - min m */
+ m = ceil(reference_freq / pll_in_max);
+
+ while (error > 0.25) {
+ /* 3 - n */
+ n = (ffreq / reference_freq) * m * p;
+
+ /* 4 - vco out freq */
+ f_vco = (n / m) * reference_freq;
+
+ /* 5 - pclk freq */
+ f_pclk = f_vco / p;
+
+ /* 6 - error */
+ error = (abs(f_pclk - ffreq) / f_pclk) * 100;
+
+ best_freq = reference_freq * (n / (m * p));
+
+ /* min error 0.25% */
+ if (error < 0.25)
+ break;
+
+ /* 7 - check m */
+ m++;
+ if ((reference_freq / m) >= pll_in_min)
+ continue;
+
+ /* 8 - check p */
+ m = ceil(reference_freq / pll_in_max);
+ p--;
+ if ((p * ffreq) >= pll_out_min)
+ continue;
+ else
+ FatalError("Couldn't find valid PLL dividers\n");
+ }
+
+ frac_n = (n - (int)n) * 10;
+
+ ErrorF("best_freq: %u\n", (unsigned int)best_freq * 10);
+ ErrorF("best_feedback_div: %d.%d\n", (int)n, (int)frac_n);
+ ErrorF("best_ref_div: %d\n", (int)m);
+ ErrorF("best_post_div: %d\n", (int)p);
+
+ *chosen_dot_clock_freq = best_freq;
+ *chosen_feedback_div = (uint32_t)n;
+ *chosen_frac_feedback_div = (uint32_t)frac_n;
+ *chosen_reference_div = (uint32_t)m;
+ *chosen_post_div = (uint32_t)p;
+
+}
+
static void
radeon_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
DisplayModePtr adjusted_mode, int x, int y)
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index bf560f7d..ae4993bc 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -205,6 +205,7 @@ static const OptionInfoRec RADEONOptions[] = {
{ OPTION_R4XX_ATOM, "R4xxATOM", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_FORCE_LOW_POWER, "ForceLowPowerMode", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_DYNAMIC_PM, "DynamicPM", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_NEW_PLL, "NewPLL", OPTV_BOOLEAN, {0}, FALSE },
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};