summaryrefslogtreecommitdiff
path: root/src/mga_g_crtc.c
diff options
context:
space:
mode:
authorTilman Sauerbeck <tilman@code-monkey.de>2007-03-18 10:30:10 +0100
committerTilman Sauerbeck <tilman@code-monkey.de>2007-03-18 10:30:10 +0100
commit3bdda29f071f9e205530472cde96372ba2731876 (patch)
tree71265c316c5aa20a0ec9ef11e1d1677853eaef28 /src/mga_g_crtc.c
parent2116d9a4cafe5bb09669257f23668006aa6aaa70 (diff)
First stab at RandR 1.2. This will only work on G450/G550 cards.
Diffstat (limited to 'src/mga_g_crtc.c')
-rw-r--r--src/mga_g_crtc.c906
1 files changed, 906 insertions, 0 deletions
diff --git a/src/mga_g_crtc.c b/src/mga_g_crtc.c
new file mode 100644
index 0000000..3f4fb4f
--- /dev/null
+++ b/src/mga_g_crtc.c
@@ -0,0 +1,906 @@
+/*
+ * Copyright 2007 Tilman Sauerbeck
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software")
+ * to deal in the software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * them Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Tilman Sauerbeck <tilman@code-monkey.de>
+ *
+ * Sources:
+ * xf86-video-intel, mga_dacG.c
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* All drivers should typically include these */
+#include "xf86.h"
+#include "xf86_OSproc.h"
+
+/* Drivers for PCI hardware need this */
+#include "xf86PciInfo.h"
+
+/* Drivers that need to access the PCI config space directly need this */
+#include "xf86Pci.h"
+
+#include "mga_reg.h"
+#include "mga.h"
+#include "mga_macros.h"
+#include "mga_dacG.h"
+
+/*
+ * Only change bits shown in this mask. Ideally reserved bits should be
+ * zeroed here. Also, don't change the vgaioen bit here since it is
+ * controlled elsewhere.
+ *
+ * XXX These settings need to be checked.
+ */
+#define OPTION1_MASK 0xFFFFFEFF
+#define OPTION2_MASK 0xFFFFFFFF
+#define OPTION3_MASK 0xFFFFFFFF
+
+#define OPTION1_MASK_PRIMARY 0xFFFC0FF
+
+typedef struct {
+ unsigned char ExtVga[6];
+ unsigned char DacRegs[0x50];
+ CARD32 Option;
+ CARD32 Option2;
+ CARD32 Option3;
+ Bool PIXPLLCSaved;
+ long clock;
+} MgaCrtcStateRec, *MgaCrtcStatePtr;
+
+typedef struct {
+ MgaCrtcStateRec saved_state;
+} MgaCrtcDataRec, *MgaCrtcDataPtr;
+
+static void crtc_dpms(xf86CrtcPtr crtc, int mode);
+static void crtc_save(xf86CrtcPtr crtc);
+static void crtc_restore(xf86CrtcPtr crtc);
+static Bool crtc_lock(xf86CrtcPtr crtc);
+static void crtc_unlock(xf86CrtcPtr crtc);
+static Bool crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode);
+static void crtc_prepare(xf86CrtcPtr crtc);
+static void crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode, int x, int y);
+static void crtc_commit(xf86CrtcPtr crtc);
+static void crtc_destroy(xf86CrtcPtr crtc);
+
+static const xf86CrtcFuncsRec crtc_funcs = {
+ .dpms = crtc_dpms,
+ .save = crtc_save,
+ .restore = crtc_restore,
+ .lock = crtc_lock,
+ .unlock = crtc_unlock,
+ .mode_fixup = crtc_mode_fixup,
+ .prepare = crtc_prepare,
+ .mode_set = crtc_mode_set,
+ .commit = crtc_commit,
+ .destroy = crtc_destroy
+};
+
+static void
+crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+}
+
+static void
+MGAG200SEComputePLLParam(long lFo, int *M, int *N, int *P)
+{
+ unsigned int ulComputedFo;
+ unsigned int ulFDelta;
+ unsigned int ulFPermitedDelta;
+ unsigned int ulFTmpDelta;
+ unsigned int ulVCOMax, ulVCOMin;
+ unsigned int ulTestP;
+ unsigned int ulTestM;
+ unsigned int ulTestN;
+ unsigned int ulPLLFreqRef;
+
+ ulVCOMax = 320000;
+ ulVCOMin = 160000;
+ ulPLLFreqRef = 25000;
+
+ ulFDelta = 0xFFFFFFFF;
+ /* Permited delta is 0.5% as VESA Specification */
+ ulFPermitedDelta = lFo * 5 / 1000;
+
+ /* Then we need to minimize the M while staying within 0.5% */
+ for (ulTestP = 8; ulTestP > 0; ulTestP >>= 1) {
+ if ((lFo * ulTestP) > ulVCOMax) continue;
+ if ((lFo * ulTestP) < ulVCOMin) continue;
+
+ for (ulTestN = 17; ulTestN <= 256; ulTestN++) {
+ for (ulTestM = 1; ulTestM <= 32; ulTestM++) {
+ ulComputedFo = (ulPLLFreqRef * ulTestN) / (ulTestM * ulTestP);
+ if (ulComputedFo > lFo)
+ ulFTmpDelta = ulComputedFo - lFo;
+ else
+ ulFTmpDelta = lFo - ulComputedFo;
+
+ if (ulFTmpDelta < ulFDelta) {
+ ulFDelta = ulFTmpDelta;
+ *M = ulTestM - 1;
+ *N = ulTestN - 1;
+ *P = ulTestP - 1;
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Calculate the PLL settings (m, n, p, s).
+ *
+ * For more information, refer to the Matrox "MGA1064SG Developer
+ * Specification" (document 10524-MS-0100). chapter 5.7.8. "PLLs Clocks
+ * Generators"
+ *
+ * \param f_out Desired clock frequency, measured in kHz.
+ * \param best_m Value of PLL 'm' register.
+ * \param best_n Value of PLL 'n' register.
+ * \param p Value of PLL 'p' register.
+ * \param s Value of PLL 's' filter register (pix pll clock only).
+ */
+
+static void
+MGAGCalcClock(xf86CrtcPtr crtc, long f_out,
+ int *best_m, int *best_n, int *p, int *s)
+{
+ MGAPtr pMga = MGAPTR(crtc->scrn);
+ int m, n;
+ double f_vco;
+ double m_err, calc_f;
+ const double ref_freq = (double) pMga->bios.pll_ref_freq;
+ int feed_div_min, feed_div_max;
+ int in_div_min, in_div_max;
+ int post_div_max;
+
+ switch( pMga->Chipset )
+ {
+ case PCI_CHIP_MGA1064:
+ feed_div_min = 100;
+ feed_div_max = 127;
+ in_div_min = 1;
+ in_div_max = 31;
+ post_div_max = 7;
+ break;
+ case PCI_CHIP_MGAG400:
+ case PCI_CHIP_MGAG550:
+ feed_div_min = 7;
+ feed_div_max = 127;
+ in_div_min = 1;
+ in_div_max = 31;
+ post_div_max = 7;
+ break;
+ case PCI_CHIP_MGAG200_SE_A_PCI:
+ case PCI_CHIP_MGAG200_SE_B_PCI:
+ case PCI_CHIP_MGAG100:
+ case PCI_CHIP_MGAG100_PCI:
+ case PCI_CHIP_MGAG200:
+ case PCI_CHIP_MGAG200_PCI:
+ default:
+ feed_div_min = 7;
+ feed_div_max = 127;
+ in_div_min = 1;
+ in_div_max = 6;
+ post_div_max = 7;
+ break;
+ }
+
+ /* Make sure that f_min <= f_out */
+ if ( f_out < ( pMga->bios.pixel.min_freq / 8))
+ f_out = pMga->bios.pixel.min_freq / 8;
+
+ /*
+ * f_pll = f_vco / (p+1)
+ * Choose p so that
+ * pMga->bios.pixel.min_freq <= f_vco <= pMga->bios.pixel.max_freq
+ * we don't have to bother checking for this maximum limit.
+ */
+ f_vco = ( double ) f_out;
+ for ( *p = 0; *p <= post_div_max && f_vco < pMga->bios.pixel.min_freq;
+ *p = *p * 2 + 1, f_vco *= 2.0);
+
+ /* Initial amount of error for frequency maximum */
+ m_err = f_out;
+
+ /* Search for the different values of ( m ) */
+ for ( m = in_div_min ; m <= in_div_max ; m++ )
+ {
+ /* see values of ( n ) which we can't use */
+ for ( n = feed_div_min; n <= feed_div_max; n++ )
+ {
+ calc_f = ref_freq * (n + 1) / (m + 1) ;
+
+ /*
+ * Pick the closest frequency.
+ */
+ if ( abs(calc_f - f_vco) < m_err ) {
+ m_err = abs(calc_f - f_vco);
+ *best_m = m;
+ *best_n = n;
+ }
+ }
+ }
+
+ /* Now all the calculations can be completed */
+ f_vco = ref_freq * (*best_n + 1) / (*best_m + 1);
+
+ /* Adjustments for filtering pll feed back */
+ if ( (50000.0 <= f_vco)
+ && (f_vco < 100000.0) )
+ *s = 0;
+ if ( (100000.0 <= f_vco)
+ && (f_vco < 140000.0) )
+ *s = 1;
+ if ( (140000.0 <= f_vco)
+ && (f_vco < 180000.0) )
+ *s = 2;
+ if ( (180000.0 <= f_vco) )
+ *s = 3;
+
+#ifdef DEBUG
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "f_out_requ =%ld f_pll_real=%.1f f_vco=%.1f n=0x%x m=0x%x p=0x%x s=0x%x\n",
+ f_out, (f_vco / (*p + 1)), f_vco, *best_n, *best_m, *p, *s );
+#endif
+}
+
+/*
+ * MGAGSetPCLK - Set the pixel (PCLK) clock.
+ */
+static void
+MGAGSetPCLK(xf86CrtcPtr crtc, MgaCrtcStatePtr state, long f_out)
+{
+ MGAPtr pMga = MGAPTR(crtc->scrn);
+
+ /* Pixel clock values */
+ int m, n, p, s;
+
+ if (MGAISGx50(pMga)) {
+ state->clock = f_out;
+ return;
+ }
+
+ if (pMga->is_G200SE) {
+ MGAG200SEComputePLLParam(f_out, &m, &n, &p);
+
+ state->DacRegs[MGA1064_PIX_PLLC_M] = m;
+ state->DacRegs[MGA1064_PIX_PLLC_N] = n;
+ state->DacRegs[MGA1064_PIX_PLLC_P] = p;
+ } else {
+ /* Do the calculations for m, n, p and s */
+ MGAGCalcClock(crtc, f_out, &m, &n, &p, &s );
+
+ /* Values for the pixel clock PLL registers */
+ state->DacRegs[MGA1064_PIX_PLLC_M] = m & 0x1F;
+ state->DacRegs[MGA1064_PIX_PLLC_N] = n & 0x7F;
+ state->DacRegs[MGA1064_PIX_PLLC_P] = (p & 0x07) |
+ ((s & 0x03) << 3);
+ }
+}
+
+static void
+state_set(xf86CrtcPtr crtc, MgaCrtcStatePtr state,
+ DisplayModePtr mode, int x, int y)
+{
+ /*
+ * initial values of the DAC registers
+ */
+ const static unsigned char initDAC[] = {
+ /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0,
+ /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x18: */ 0x00, 0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20,
+ /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 0x28: */ 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x40,
+ /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83,
+ /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A,
+ /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ int i;
+ int hd, hs, he, ht, vd, vs, ve, vt, wd;
+ int BppShift;
+ MGAPtr pMga = MGAPTR(crtc->scrn);
+ MGAFBLayout *pLayout = &pMga->CurrentLayout;
+ vgaRegPtr vga = &VGAHWPTR(crtc->scrn)->ModeReg;
+
+ BppShift = pMga->BppShifts[(pLayout->bitsPerPixel >> 3) - 1];
+
+ for (i = 0; i < sizeof(state->DacRegs); i++)
+ state->DacRegs[i] = initDAC[i];
+
+ switch (pMga->Chipset) {
+ case PCI_CHIP_MGA1064:
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x04;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x44;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x18;
+ state->Option = 0x5F094F21;
+ state->Option2 = 0x00000000;
+ break;
+ case PCI_CHIP_MGAG100:
+ case PCI_CHIP_MGAG100_PCI:
+ state->DacRegs[MGA1064_VREF_CTL] = 0x03;
+
+ if (pMga->HasSDRAM) {
+ if (pMga->OverclockMem) {
+ /* 220 Mhz */
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x06;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x38;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x18;
+ } else {
+ /* 203 Mhz */
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x01;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x0E;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x18;
+ }
+
+ state->Option = 0x404991a9;
+ } else {
+ if (pMga->OverclockMem) {
+ /* 143 Mhz */
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x06;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x24;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x10;
+ } else {
+ /* 124 Mhz */
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x04;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x16;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x08;
+ }
+
+ state->Option = 0x4049d121;
+ }
+
+ state->Option2 = 0x0000007;
+ break;
+ case PCI_CHIP_MGAG400:
+ case PCI_CHIP_MGAG550:
+ if (MGAISGx50(pMga))
+ break;
+
+ if (pMga->Dac.maxPixelClock == 360000) { /* G400 MAX */
+ if (pMga->OverclockMem) {
+ /* 150/200 */
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x05;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x42;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x18;
+ state->Option3 = 0x019B8419;
+ state->Option = 0x50574120;
+ } else {
+ /* 125/166 */
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x02;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x1B;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x18;
+ state->Option3 = 0x019B8419;
+ state->Option = 0x5053C120;
+ }
+ } else {
+ if (pMga->OverclockMem) {
+ /* 125/166 */
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x02;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x1B;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x18;
+ state->Option3 = 0x019B8419;
+ state->Option = 0x5053C120;
+ } else {
+ /* 110/166 */
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x13;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x7A;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x08;
+ state->Option3 = 0x0190a421;
+ state->Option = 0x50044120;
+ }
+ }
+
+ if (pMga->HasSDRAM)
+ state->Option &= ~(1 << 14);
+
+ state->Option2 = 0x01003000;
+ break;
+ case PCI_CHIP_MGAG200_SE_A_PCI:
+ case PCI_CHIP_MGAG200_SE_B_PCI:
+ state->DacRegs[MGA1064_VREF_CTL] = 0x03;
+ state->DacRegs[MGA1064_PIX_CLK_CTL] =
+ MGA1064_PIX_CLK_CTL_SEL_PLL;
+
+ state->DacRegs[MGA1064_MISC_CTL] =
+ MGA1064_MISC_CTL_DAC_EN |
+ MGA1064_MISC_CTL_VGA8 |
+ MGA1064_MISC_CTL_DAC_RAM_CS;
+
+ if (pMga->HasSDRAM)
+ state->Option = 0x40499121;
+ else
+ state->Option = 0x4049cd21;
+
+ state->Option2 = 0x00008000;
+ break;
+ case PCI_CHIP_MGAG200:
+ case PCI_CHIP_MGAG200_PCI:
+ default:
+ if (pMga->OverclockMem) {
+ /* 143 Mhz */
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x06;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x24;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x10;
+ } else {
+ /* 124 Mhz */
+ state->DacRegs[MGA1064_SYS_PLL_M] = 0x04;
+ state->DacRegs[MGA1064_SYS_PLL_N] = 0x2D;
+ state->DacRegs[MGA1064_SYS_PLL_P] = 0x19;
+ }
+
+ state->Option2 = 0x00008000;
+
+ if (pMga->HasSDRAM)
+ state->Option = 0x40499121;
+ else
+ state->Option = 0x4049cd21;
+
+ break;
+ }
+
+ /* must always have the pci retries on but rely on
+ polling to keep them from occuring */
+ state->Option &= ~0x20000000;
+
+ switch (pLayout->bitsPerPixel) {
+ case 8:
+ state->DacRegs[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits;
+ break;
+ case 16:
+ state->DacRegs[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits;
+
+ if ((pLayout->weight.red == 5) && (pLayout->weight.green == 5)
+ && (pLayout->weight.blue == 5)) {
+ state->DacRegs[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits;
+ }
+
+ break;
+ case 24:
+ state->DacRegs[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_24bits;
+ break;
+ case 32:
+ if (pLayout->Overlay8Plus24) {
+ state->DacRegs[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_32bits;
+ state->DacRegs[MGA1064_COL_KEY_MSK_LSB] = 0xFF;
+ state->DacRegs[MGA1064_COL_KEY_LSB] = pMga->colorKey;
+ } else
+ state->DacRegs[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_32_24bits;
+
+ break;
+ default:
+ FatalError("MGA: unsupported depth\n");
+ }
+
+ /*
+ * This will initialize all of the generic VGA registers.
+ */
+ if (!vgaHWInit(crtc->scrn, mode)) {
+ ErrorF("oh noes, vgahwinit failed\n");
+ return;
+ }
+
+ /*
+ * Here all of the MGA registers get filled in.
+ */
+ hd = (mode->HDisplay >> 3) - 1;
+ hs = (mode->HSyncStart >> 3) - 1;
+ he = (mode->HSyncEnd >> 3) - 1;
+ ht = (mode->HTotal >> 3) - 1;
+ vd = mode->VDisplay - 1;
+ vs = mode->VSyncStart - 1;
+ ve = mode->VSyncEnd - 1;
+ vt = mode->VTotal - 2;
+
+ /* HTOTAL & 0x7 equal to 0x6 in 8bpp or 0x4 in 24bpp causes strange
+ * vertical stripes
+ */
+ if ((ht & 0x07) == 0x06 || (ht & 0x07) == 0x04)
+ ht++;
+
+ if (pLayout->bitsPerPixel == 24)
+ wd = (pLayout->displayWidth * 3) >> (4 - BppShift);
+ else
+ wd = pLayout->displayWidth >> (4 - BppShift);
+
+ state->ExtVga[0] = 0;
+ state->ExtVga[5] = 0;
+
+ if (mode->Flags & V_INTERLACE) {
+ state->ExtVga[0] = 0x80;
+ state->ExtVga[5] = (hs + he - ht) >> 1;
+ wd <<= 1;
+ vt &= 0xFFFE;
+ }
+
+ state->ExtVga[0] |= (wd & 0x300) >> 4;
+
+ state->ExtVga[1] = (((ht - 4) & 0x100) >> 8) |
+ ((hd & 0x100) >> 7) |
+ ((hs & 0x100) >> 6) |
+ (ht & 0x40);
+ state->ExtVga[2] = ((vt & 0xc00) >> 10) |
+ ((vd & 0x400) >> 8) |
+ ((vd & 0xc00) >> 7) |
+ ((vs & 0xc00) >> 5) |
+ ((vd & 0x400) >> 3); /* linecomp */
+
+ if (pLayout->bitsPerPixel == 24)
+ state->ExtVga[3] = (((1 << BppShift) * 3) - 1) | 0x80;
+ else
+ state->ExtVga[3] = ((1 << BppShift) - 1) | 0x80;
+
+ state->ExtVga[4] = 0;
+
+ vga->CRTC[0] = ht - 4;
+ vga->CRTC[1] = hd;
+ vga->CRTC[2] = hd;
+ vga->CRTC[3] = (ht & 0x1F) | 0x80;
+ vga->CRTC[4] = hs;
+ vga->CRTC[5] = ((ht & 0x20) << 2) | (he & 0x1F);
+ vga->CRTC[6] = vt & 0xFF;
+ vga->CRTC[7] = ((vt & 0x100) >> 8 ) |
+ ((vd & 0x100) >> 7 ) |
+ ((vs & 0x100) >> 6 ) |
+ ((vd & 0x100) >> 5 ) |
+ ((vd & 0x100) >> 4 ) | /* linecomp */
+ ((vt & 0x200) >> 4 ) |
+ ((vd & 0x200) >> 3 ) |
+ ((vs & 0x200) >> 2 );
+ vga->CRTC[9] = ((vd & 0x200) >> 4) |
+ ((vd & 0x200) >> 3); /* linecomp */
+
+ vga->CRTC[16] = vs & 0xFF;
+ vga->CRTC[17] = (ve & 0x0F) | 0x20;
+ vga->CRTC[18] = vd & 0xFF;
+ vga->CRTC[19] = wd & 0xFF;
+ vga->CRTC[21] = vd & 0xFF;
+ vga->CRTC[22] = (vt + 1) & 0xFF;
+ vga->CRTC[24] = vd & 0xFF; /* linecomp */
+
+ state->DacRegs[MGA1064_CURSOR_BASE_ADR_LOW] = pMga->FbCursorOffset >> 10;
+ state->DacRegs[MGA1064_CURSOR_BASE_ADR_HI] = pMga->FbCursorOffset >> 18;
+
+ if (pMga->SyncOnGreen) {
+ state->DacRegs[MGA1064_GEN_CTL] &=
+ ~MGA1064_GEN_CTL_SYNC_ON_GREEN_DIS;
+
+ state->ExtVga[3] |= 0x40;
+ }
+
+ /* select external clock */
+ vga->MiscOutReg |= 0x0C;
+
+ if (mode->Flags & V_DBLSCAN)
+ vga->CRTC[9] |= 0x80;
+
+ if (MGAISGx50(pMga)) {
+ OUTREG(MGAREG_ZORG, 0);
+ }
+
+ MGAGSetPCLK(crtc, state, mode->Clock);
+
+ /* This disables the VGA memory aperture */
+ vga->MiscOutReg &= ~0x02;
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ /* Disable byte-swapping for big-endian architectures - the XFree
+ driver seems to like a little-endian framebuffer -ReneR */
+ /* state->Option |= 0x80000000; */
+ state->Option &= ~0x80000000;
+#endif
+}
+
+/*
+ * This function restores a video mode. It basically writes out all of
+ * the registers that have previously been saved in the MgaCrtcStateRec
+ * data structure.
+ */
+static void
+state_restore(xf86CrtcPtr crtc, MgaCrtcStatePtr state,
+ vgaRegPtr vga, int vga_flags)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ MGAPtr pMga = MGAPTR(scrn);
+ CARD32 optionMask;
+ int i;
+
+ /*
+ * Pixel Clock needs to be restored regardless if we use
+ * HALLib or not. HALlib doesn't do a good job restoring
+ * VESA modes. MATROX: hint, hint.
+ *
+ * FIXME: This seems weird. Verify.
+ */
+ if (MGAISGx50(pMga) && state->clock) {
+ MGAG450SetPLLFreq(scrn, MGA_PIXEL_PLL, state->clock);
+ state->PIXPLLCSaved = FALSE;
+ }
+
+ /* Do not set the memory config for primary cards as it
+ should be correct already. Only on little endian architectures
+ since we need to modify the byteswap bit. -ReneR */
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ optionMask = OPTION1_MASK;
+#else
+ optionMask = (pMga->Primary) ? OPTION1_MASK_PRIMARY : OPTION1_MASK;
+#endif
+
+ /*
+ * Code is needed to get things back to bank zero.
+ */
+
+ /* restore DAC registers
+ * according to the docs we shouldn't write to reserved regs
+ */
+ for (i = 0; i < sizeof(state->DacRegs); i++) {
+ if ((i <= 0x03) ||
+ (i == 0x07) ||
+ (i == 0x0b) ||
+ (i == 0x0f) ||
+ ((i >= 0x13) && (i <= 0x17)) ||
+ (i == 0x1b) ||
+ (i == 0x1c) ||
+ ((i >= 0x1f) && (i <= 0x29)) ||
+ ((i >= 0x30) && (i <= 0x37)) ||
+ (MGAISGx50(pMga) && !state->PIXPLLCSaved &&
+ ((i == 0x2c) || (i == 0x2d) || (i == 0x2e) ||
+ (i == 0x4c) || (i == 0x4d) || (i == 0x4e))))
+ continue;
+ if (pMga->is_G200SE
+ && ((i == 0x2C) || (i == 0x2D) || (i == 0x2E)))
+ continue;
+ outMGAdac(i, state->DacRegs[i]);
+ }
+
+ if (!MGAISGx50(pMga)) {
+ /* restore pci_option register */
+ pciSetBitsLong(pMga->PciTag, PCI_OPTION_REG, optionMask,
+ state->Option);
+
+ if (pMga->Chipset != PCI_CHIP_MGA1064)
+ pciSetBitsLong(pMga->PciTag, PCI_MGA_OPTION2, OPTION2_MASK,
+ state->Option2);
+
+ if (pMga->Chipset == PCI_CHIP_MGAG400 || pMga->Chipset == PCI_CHIP_MGAG550)
+ pciSetBitsLong(pMga->PciTag, PCI_MGA_OPTION3, OPTION3_MASK,
+ state->Option3);
+ }
+
+ /* restore CRTCEXT regs */
+ for (i = 0; i < 6; i++)
+ OUTREG16(MGAREG_CRTCEXT_INDEX, (state->ExtVga[i] << 8) | i);
+
+ /* This handles restoring the generic VGA registers. */
+ if (pMga->is_G200SE) {
+ vgaHWRestore(scrn, vga, VGA_SR_MODE);
+
+ if (vga_flags & VGA_SR_FONTS)
+ MGAG200SERestoreFonts(scrn, vga);
+ } else
+ vgaHWRestore(scrn, vga, vga_flags);
+
+ MGAGRestorePalette(scrn, vga->DAC);
+
+ /*
+ * this is needed to properly restore start address
+ */
+ OUTREG16(MGAREG_CRTCEXT_INDEX, (state->ExtVga[0] << 8) | 0);
+
+#ifdef DEBUG
+ ErrorF("Setting DAC:");
+ for (i = 0; i < sizeof(state->DacRegs); i++) {
+#if 1
+ if(!(i%16)) ErrorF("\n%02X: ",i);
+ ErrorF("%02X ", mgaReg->DacRegs[i]);
+#else
+ if(!(i%8)) ErrorF("\n%02X: ",i);
+ ErrorF("0x%02X, ", mgaReg->DacRegs[i]);
+#endif
+ }
+ ErrorF("\nOPTION = %08lX\n", mgaReg->Option);
+ ErrorF("OPTION2 = %08lX\n", mgaReg->Option2);
+ ErrorF("CRTCEXT:");
+ for (i=0; i<6; i++) ErrorF(" %02X", state->ExtVga[i]);
+ ErrorF("\n");
+#endif
+}
+
+static void
+state_save(xf86CrtcPtr crtc, MgaCrtcStatePtr state, int vga_flags)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ MGAPtr pMga = MGAPTR(scrn);
+ vgaRegPtr vga = &VGAHWPTR(scrn)->SavedReg;
+ int i;
+
+ if (MGAISGx50(pMga))
+ state->clock = MGAG450SavePLLFreq(scrn, MGA_PIXEL_PLL);
+
+ /*
+ * Code is needed to get back to bank zero.
+ */
+ OUTREG16(MGAREG_CRTCEXT_INDEX, 0x0004);
+
+ /*
+ * This function will handle creating the data structure and filling
+ * in the generic VGA portion.
+ */
+ if (pMga->is_G200SE) {
+ vgaHWSave(scrn, vga, VGA_SR_MODE);
+
+ if (vga_flags & VGA_SR_FONTS)
+ MGAG200SESaveFonts(scrn, vga);
+ } else
+ vgaHWSave(scrn, vga, vga_flags);
+
+ MGAGSavePalette(scrn, vga->DAC);
+
+ /*
+ * The port I/O code necessary to read in the extended registers.
+ */
+ for (i = 0; i < sizeof(state->DacRegs); i++)
+ state->DacRegs[i] = inMGAdac(i);
+
+ state->PIXPLLCSaved = TRUE;
+
+ state->Option = pciReadLong(pMga->PciTag, PCI_OPTION_REG);
+ state->Option2 = pciReadLong(pMga->PciTag, PCI_MGA_OPTION2);
+
+ if (pMga->Chipset == PCI_CHIP_MGAG400 || pMga->Chipset == PCI_CHIP_MGAG550)
+ state->Option3 = pciReadLong(pMga->PciTag, PCI_MGA_OPTION3);
+
+ for (i = 0; i < 6; i++) {
+ OUTREG8(MGAREG_CRTCEXT_INDEX, i);
+ state->ExtVga[i] = INREG8(MGAREG_CRTCEXT_DATA);
+ }
+
+#ifdef DEBUG
+ ErrorF("Saved values:\nDAC:");
+ for (i = 0; i < sizeof(state->DacRegs); i++) {
+#if 1
+ if(!(i%16)) ErrorF("\n%02X: ",i);
+ ErrorF("%02X ", state->DacRegs[i]);
+#else
+ if(!(i%8)) ErrorF("\n%02X: ",i);
+ ErrorF("0x%02X, ", state->DacRegs[i]);
+#endif
+ }
+
+ ErrorF("\nOPTION = %08lX\n:", state->Option);
+ ErrorF("OPTION2 = %08lX\nCRTCEXT:", state->Option2);
+
+ for (i=0; i<6; i++) ErrorF(" %02X", state->ExtVga[i]);
+ ErrorF("\n");
+#endif
+}
+
+static void
+crtc_save(xf86CrtcPtr crtc)
+{
+ MgaCrtcDataPtr data = MGACRTCDATAPTR(crtc);
+ MGAPtr pMga = MGAPTR(crtc->scrn);
+ int vga_flags = VGA_SR_MODE;
+
+ if (pMga->Primary)
+ vga_flags |= VGA_SR_FONTS;
+
+ state_save(crtc, &data->saved_state, vga_flags);
+}
+
+static void
+crtc_restore(xf86CrtcPtr crtc)
+{
+ MgaCrtcDataPtr data = MGACRTCDATAPTR(crtc);
+ MGAPtr pMga = MGAPTR(crtc->scrn);
+ vgaHWPtr vga = VGAHWPTR(crtc->scrn);
+ int vga_flags = VGA_SR_MODE;
+
+ if (pMga->Primary)
+ vga_flags |= VGA_SR_FONTS;
+
+ state_restore(crtc, &data->saved_state, &vga->SavedReg, vga_flags);
+}
+
+static Bool
+crtc_lock(xf86CrtcPtr crtc)
+{
+#ifdef XF86DRI
+ return MGADRILock(crtc->scrn);
+#else
+ return FALSE;
+#endif
+}
+
+static void
+crtc_unlock(xf86CrtcPtr crtc)
+{
+#ifdef XF86DRI
+ MGADRIUnlock(crtc->scrn);
+#endif
+}
+
+static Bool
+crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
+{
+ return TRUE;
+}
+
+static void
+crtc_prepare(xf86CrtcPtr crtc)
+{
+ crtc->funcs->dpms(crtc, DPMSModeOff);
+}
+
+static void
+crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
+ DisplayModePtr adjust_mode, int x, int y)
+{
+ MgaCrtcStateRec state;
+ vgaHWPtr vga = VGAHWPTR(crtc->scrn);
+
+ memset(&state, 0, sizeof (state));
+
+ state_set(crtc, &state, mode, x, y);
+ state_restore(crtc, &state, &vga->ModeReg, VGA_SR_MODE);
+}
+
+static void
+crtc_commit(xf86CrtcPtr crtc)
+{
+ crtc->funcs->dpms(crtc, DPMSModeOn);
+}
+
+static void
+crtc_destroy(xf86CrtcPtr crtc)
+{
+ if (crtc->driver_private)
+ xfree (crtc->driver_private);
+}
+
+Bool
+MgaGCrtc1Init(ScrnInfoPtr scrn)
+{
+ xf86CrtcPtr crtc;
+ MgaCrtcDataPtr data;
+
+ data = xnfcalloc (sizeof (MgaCrtcDataRec), 1);
+ if (!data)
+ return FALSE;
+
+ crtc = xf86CrtcCreate (scrn, &crtc_funcs);
+ if (!crtc) {
+ xfree(data);
+ return FALSE;
+ }
+
+ crtc->driver_private = data;
+
+ return TRUE;
+}