summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuc Verhaegen <libv@skynet.be>2005-12-30 23:01:40 +0000
committerLuc Verhaegen <libv@skynet.be>2005-12-30 23:01:40 +0000
commitbfbd72e9ac5018b73cb9b7373207be14e74aa954 (patch)
treea36adce314df65815f3605ed6b5af33205a62bea
parent8f4442a8fa88d5a233e3620d179908c5716bc731 (diff)
[devel-PLL_generation] This has been the week of one-thousand-and-one modes
for me. Although these crts of mine have seen way more than that. But it does somewhat situate what work it took to get this one finally done. But here it is: Completely Free Modes! Now with added non-borking dotclock PLL generator! Happy New Years!
-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);