summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Deucher <alex@samba.(none)>2007-12-13 18:45:09 -0500
committerAlex Deucher <alex@samba.(none)>2007-12-13 18:45:09 -0500
commit814c6c48aebba2e45ce257289b922cd7e92caf2a (patch)
treeb6421082b5c6fe80591ce208f9c8feaf4313616e
parentf5ac34983411e4c4f41ab1817dce582830f398fd (diff)
RADEON: rework PLL calculation
- Take into account the limits from the bios tables - Unify the PLL calculation between legacy and avivo chips
-rw-r--r--src/atombios_crtc.c89
-rw-r--r--src/radeon.h10
-rw-r--r--src/radeon_bios.c28
-rw-r--r--src/radeon_crtc.c12
-rw-r--r--src/radeon_driver.c34
5 files changed, 60 insertions, 113 deletions
diff --git a/src/atombios_crtc.c b/src/atombios_crtc.c
index 5b09107..2297316 100644
--- a/src/atombios_crtc.c
+++ b/src/atombios_crtc.c
@@ -148,82 +148,6 @@ atombios_set_crtc_timing(atomBiosHandlePtr atomBIOS, SET_CRTC_TIMING_PARAMETERS_
return ATOM_NOT_IMPLEMENTED;
}
-/*
- * Calculate the PLL parameters for a given dotclock.
- */
-#define RADEON_PLL_DEFAULT_PLLOUT_MIN 64800 /* experimental. - taken from rhd divided by 10 */
-
-static Bool
-PLLCalculate(ScrnInfoPtr pScrn, CARD32 PixelClock,
- CARD16 *RefDivider, CARD16 *FBDivider, CARD8 *PostDivider)
-{
-/* limited by the number of bits available */
-#define FB_DIV_LIMIT 1024 /* rv6x0 doesn't like 2048 */
-#define REF_DIV_LIMIT 1024
-#define POST_DIV_LIMIT 128
- RADEONInfoPtr info = RADEONPTR (pScrn);
- RADEONPLLPtr pll = &info->pll;
- CARD32 FBDiv, RefDiv, PostDiv, BestDiff = 0xFFFFFFFF;
- float Ratio;
-
- Ratio = ((float) PixelClock) / ((float) pll->reference_freq * 10);
-
- if (pll->min_pll_freq == 0)
- pll->min_pll_freq = RADEON_PLL_DEFAULT_PLLOUT_MIN;
- for (PostDiv = 2; PostDiv < POST_DIV_LIMIT; PostDiv++) {
- CARD32 VCOOut = PixelClock * PostDiv;
-
- /* we are conservative and avoid the limits */
- if (VCOOut <= pll->min_pll_freq * 10)
- continue;
- if (VCOOut >= pll->max_pll_freq * 10)
- break;
-
- for (RefDiv = 1; RefDiv <= REF_DIV_LIMIT; RefDiv++)
- {
- CARD32 Diff;
-
- FBDiv = (CARD32) ((Ratio * PostDiv * RefDiv) + 0.5);
-
- if (FBDiv >= FB_DIV_LIMIT)
- break;
-
- if (FBDiv > (500 + (13 * RefDiv))) /* rv6x0 limit */
- break;
-
- Diff = abs( PixelClock - (FBDiv * pll->reference_freq * 10) / (PostDiv * RefDiv) );
-
- if (Diff < BestDiff) {
- *FBDivider = FBDiv;
- *RefDivider = RefDiv;
- *PostDivider = PostDiv;
- BestDiff = Diff;
- }
-
- if (BestDiff == 0)
- break;
- }
- if (BestDiff == 0)
- break;
- }
-
- if (BestDiff != 0xFFFFFFFF) {
- ErrorF("PLL Calculation: %dkHz = "
- "(((0x%X / 0x%X) * 0x%X) / 0x%X) (%dkHz off)\n",
- (int) PixelClock, (unsigned int) pll->reference_freq * 10, *RefDivider,
- *FBDivider, *PostDivider, (int) BestDiff);
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PLL for %dkHz uses %dkHz internally.\n",
- (int) PixelClock,
- (int) (pll->reference_freq * 10 * *FBDivider) / *RefDivider);
- return TRUE;
- } else { /* Should never happen */
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "%s: Failed to get a valid PLL setting for %dkHz\n",
- __func__, (int) PixelClock);
- return FALSE;
- }
-}
-
void
atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode)
{
@@ -231,7 +155,7 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode)
RADEONInfoPtr info = RADEONPTR(crtc->scrn);
unsigned char *RADEONMMIO = info->MMIO;
int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
- int sclock = mode->Clock;
+ CARD32 sclock = mode->Clock;
uint16_t ref_div = 0, fb_div = 0;
uint8_t post_div = 0;
int major, minor;
@@ -240,10 +164,11 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode)
AtomBiosArgRec data;
unsigned char *space;
RADEONSavePtr save = info->ModeReg;
-
+
if (IS_AVIVO_VARIANT) {
- CARD32 temp;
- PLLCalculate(crtc->scrn, sclock, &ref_div, &fb_div, &post_div);
+ CARD32 temp;
+ RADEONComputePLL(&info->pll, mode->Clock * 1000, &sclock, &fb_div, &ref_div, &post_div);
+ sclock /= 1000;
/* disable spread spectrum clocking for now -- thanks Hedy Lamarr */
if (radeon_crtc->crtc_id == 0) {
@@ -268,7 +193,7 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode)
radeon_crtc->crtc_id, ref_div, fb_div, fb_div, post_div);
atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
-
+
ErrorF("table is %d %d\n", major, minor);
switch(major) {
case 1:
@@ -304,7 +229,7 @@ atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode)
ErrorF("Set CRTC PLL success\n");
return;
}
-
+
ErrorF("Set CRTC PLL failed\n");
return;
}
diff --git a/src/radeon.h b/src/radeon.h
index 038fcc7..6c38826 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -203,16 +203,18 @@ typedef struct {
typedef struct {
CARD16 reference_freq;
CARD16 reference_div;
- CARD32 min_pll_freq;
- CARD32 max_pll_freq;
+ CARD32 pll_in_min;
+ CARD32 pll_in_max;
+ CARD32 pll_out_min;
+ CARD32 pll_out_max;
CARD16 xclk;
CARD32 min_ref_div;
CARD32 max_ref_div;
+ CARD32 min_post_div;
+ CARD32 max_post_div;
CARD32 min_feedback_div;
CARD32 max_feedback_div;
- CARD32 pll_in_min;
- CARD32 pll_in_max;
CARD32 best_vco;
} RADEONPLLRec, *RADEONPLLPtr;
diff --git a/src/radeon_bios.c b/src/radeon_bios.c
index 7b4eafb..9730119 100644
--- a/src/radeon_bios.c
+++ b/src/radeon_bios.c
@@ -611,8 +611,19 @@ Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn)
or use a new algorithm to calculate
from min_input and max_input
*/
- pll->min_pll_freq = RADEON_BIOS16 (pll_info_block + 78);
- pll->max_pll_freq = RADEON_BIOS32 (pll_info_block + 32);
+ pll->pll_out_min = RADEON_BIOS16 (pll_info_block + 78);
+ pll->pll_out_max = RADEON_BIOS32 (pll_info_block + 32);
+
+ if (pll->pll_out_min == 0) {
+ if (IS_AVIVO_VARIANT)
+ pll->pll_out_min = 64800;
+ else
+ pll->pll_out_min = 20000;
+ }
+
+ pll->pll_in_min = RADEON_BIOS16 (pll_info_block + 74);
+ pll->pll_in_max = RADEON_BIOS16 (pll_info_block + 76);
+
pll->xclk = RADEON_BIOS16 (pll_info_block + 72);
info->sclk = RADEON_BIOS32(pll_info_block + 8) / 100.0;
@@ -622,8 +633,13 @@ Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn)
pll->reference_freq = RADEON_BIOS16 (pll_info_block + 0x0e);
pll->reference_div = RADEON_BIOS16 (pll_info_block + 0x10);
- pll->min_pll_freq = RADEON_BIOS32 (pll_info_block + 0x12);
- pll->max_pll_freq = RADEON_BIOS32 (pll_info_block + 0x16);
+ pll->pll_out_min = RADEON_BIOS32 (pll_info_block + 0x12);
+ pll->pll_out_max = RADEON_BIOS32 (pll_info_block + 0x16);
+
+ /* not available in the bios */
+ pll->pll_in_min = 40;
+ pll->pll_in_max = 100;
+
pll->xclk = RADEON_BIOS16 (pll_info_block + 0x08);
info->sclk = RADEON_BIOS16(pll_info_block + 8) / 100.0;
@@ -636,8 +652,8 @@ Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn)
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ref_freq: %d, min_pll: %u, "
"max_pll: %u, xclk: %d, sclk: %f, mclk: %f\n",
- pll->reference_freq, (unsigned)pll->min_pll_freq,
- (unsigned)pll->max_pll_freq, pll->xclk, info->sclk,
+ pll->reference_freq, (unsigned)pll->pll_out_min,
+ (unsigned)pll->pll_out_max, pll->xclk, info->sclk,
info->mclk);
return TRUE;
diff --git a/src/radeon_crtc.c b/src/radeon_crtc.c
index cf78e2c..45eb1ac 100644
--- a/src/radeon_crtc.c
+++ b/src/radeon_crtc.c
@@ -631,7 +631,7 @@ static CARD32 RADEONDiv64(CARD64 n, CARD32 d)
return (n + (d / 2)) / d;
}
-static void
+void
RADEONComputePLL(RADEONPLLPtr pll,
unsigned long freq,
CARD32 *chosen_dot_clock_freq,
@@ -639,10 +639,6 @@ RADEONComputePLL(RADEONPLLPtr pll,
CARD32 *chosen_reference_div,
CARD32 *chosen_post_div)
{
- int post_divs[] = {1, 2, 4, 8, 3, 6, 12, 0};
-
- int i;
-
CARD32 best_vco = pll->best_vco;
CARD32 best_post_div = 1;
CARD32 best_ref_div = 1;
@@ -650,15 +646,15 @@ RADEONComputePLL(RADEONPLLPtr pll,
CARD32 best_freq = 1;
CARD32 best_error = 0xffffffff;
CARD32 best_vco_diff = 1;
+ CARD32 post_div;
ErrorF("freq: %lu\n", freq);
- for (i = 0; post_divs[i]; i++) {
- int post_div = post_divs[i];
+ for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) {
CARD32 ref_div;
CARD32 vco = (freq / 10000) * post_div;
- if (vco < pll->min_pll_freq || vco > pll->max_pll_freq)
+ if (vco < pll->pll_out_min || vco > pll->pll_out_max)
continue;
for (ref_div = pll->min_ref_div; ref_div <= pll->max_ref_div; ++ref_div) {
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 2c5e64f..16d758b 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -1162,22 +1162,25 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn)
if (pll->reference_div < 2) pll->reference_div = 12;
}
-
} else {
xf86DrvMsg (pScrn->scrnIndex, X_WARNING,
"Video BIOS not detected, using default clock settings!\n");
/* Default min/max PLL values */
if (info->ChipFamily == CHIP_FAMILY_R420 || info->ChipFamily == CHIP_FAMILY_RV410) {
- pll->min_pll_freq = 20000;
- pll->max_pll_freq = 50000;
+ pll->pll_in_min = 100;
+ pll->pll_in_max = 1350;
+ pll->pll_out_min = 20000;
+ pll->pll_out_max = 50000;
} else {
- pll->min_pll_freq = 12500;
- pll->max_pll_freq = 35000;
+ pll->pll_in_min = 40;
+ pll->pll_in_max = 100;
+ pll->pll_out_min = 12500;
+ pll->pll_out_max = 35000;
}
if (RADEONProbePLLParameters(pScrn))
- return;
+ return;
if (info->IsIGP)
pll->reference_freq = 1432;
@@ -1198,25 +1201,30 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn)
* Empirical value changed to 24 to raise pixel clock limit and
* allow higher resolution modes on capable monitors
*/
- pll->max_pll_freq = min(pll->max_pll_freq,
+ pll->pll_out_max = min(pll->pll_out_max,
24 * info->mclk * 100 / pScrn->bitsPerPixel *
info->RamWidth / 16);
}
/* card limits for computing PLLs */
+ if (IS_AVIVO_VARIANT) {
+ pll->min_post_div = 2;
+ pll->max_post_div = 0x7f;
+ } else {
+ pll->min_post_div = 2;
+ pll->max_post_div = 12; //16 on crtc0
+ }
pll->min_ref_div = 2;
pll->max_ref_div = 0x3ff;
pll->min_feedback_div = 4;
pll->max_feedback_div = 0x7ff;
- pll->pll_in_min = 40;
- pll->pll_in_max = 100;
pll->best_vco = 0;
xf86DrvMsg (pScrn->scrnIndex, X_INFO,
"PLL parameters: rf=%u rd=%u min=%u max=%u; xclk=%u\n",
pll->reference_freq,
pll->reference_div,
- (unsigned)pll->min_pll_freq, (unsigned)pll->max_pll_freq,
+ (unsigned)pll->pll_out_min, (unsigned)pll->pll_out_max,
pll->xclk);
/* (Some?) Radeon BIOSes seem too lie about their minimum dot
@@ -1225,7 +1233,7 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn)
*/
if (xf86GetOptValFreq(info->Options, OPTION_MIN_DOTCLOCK,
OPTUNITS_MHZ, &min_dotclock)) {
- if (min_dotclock < 12 || min_dotclock*100 >= pll->max_pll_freq) {
+ if (min_dotclock < 12 || min_dotclock*100 >= pll->pll_out_max) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Illegal minimum dotclock specified %.2f MHz "
"(option ignored)\n",
@@ -1234,8 +1242,8 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn)
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Forced minimum dotclock to %.2f MHz "
"(instead of detected %.2f MHz)\n",
- min_dotclock, ((double)pll->min_pll_freq/1000));
- pll->min_pll_freq = min_dotclock * 1000;
+ min_dotclock, ((double)pll->pll_out_min/1000));
+ pll->pll_out_min = min_dotclock * 1000;
}
}
}