diff options
-rw-r--r-- | src/radeon.h | 8 | ||||
-rw-r--r-- | src/radeon_bios.c | 18 | ||||
-rw-r--r-- | src/radeon_crtc.c | 193 | ||||
-rw-r--r-- | src/radeon_driver.c | 9 | ||||
-rw-r--r-- | src/radeon_output.c | 2 | ||||
-rw-r--r-- | src/radeon_probe.h | 2 |
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 */ |