summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/via_mode.c154
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);