summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/radeon.h8
-rw-r--r--src/radeon_bios.c18
-rw-r--r--src/radeon_crtc.c193
-rw-r--r--src/radeon_driver.c9
-rw-r--r--src/radeon_output.c2
-rw-r--r--src/radeon_probe.h2
6 files changed, 164 insertions, 68 deletions
diff --git a/src/radeon.h b/src/radeon.h
index 10ecd09..b1091bd 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -206,6 +206,14 @@ typedef struct {
CARD32 min_pll_freq;
CARD32 max_pll_freq;
CARD16 xclk;
+
+ CARD32 min_ref_div;
+ CARD32 max_ref_div;
+ CARD32 min_feedback_div;
+ CARD32 max_feedback_div;
+ CARD32 pll_in_min;
+ CARD32 pll_in_max;
+ CARD32 best_vco;
} RADEONPLLRec, *RADEONPLLPtr;
typedef struct {
diff --git a/src/radeon_bios.c b/src/radeon_bios.c
index 3043de6..cca3d43 100644
--- a/src/radeon_bios.c
+++ b/src/radeon_bios.c
@@ -618,15 +618,6 @@ Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn)
info->sclk = RADEON_BIOS32(pll_info_block + 8) / 100.0;
info->mclk = RADEON_BIOS32(pll_info_block + 12) / 100.0;
- if (info->sclk == 0) info->sclk = 200;
- if (info->mclk == 0) info->mclk = 200;
-
- 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,
- info->mclk);
-
} else {
pll_info_block = RADEON_BIOS16 (info->ROMHeaderStart + 0x30);
@@ -639,8 +630,17 @@ Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn)
info->sclk = RADEON_BIOS16(pll_info_block + 8) / 100.0;
info->mclk = RADEON_BIOS16(pll_info_block + 10) / 100.0;
}
+
+ if (info->sclk == 0) info->sclk = 200;
+ if (info->mclk == 0) info->mclk = 200;
}
+ 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,
+ info->mclk);
+
return TRUE;
}
diff --git a/src/radeon_crtc.c b/src/radeon_crtc.c
index 1ea6d2b..fa2aba0 100644
--- a/src/radeon_crtc.c
+++ b/src/radeon_crtc.c
@@ -626,13 +626,96 @@ static int RADEONDiv(int n, int d)
return (n + (d / 2)) / d;
}
+static CARD32 RADEONDiv64(CARD64 n, CARD32 d)
+{
+ return (n + (d / 2)) / d;
+}
+
+static void
+RADEONComputePLL(RADEONPLLPtr pll,
+ unsigned long freq,
+ CARD32 *chosen_dot_clock_freq,
+ CARD32 *chosen_feedback_div,
+ 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;
+ CARD32 best_feedback_div = 1;
+ CARD32 best_freq = 1;
+ CARD32 best_error = 0xffffffff;
+ CARD32 best_vco_diff = 1;
+
+ ErrorF("freq: %d\n", freq);
+
+ for (i = 0; post_divs[i]; i++) {
+ int post_div = post_divs[i];
+ CARD32 ref_div;
+ CARD32 vco = (freq / 10000) * post_div;
+
+ if (vco < pll->min_pll_freq || vco > pll->max_pll_freq)
+ continue;
+
+ for (ref_div = pll->min_ref_div; ref_div <= pll->max_ref_div; ++ref_div) {
+ CARD32 feedback_div, current_freq, error, vco_diff;
+ CARD32 pll_in = pll->reference_freq / ref_div;
+
+ if (pll_in < pll->pll_in_min || pll_in > pll->pll_in_max)
+ continue;
+
+ feedback_div = RADEONDiv64((CARD64)freq * ref_div * post_div,
+ pll->reference_freq * 10000);
+
+ if (feedback_div < pll->min_feedback_div || feedback_div > pll->max_feedback_div)
+ continue;
+
+ current_freq = RADEONDiv64((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;
+ }
+ }
+ }
+
+ ErrorF("best_freq: %d\n", best_freq);
+ ErrorF("best_feedback_div: %d\n", best_feedback_div);
+ ErrorF("best_ref_div: %d\n", best_ref_div);
+ ErrorF("best_post_div: %d\n", best_post_div);
+
+ *chosen_dot_clock_freq = best_freq;
+ *chosen_feedback_div = best_feedback_div;
+ *chosen_reference_div = best_ref_div;
+ *chosen_post_div = best_post_div;
+
+}
+
/* Define PLL registers for requested video mode */
static void
-RADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONInfoPtr info,
- RADEONSavePtr save, RADEONPLLPtr pll,
- double dot_clock)
+RADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save,
+ RADEONPLLPtr pll, DisplayModePtr mode)
{
- unsigned long freq = dot_clock * 100;
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ CARD32 feedback_div = 0;
+ CARD32 reference_div = 0;
+ CARD32 post_divider = 0;
+ CARD32 freq = 0;
struct {
int divider;
@@ -654,21 +737,20 @@ RADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONInfoPtr info,
{ 0, 0 }
};
+ RADEONComputePLL(pll, mode->Clock * 1000, &freq, &feedback_div, &reference_div, &post_divider);
+
+#if 0
if (info->UseBiosDividers) {
save->ppll_ref_div = info->RefDivider;
save->ppll_div_3 = info->FeedbackDivider | (info->PostDivider << 16);
save->htotal_cntl = 0;
return;
}
-
- if (freq > pll->max_pll_freq) freq = pll->max_pll_freq;
- if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12;
+#endif
for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
- save->pll_output_freq = post_div->divider * freq;
-
- if (save->pll_output_freq >= pll->min_pll_freq
- && save->pll_output_freq <= pll->max_pll_freq) break;
+ if (post_div->divider == post_divider)
+ break;
}
if (!post_div->divider) {
@@ -676,20 +758,20 @@ RADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONInfoPtr info,
post_div = &post_divs[0];
}
- save->dot_clock_freq = freq;
- save->feedback_div = RADEONDiv(pll->reference_div
- * save->pll_output_freq,
- pll->reference_freq);
- save->post_div = post_div->divider;
+ save->dot_clock_freq = freq / 10000;
+ save->feedback_div = feedback_div;
+ save->reference_div = reference_div;
+ save->post_div = post_divider;
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
- "dc=%u, of=%u, fd=%d, pd=%d\n",
+ "dc=%u, of=%u, fd=%d, rd=%d, pd=%d\n",
(unsigned)save->dot_clock_freq,
(unsigned)save->pll_output_freq,
save->feedback_div,
+ save->reference_div,
save->post_div);
- save->ppll_ref_div = pll->reference_div;
+ save->ppll_ref_div = save->reference_div;
#if defined(__powerpc__)
/* apparently programming this otherwise causes a hang??? */
@@ -699,21 +781,22 @@ RADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONInfoPtr info,
#endif
save->ppll_div_3 = (save->feedback_div | (post_div->bitvalue << 16));
- save->htotal_cntl = 0;
+ save->htotal_cntl = mode->HTotal & 0x7;
save->vclk_ecp_cntl = (info->SavedReg->vclk_ecp_cntl &
~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK;
-
}
/* Define PLL2 registers for requested video mode */
static void
RADEONInitPLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save,
- RADEONPLLPtr pll, double dot_clock,
- int no_odd_postdiv)
+ RADEONPLLPtr pll, DisplayModePtr mode)
{
- RADEONInfoPtr info = RADEONPTR(pScrn);
- unsigned long freq = dot_clock * 100;
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ CARD32 feedback_div = 0;
+ CARD32 reference_div = 0;
+ CARD32 post_divider = 0;
+ CARD32 freq = 0;
struct {
int divider;
@@ -734,18 +817,11 @@ RADEONInitPLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save,
{ 0, 0 }
};
- if (freq > pll->max_pll_freq) freq = pll->max_pll_freq;
- if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12;
+ RADEONComputePLL(pll, mode->Clock * 1000, &freq, &feedback_div, &reference_div, &post_divider);
for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
- /* Odd post divider value don't work properly on the second digital
- * output
- */
- if (no_odd_postdiv && (post_div->divider & 1))
- continue;
- save->pll_output_freq_2 = post_div->divider * freq;
- if (save->pll_output_freq_2 >= pll->min_pll_freq
- && save->pll_output_freq_2 <= pll->max_pll_freq) break;
+ if (post_div->divider == post_divider)
+ break;
}
if (!post_div->divider) {
@@ -753,28 +829,29 @@ RADEONInitPLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save,
post_div = &post_divs[0];
}
- save->dot_clock_freq_2 = freq;
- save->feedback_div_2 = RADEONDiv(pll->reference_div
- * save->pll_output_freq_2,
- pll->reference_freq);
- save->post_div_2 = post_div->divider;
+ save->dot_clock_freq_2 = freq / 10000;
+ save->feedback_div_2 = feedback_div;
+ save->reference_div_2 = reference_div;
+ save->post_div_2 = post_divider;
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
- "dc=%u, of=%u, fd=%d, pd=%d\n",
+ "dc=%u, of=%u, fd=%d, rd=%d, pd=%d\n",
(unsigned)save->dot_clock_freq_2,
(unsigned)save->pll_output_freq_2,
save->feedback_div_2,
+ save->reference_div_2,
save->post_div_2);
- save->p2pll_ref_div = pll->reference_div;
+ save->p2pll_ref_div = save->reference_div_2;
+
save->p2pll_div_0 = (save->feedback_div_2 |
(post_div->bitvalue << 16));
- save->htotal_cntl2 = 0;
- save->pixclks_cntl = ((info->SavedReg->pixclks_cntl &
- ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
- RADEON_PIX2CLK_SRC_SEL_P2PLLCLK);
+ save->htotal_cntl2 = mode->HTotal & 0x7;
+ save->pixclks_cntl = ((info->SavedReg->pixclks_cntl &
+ ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
+ RADEON_PIX2CLK_SRC_SEL_P2PLLCLK);
}
static void
@@ -851,25 +928,25 @@ legacy_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
ErrorF("init crtc1\n");
RADEONInitCrtcRegisters(crtc, info->ModeReg, adjusted_mode);
RADEONInitCrtcBase(crtc, info->ModeReg, x, y);
- dot_clock = adjusted_mode->Clock / 1000.0;
- if (dot_clock) {
+ dot_clock = adjusted_mode->Clock / 1000.0;
+ if (dot_clock) {
ErrorF("init pll1\n");
- RADEONInitPLLRegisters(pScrn, info, info->ModeReg, &info->pll, dot_clock);
- } else {
- info->ModeReg->ppll_ref_div = info->SavedReg->ppll_ref_div;
- info->ModeReg->ppll_div_3 = info->SavedReg->ppll_div_3;
- info->ModeReg->htotal_cntl = info->SavedReg->htotal_cntl;
- }
+ RADEONInitPLLRegisters(pScrn, info->ModeReg, &info->pll, adjusted_mode);
+ } else {
+ info->ModeReg->ppll_ref_div = info->SavedReg->ppll_ref_div;
+ info->ModeReg->ppll_div_3 = info->SavedReg->ppll_div_3;
+ info->ModeReg->htotal_cntl = info->SavedReg->htotal_cntl;
+ }
break;
case 1:
ErrorF("init crtc2\n");
- RADEONInitCrtc2Registers(crtc, info->ModeReg, adjusted_mode);
+ RADEONInitCrtc2Registers(crtc, info->ModeReg, adjusted_mode);
RADEONInitCrtc2Base(crtc, info->ModeReg, x, y);
- dot_clock = adjusted_mode->Clock / 1000.0;
- if (dot_clock) {
+ dot_clock = adjusted_mode->Clock / 1000.0;
+ if (dot_clock) {
ErrorF("init pll2\n");
- RADEONInitPLL2Registers(pScrn, info->ModeReg, &info->pll, dot_clock, no_odd_post_div);
- }
+ RADEONInitPLL2Registers(pScrn, info->ModeReg, &info->pll, adjusted_mode);
+ }
break;
}
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 8ade8b1..0baf2ef 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -1203,6 +1203,15 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn)
info->RamWidth / 16);
}
+ /* card limits for computing PLLs */
+ 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,
diff --git a/src/radeon_output.c b/src/radeon_output.c
index 85f1156..d872205 100644
--- a/src/radeon_output.c
+++ b/src/radeon_output.c
@@ -861,7 +861,7 @@ radeon_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
}
/* update timing for LVDS and DFP if RMX is active */
- if ((radeon_output->MonType == MT_LCD) || (radeon_output->Flags & RADEON_USE_RMX)) {
+ if (radeon_output->Flags & RADEON_USE_RMX) {
/* set to the panel's native mode */
adjusted_mode->HTotal = radeon_output->PanelXRes + radeon_output->HBlank;
adjusted_mode->HSyncStart = radeon_output->PanelXRes + radeon_output->HOverPlus;
diff --git a/src/radeon_probe.h b/src/radeon_probe.h
index a7d873e..c0b2694 100644
--- a/src/radeon_probe.h
+++ b/src/radeon_probe.h
@@ -435,6 +435,7 @@ typedef struct {
CARD32 dot_clock_freq;
CARD32 pll_output_freq;
int feedback_div;
+ int reference_div;
int post_div;
/* PLL registers */
@@ -447,6 +448,7 @@ typedef struct {
CARD32 dot_clock_freq_2;
CARD32 pll_output_freq_2;
int feedback_div_2;
+ int reference_div_2;
int post_div_2;
/* PLL2 registers */