diff options
-rw-r--r-- | src/via_mode.c | 154 |
1 files changed, 90 insertions, 64 deletions
diff --git a/src/via_mode.c b/src/via_mode.c index b9951b9..2b4dacf 100644 --- a/src/via_mode.c +++ b/src/via_mode.c @@ -656,74 +656,104 @@ ViaSetSecondaryDotclock(ScrnInfoPtr pScrn, CARD32 clock) ViaSeqMask(hwp, 0x40, 0x00, 0x04); } - /* - * Simple lookup table for dotclocks - * Only knows those modes known by X. + * */ -static struct ViaDotClock { - int DotClock; - CARD16 UniChrome; - CARD32 UniChromePro; -} ViaDotClocks[] = { - { 25200, 0x513C, 0x000000 }, - { 31500, 0xC558, 0 }, - { 35500, 0x5877, 0 }, - { 36000, 0x5879, 0 }, - { 40000, 0x515F, 0 }, - { 49500, 0xC353, 0 }, - { 50000, 0xC354, 0 }, - { 56300, 0x4F76, 0 }, - { 57284, 0x4E70, 0 }, - { 64995, 0x0D3B, 0 }, - { 65000, 0x0D3B, 0 }, - { 75000, 0x156E, 0 }, - { 78800, 0x442C, 0 }, - { 94500, 0x4542, 0 }, - { 108000, 0x0B53, 0 }, - { 122000, 0x0D6F, 0 }, - { 135000, 0x0742, 0 }, - { 148500, 0x0853, 0 }, - { 155800, 0x0857, 0 }, - { 157500, 0x422C, 0 }, - { 162000, 0x0A71, 0 }, - { 175500, 0x4231, 0 }, - { 189000, 0x0542, 0 }, - { 202500, 0x0763, 0 }, - { 204800, 0x0764, 0 }, - { 218300, 0x043D, 0 }, - { 229500, 0x0660, 0 }, -#if 0 /* dotclock is limited to 230Mhz currently */ - { 234000, 0, 0}, - { 261000, 0, 0}, - { 266950, 0, 0}, - { 288000, 0, 0}, - { 297000, 0, 0}, - { 340480, 0, 0}, - { 341350, 0, 0}, - { 388040, 0, 0}, -#endif - { 0, 0, 0 }, -}; +static CARD32 +VT3122PLLGenerateBest(int Clock, int Shift, int MinDiv, int MaxDiv, + int *BestDiff) +{ + CARD32 PLL = 0; + CARD8 PLLShift; + int Div, Mult, Diff; + float Ratio = Clock / 14318.0; + + switch (Shift) { + case 4: + PLLShift = 0x80; + break; + case 2: + PLLShift = 0x40; + break; + default: + PLLShift = 0x00; + break; + } + + for (Div = MinDiv; Div <= MaxDiv; Div++) { + Mult = Ratio * Div * Shift + 0.5; + + if (Mult < 129) { + Diff = Clock - Mult * 14318 / Div / Shift; + if (Diff < 0) + Diff *= -1; + + if (Diff < *BestDiff) { + *BestDiff = Diff; + PLL = ((PLLShift | Div) << 8) | Mult; + } + } + } + + return PLL; +} /* + * This might seem nasty and ugly, but it's the best solution given the crappy + * limitations the VT3122 PLL has. * + * The below information has been gathered using nothing but a lot of time and + * perseverance. */ static CARD32 -ViaModeDotClockTranslate(ScrnInfoPtr pScrn, DisplayModePtr mode) +VT3122PLLGenerate(ScrnInfoPtr pScrn, int Clock) { - VIAPtr pVia = VIAPTR(pScrn); - int i; + CARD32 PLL; + int Diff = 300000; - for (i = 0; ViaDotClocks[i].DotClock; i++) - if (ViaDotClocks[i].DotClock == mode->Clock) { - if ((pVia->Chipset == VT3122) || (pVia->Chipset == VT7205)) - return ViaDotClocks[i].UniChrome; - else - return ViaDotClocks[i].UniChromePro; - } - return 0x0000; + VIAFUNC(pScrn->scrnIndex); + + if (Clock > 72514) + PLL = VT3122PLLGenerateBest(Clock, 1, 2, 25, &Diff); + else if (Clock > 71788) + PLL = VT3122PLLGenerateBest(Clock, 1, 16, 24, &Diff); + else if (Clock > 71389) { + PLL = 0x1050; /* Big singularity. */ + + Diff = Clock - 71590; + if (Diff < 0) + Diff *= -1; + } else if (Clock > 48833) { + CARD32 tmpPLL; + + PLL = VT3122PLLGenerateBest(Clock, 2, 7, 18, &Diff); + + if (Clock > 69024) + tmpPLL = VT3122PLLGenerateBest(Clock, 1, 15, 23, &Diff); + else if (Clock > 63500) + tmpPLL = VT3122PLLGenerateBest(Clock, 1, 15, 21, &Diff); + else if (Clock > 52008) + tmpPLL = VT3122PLLGenerateBest(Clock, 1, 17, 19, &Diff); + else + tmpPLL = VT3122PLLGenerateBest(Clock, 1, 17, 17, &Diff); + + if (tmpPLL) + PLL = tmpPLL; + } else if (Clock > 35220) + PLL = VT3122PLLGenerateBest(Clock, 2, 11, 24, &Diff); + else if (Clock > 34511) + PLL = VT3122PLLGenerateBest(Clock, 2, 11, 23, &Diff); + else if (Clock > 33441) + PLL = VT3122PLLGenerateBest(Clock, 2, 13, 22, &Diff); + else if (Clock > 31967) + PLL = VT3122PLLGenerateBest(Clock, 2, 11, 21, &Diff); + else + PLL = VT3122PLLGenerateBest(Clock, 4, 8, 19, &Diff); + + ViaDebug(pScrn->scrnIndex, "%s: PLL: 0x%04X (%d off from %d)\n", + __func__, PLL, Diff, Clock); + return PLL; } /* @@ -964,10 +994,6 @@ ViaValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) return ret; } - if (!ModeInfo->PanelClock && !ModeInfo->ClockSlave) - if (!ViaModeDotClockTranslate(pScrn, mode)) - return MODE_NOCLOCK; - temp = mode->CrtcHDisplay * mode->CrtcVDisplay * mode->VRefresh * (pScrn->bitsPerPixel >> 3); if (ModeInfo->Bandwidth < temp) { @@ -1294,7 +1320,7 @@ ViaModePrimary(ScrnInfoPtr pScrn, DisplayModePtr mode) if (ModeInfo->PanelClock) ViaSetPrimaryDotclock(pScrn, ModeInfo->PanelClock); else - ViaSetPrimaryDotclock(pScrn, ViaModeDotClockTranslate(pScrn, mode)); + ViaSetPrimaryDotclock(pScrn, VT3122PLLGenerate(pScrn, mode->Clock)); ViaSetUseExternalClock(pScrn); ViaCrtcMask(hwp, 0x6B, 0x00, 0x01); @@ -1479,7 +1505,7 @@ ViaModeSecondary(ScrnInfoPtr pScrn, DisplayModePtr mode) if (ModeInfo->PanelClock) ViaSetSecondaryDotclock(pScrn, ModeInfo->PanelClock); else - ViaSetSecondaryDotclock(pScrn, ViaModeDotClockTranslate(pScrn, mode)); + ViaSetSecondaryDotclock(pScrn, VT3122PLLGenerate(pScrn, mode->Clock)); ViaSetUseExternalClock(pScrn); ViaCrtcMask(hwp, 0x17, 0x80, 0x80); |