1f7018c21STomi Valkeinen /* 2f7018c21STomi Valkeinen * 3f7018c21STomi Valkeinen * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. 4f7018c21STomi Valkeinen * 5f7018c21STomi Valkeinen * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> 6f7018c21STomi Valkeinen * 7f7018c21STomi Valkeinen * Portions Copyright (c) 2001 Matrox Graphics Inc. 8f7018c21STomi Valkeinen * 9f7018c21STomi Valkeinen * Version: 1.65 2002/08/14 10f7018c21STomi Valkeinen * 11f7018c21STomi Valkeinen * See matroxfb_base.c for contributors. 12f7018c21STomi Valkeinen * 13f7018c21STomi Valkeinen */ 14f7018c21STomi Valkeinen 15f7018c21STomi Valkeinen 16f7018c21STomi Valkeinen #include "matroxfb_DAC1064.h" 17f7018c21STomi Valkeinen #include "matroxfb_misc.h" 18f7018c21STomi Valkeinen #include "matroxfb_accel.h" 19f7018c21STomi Valkeinen #include "g450_pll.h" 20f7018c21STomi Valkeinen #include <linux/matroxfb.h> 21f7018c21STomi Valkeinen 22f7018c21STomi Valkeinen #ifdef NEED_DAC1064 23f7018c21STomi Valkeinen #define outDAC1064 matroxfb_DAC_out 24f7018c21STomi Valkeinen #define inDAC1064 matroxfb_DAC_in 25f7018c21STomi Valkeinen 26f7018c21STomi Valkeinen #define DAC1064_OPT_SCLK_PCI 0x00 27f7018c21STomi Valkeinen #define DAC1064_OPT_SCLK_PLL 0x01 28f7018c21STomi Valkeinen #define DAC1064_OPT_SCLK_EXT 0x02 29f7018c21STomi Valkeinen #define DAC1064_OPT_SCLK_MASK 0x03 30f7018c21STomi Valkeinen #define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */ 31f7018c21STomi Valkeinen #define DAC1064_OPT_GDIV3 0x00 32f7018c21STomi Valkeinen #define DAC1064_OPT_MDIV1 0x08 33f7018c21STomi Valkeinen #define DAC1064_OPT_MDIV2 0x00 34f7018c21STomi Valkeinen #define DAC1064_OPT_RESERVED 0x10 35f7018c21STomi Valkeinen 36f7018c21STomi Valkeinen static void DAC1064_calcclock(const struct matrox_fb_info *minfo, 37f7018c21STomi Valkeinen unsigned int freq, unsigned int fmax, 38f7018c21STomi Valkeinen unsigned int *in, unsigned int *feed, 39f7018c21STomi Valkeinen unsigned int *post) 40f7018c21STomi Valkeinen { 41f7018c21STomi Valkeinen unsigned int fvco; 42f7018c21STomi Valkeinen unsigned int p; 43f7018c21STomi Valkeinen 44f7018c21STomi Valkeinen DBG(__func__) 45f7018c21STomi Valkeinen 46f7018c21STomi Valkeinen /* only for devices older than G450 */ 47f7018c21STomi Valkeinen 48f7018c21STomi Valkeinen fvco = PLL_calcclock(minfo, freq, fmax, in, feed, &p); 49f7018c21STomi Valkeinen 50f7018c21STomi Valkeinen p = (1 << p) - 1; 51f7018c21STomi Valkeinen if (fvco <= 100000) 52f7018c21STomi Valkeinen ; 53f7018c21STomi Valkeinen else if (fvco <= 140000) 54f7018c21STomi Valkeinen p |= 0x08; 55f7018c21STomi Valkeinen else if (fvco <= 180000) 56f7018c21STomi Valkeinen p |= 0x10; 57f7018c21STomi Valkeinen else 58f7018c21STomi Valkeinen p |= 0x18; 59f7018c21STomi Valkeinen *post = p; 60f7018c21STomi Valkeinen } 61f7018c21STomi Valkeinen 62f7018c21STomi Valkeinen /* they must be in POS order */ 63f7018c21STomi Valkeinen static const unsigned char MGA1064_DAC_regs[] = { 64f7018c21STomi Valkeinen M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL, 65f7018c21STomi Valkeinen M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE, 66f7018c21STomi Valkeinen M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE, 67f7018c21STomi Valkeinen M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE, 68f7018c21STomi Valkeinen DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL, 69f7018c21STomi Valkeinen M1064_XMISCCTRL, 70f7018c21STomi Valkeinen M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST, 71f7018c21STomi Valkeinen M1064_XCRCBITSEL, 72f7018c21STomi Valkeinen M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH }; 73f7018c21STomi Valkeinen 74f7018c21STomi Valkeinen static const unsigned char MGA1064_DAC[] = { 75f7018c21STomi Valkeinen 0x00, 0x00, M1064_XCURCTRL_DIS, 76f7018c21STomi Valkeinen 0x00, 0x00, 0x00, /* black */ 77f7018c21STomi Valkeinen 0xFF, 0xFF, 0xFF, /* white */ 78f7018c21STomi Valkeinen 0xFF, 0x00, 0x00, /* red */ 79f7018c21STomi Valkeinen 0x00, 0, 80f7018c21STomi Valkeinen M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL, 81f7018c21STomi Valkeinen M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN, 82f7018c21STomi Valkeinen M1064_XMISCCTRL_DAC_8BIT, 83f7018c21STomi Valkeinen 0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN, 84f7018c21STomi Valkeinen 0x00, 85f7018c21STomi Valkeinen 0x00, 0x00, 0xFF, 0xFF}; 86f7018c21STomi Valkeinen 87f7018c21STomi Valkeinen static void DAC1064_setpclk(struct matrox_fb_info *minfo, unsigned long fout) 88f7018c21STomi Valkeinen { 89f7018c21STomi Valkeinen unsigned int m, n, p; 90f7018c21STomi Valkeinen 91f7018c21STomi Valkeinen DBG(__func__) 92f7018c21STomi Valkeinen 93f7018c21STomi Valkeinen DAC1064_calcclock(minfo, fout, minfo->max_pixel_clock, &m, &n, &p); 94f7018c21STomi Valkeinen minfo->hw.DACclk[0] = m; 95f7018c21STomi Valkeinen minfo->hw.DACclk[1] = n; 96f7018c21STomi Valkeinen minfo->hw.DACclk[2] = p; 97f7018c21STomi Valkeinen } 98f7018c21STomi Valkeinen 99f7018c21STomi Valkeinen static void DAC1064_setmclk(struct matrox_fb_info *minfo, int oscinfo, 100f7018c21STomi Valkeinen unsigned long fmem) 101f7018c21STomi Valkeinen { 102f7018c21STomi Valkeinen u_int32_t mx; 103f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 104f7018c21STomi Valkeinen 105f7018c21STomi Valkeinen DBG(__func__) 106f7018c21STomi Valkeinen 107f7018c21STomi Valkeinen if (minfo->devflags.noinit) { 108f7018c21STomi Valkeinen /* read MCLK and give up... */ 109f7018c21STomi Valkeinen hw->DACclk[3] = inDAC1064(minfo, DAC1064_XSYSPLLM); 110f7018c21STomi Valkeinen hw->DACclk[4] = inDAC1064(minfo, DAC1064_XSYSPLLN); 111f7018c21STomi Valkeinen hw->DACclk[5] = inDAC1064(minfo, DAC1064_XSYSPLLP); 112f7018c21STomi Valkeinen return; 113f7018c21STomi Valkeinen } 114f7018c21STomi Valkeinen mx = hw->MXoptionReg | 0x00000004; 115f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx); 116f7018c21STomi Valkeinen mx &= ~0x000000BB; 117f7018c21STomi Valkeinen if (oscinfo & DAC1064_OPT_GDIV1) 118f7018c21STomi Valkeinen mx |= 0x00000008; 119f7018c21STomi Valkeinen if (oscinfo & DAC1064_OPT_MDIV1) 120f7018c21STomi Valkeinen mx |= 0x00000010; 121f7018c21STomi Valkeinen if (oscinfo & DAC1064_OPT_RESERVED) 122f7018c21STomi Valkeinen mx |= 0x00000080; 123f7018c21STomi Valkeinen if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) { 124f7018c21STomi Valkeinen /* select PCI clock until we have setup oscilator... */ 125f7018c21STomi Valkeinen int clk; 126f7018c21STomi Valkeinen unsigned int m, n, p; 127f7018c21STomi Valkeinen 128f7018c21STomi Valkeinen /* powerup system PLL, select PCI clock */ 129f7018c21STomi Valkeinen mx |= 0x00000020; 130f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx); 131f7018c21STomi Valkeinen mx &= ~0x00000004; 132f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx); 133f7018c21STomi Valkeinen 134f7018c21STomi Valkeinen /* !!! you must not access device if MCLK is not running !!! 135f7018c21STomi Valkeinen Doing so cause immediate PCI lockup :-( Maybe they should 136f7018c21STomi Valkeinen generate ABORT or I/O (parity...) error and Linux should 137f7018c21STomi Valkeinen recover from this... (kill driver/process). But world is not 138f7018c21STomi Valkeinen perfect... */ 139f7018c21STomi Valkeinen /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not 140f7018c21STomi Valkeinen select PLL... because of PLL can be stopped at this time) */ 141f7018c21STomi Valkeinen DAC1064_calcclock(minfo, fmem, minfo->max_pixel_clock, &m, &n, &p); 142f7018c21STomi Valkeinen outDAC1064(minfo, DAC1064_XSYSPLLM, hw->DACclk[3] = m); 143f7018c21STomi Valkeinen outDAC1064(minfo, DAC1064_XSYSPLLN, hw->DACclk[4] = n); 144f7018c21STomi Valkeinen outDAC1064(minfo, DAC1064_XSYSPLLP, hw->DACclk[5] = p); 145f7018c21STomi Valkeinen for (clk = 65536; clk; --clk) { 146f7018c21STomi Valkeinen if (inDAC1064(minfo, DAC1064_XSYSPLLSTAT) & 0x40) 147f7018c21STomi Valkeinen break; 148f7018c21STomi Valkeinen } 149f7018c21STomi Valkeinen if (!clk) 150f7018c21STomi Valkeinen printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n"); 151f7018c21STomi Valkeinen /* select PLL */ 152f7018c21STomi Valkeinen mx |= 0x00000005; 153f7018c21STomi Valkeinen } else { 154f7018c21STomi Valkeinen /* select specified system clock source */ 155f7018c21STomi Valkeinen mx |= oscinfo & DAC1064_OPT_SCLK_MASK; 156f7018c21STomi Valkeinen } 157f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx); 158f7018c21STomi Valkeinen mx &= ~0x00000004; 159f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx); 160f7018c21STomi Valkeinen hw->MXoptionReg = mx; 161f7018c21STomi Valkeinen } 162f7018c21STomi Valkeinen 163f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G 164f7018c21STomi Valkeinen static void g450_set_plls(struct matrox_fb_info *minfo) 165f7018c21STomi Valkeinen { 166f7018c21STomi Valkeinen u_int32_t c2_ctl; 167f7018c21STomi Valkeinen unsigned int pxc; 168f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 169f7018c21STomi Valkeinen int pixelmnp; 170f7018c21STomi Valkeinen int videomnp; 171f7018c21STomi Valkeinen 172f7018c21STomi Valkeinen c2_ctl = hw->crtc2.ctl & ~0x4007; /* Clear PLL + enable for CRTC2 */ 173f7018c21STomi Valkeinen c2_ctl |= 0x0001; /* Enable CRTC2 */ 174f7018c21STomi Valkeinen hw->DACreg[POS1064_XPWRCTRL] &= ~0x02; /* Stop VIDEO PLL */ 175f7018c21STomi Valkeinen pixelmnp = minfo->crtc1.mnp; 176f7018c21STomi Valkeinen videomnp = minfo->crtc2.mnp; 177f7018c21STomi Valkeinen if (videomnp < 0) { 178f7018c21STomi Valkeinen c2_ctl &= ~0x0001; /* Disable CRTC2 */ 179f7018c21STomi Valkeinen hw->DACreg[POS1064_XPWRCTRL] &= ~0x10; /* Powerdown CRTC2 */ 180f7018c21STomi Valkeinen } else if (minfo->crtc2.pixclock == minfo->features.pll.ref_freq) { 181f7018c21STomi Valkeinen c2_ctl |= 0x4002; /* Use reference directly */ 182f7018c21STomi Valkeinen } else if (videomnp == pixelmnp) { 183f7018c21STomi Valkeinen c2_ctl |= 0x0004; /* Use pixel PLL */ 184f7018c21STomi Valkeinen } else { 185f7018c21STomi Valkeinen if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) { 186f7018c21STomi Valkeinen /* PIXEL and VIDEO PLL must not use same frequency. We modify N 187f7018c21STomi Valkeinen of PIXEL PLL in such case because of VIDEO PLL may be source 188f7018c21STomi Valkeinen of TVO clocks, and chroma subcarrier is derived from its 189f7018c21STomi Valkeinen pixel clocks */ 190f7018c21STomi Valkeinen pixelmnp += 0x000100; 191f7018c21STomi Valkeinen } 192f7018c21STomi Valkeinen c2_ctl |= 0x0006; /* Use video PLL */ 193f7018c21STomi Valkeinen hw->DACreg[POS1064_XPWRCTRL] |= 0x02; 194f7018c21STomi Valkeinen 195f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]); 196f7018c21STomi Valkeinen matroxfb_g450_setpll_cond(minfo, videomnp, M_VIDEO_PLL); 197f7018c21STomi Valkeinen } 198f7018c21STomi Valkeinen 199f7018c21STomi Valkeinen hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP; 200f7018c21STomi Valkeinen if (pixelmnp >= 0) { 201f7018c21STomi Valkeinen hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP; 202f7018c21STomi Valkeinen 203f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]); 204f7018c21STomi Valkeinen matroxfb_g450_setpll_cond(minfo, pixelmnp, M_PIXEL_PLL_C); 205f7018c21STomi Valkeinen } 206f7018c21STomi Valkeinen if (c2_ctl != hw->crtc2.ctl) { 207f7018c21STomi Valkeinen hw->crtc2.ctl = c2_ctl; 208f7018c21STomi Valkeinen mga_outl(0x3C10, c2_ctl); 209f7018c21STomi Valkeinen } 210f7018c21STomi Valkeinen 211f7018c21STomi Valkeinen pxc = minfo->crtc1.pixclock; 212f7018c21STomi Valkeinen if (pxc == 0 || minfo->outputs[2].src == MATROXFB_SRC_CRTC2) { 213f7018c21STomi Valkeinen pxc = minfo->crtc2.pixclock; 214f7018c21STomi Valkeinen } 215f7018c21STomi Valkeinen if (minfo->chip == MGA_G550) { 216f7018c21STomi Valkeinen if (pxc < 45000) { 217f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x00; /* 0-50 */ 218f7018c21STomi Valkeinen } else if (pxc < 55000) { 219f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x08; /* 34-62 */ 220f7018c21STomi Valkeinen } else if (pxc < 70000) { 221f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x10; /* 42-78 */ 222f7018c21STomi Valkeinen } else if (pxc < 85000) { 223f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x18; /* 62-92 */ 224f7018c21STomi Valkeinen } else if (pxc < 100000) { 225f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x20; /* 74-108 */ 226f7018c21STomi Valkeinen } else if (pxc < 115000) { 227f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x28; /* 94-122 */ 228f7018c21STomi Valkeinen } else if (pxc < 125000) { 229f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x30; /* 108-132 */ 230f7018c21STomi Valkeinen } else { 231f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x38; /* 120-168 */ 232f7018c21STomi Valkeinen } 233f7018c21STomi Valkeinen } else { 234f7018c21STomi Valkeinen /* G450 */ 235f7018c21STomi Valkeinen if (pxc < 45000) { 236f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x00; /* 0-54 */ 237f7018c21STomi Valkeinen } else if (pxc < 65000) { 238f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x08; /* 38-70 */ 239f7018c21STomi Valkeinen } else if (pxc < 85000) { 240f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x10; /* 56-96 */ 241f7018c21STomi Valkeinen } else if (pxc < 105000) { 242f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x18; /* 80-114 */ 243f7018c21STomi Valkeinen } else if (pxc < 135000) { 244f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x20; /* 102-144 */ 245f7018c21STomi Valkeinen } else if (pxc < 160000) { 246f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x28; /* 132-166 */ 247f7018c21STomi Valkeinen } else if (pxc < 175000) { 248f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x30; /* 154-182 */ 249f7018c21STomi Valkeinen } else { 250f7018c21STomi Valkeinen hw->DACreg[POS1064_XPANMODE] = 0x38; /* 170-204 */ 251f7018c21STomi Valkeinen } 252f7018c21STomi Valkeinen } 253f7018c21STomi Valkeinen } 254f7018c21STomi Valkeinen #endif 255f7018c21STomi Valkeinen 256f7018c21STomi Valkeinen void DAC1064_global_init(struct matrox_fb_info *minfo) 257f7018c21STomi Valkeinen { 258f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 259f7018c21STomi Valkeinen 260f7018c21STomi Valkeinen hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK; 261f7018c21STomi Valkeinen hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN; 262f7018c21STomi Valkeinen hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL; 263f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G 264f7018c21STomi Valkeinen if (minfo->devflags.g450dac) { 265f7018c21STomi Valkeinen hw->DACreg[POS1064_XPWRCTRL] = 0x1F; /* powerup everything */ 266f7018c21STomi Valkeinen hw->DACreg[POS1064_XOUTPUTCONN] = 0x00; /* disable outputs */ 267f7018c21STomi Valkeinen hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN; 268f7018c21STomi Valkeinen switch (minfo->outputs[0].src) { 269f7018c21STomi Valkeinen case MATROXFB_SRC_CRTC1: 270f7018c21STomi Valkeinen case MATROXFB_SRC_CRTC2: 271f7018c21STomi Valkeinen hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01; /* enable output; CRTC1/2 selection is in CRTC2 ctl */ 272f7018c21STomi Valkeinen break; 273f7018c21STomi Valkeinen case MATROXFB_SRC_NONE: 274f7018c21STomi Valkeinen hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN; 275f7018c21STomi Valkeinen break; 276f7018c21STomi Valkeinen } 277f7018c21STomi Valkeinen switch (minfo->outputs[1].src) { 278f7018c21STomi Valkeinen case MATROXFB_SRC_CRTC1: 279f7018c21STomi Valkeinen hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04; 280f7018c21STomi Valkeinen break; 281f7018c21STomi Valkeinen case MATROXFB_SRC_CRTC2: 282f7018c21STomi Valkeinen if (minfo->outputs[1].mode == MATROXFB_OUTPUT_MODE_MONITOR) { 283f7018c21STomi Valkeinen hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08; 284f7018c21STomi Valkeinen } else { 285f7018c21STomi Valkeinen hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C; 286f7018c21STomi Valkeinen } 287f7018c21STomi Valkeinen break; 288f7018c21STomi Valkeinen case MATROXFB_SRC_NONE: 289f7018c21STomi Valkeinen hw->DACreg[POS1064_XPWRCTRL] &= ~0x01; /* Poweroff DAC2 */ 290f7018c21STomi Valkeinen break; 291f7018c21STomi Valkeinen } 292f7018c21STomi Valkeinen switch (minfo->outputs[2].src) { 293f7018c21STomi Valkeinen case MATROXFB_SRC_CRTC1: 294f7018c21STomi Valkeinen hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20; 295f7018c21STomi Valkeinen break; 296f7018c21STomi Valkeinen case MATROXFB_SRC_CRTC2: 297f7018c21STomi Valkeinen hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40; 298f7018c21STomi Valkeinen break; 299f7018c21STomi Valkeinen case MATROXFB_SRC_NONE: 300f7018c21STomi Valkeinen #if 0 301f7018c21STomi Valkeinen /* HELP! If we boot without DFP connected to DVI, we can 302f7018c21STomi Valkeinen poweroff TMDS. But if we boot with DFP connected, 303f7018c21STomi Valkeinen TMDS generated clocks are used instead of ALL pixclocks 304f7018c21STomi Valkeinen available... If someone knows which register 305f7018c21STomi Valkeinen handles it, please reveal this secret to me... */ 306f7018c21STomi Valkeinen hw->DACreg[POS1064_XPWRCTRL] &= ~0x04; /* Poweroff TMDS */ 307f7018c21STomi Valkeinen #endif 308f7018c21STomi Valkeinen break; 309f7018c21STomi Valkeinen } 310f7018c21STomi Valkeinen /* Now set timming related variables... */ 311f7018c21STomi Valkeinen g450_set_plls(minfo); 312f7018c21STomi Valkeinen } else 313f7018c21STomi Valkeinen #endif 314f7018c21STomi Valkeinen { 315f7018c21STomi Valkeinen if (minfo->outputs[1].src == MATROXFB_SRC_CRTC1) { 316f7018c21STomi Valkeinen hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT; 317f7018c21STomi Valkeinen hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12; 318f7018c21STomi Valkeinen } else if (minfo->outputs[1].src == MATROXFB_SRC_CRTC2) { 319f7018c21STomi Valkeinen hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12; 320f7018c21STomi Valkeinen } else if (minfo->outputs[2].src == MATROXFB_SRC_CRTC1) 321f7018c21STomi Valkeinen hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12; 322f7018c21STomi Valkeinen else 323f7018c21STomi Valkeinen hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS; 324f7018c21STomi Valkeinen 325f7018c21STomi Valkeinen if (minfo->outputs[0].src != MATROXFB_SRC_NONE) 326f7018c21STomi Valkeinen hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN; 327f7018c21STomi Valkeinen } 328f7018c21STomi Valkeinen } 329f7018c21STomi Valkeinen 330f7018c21STomi Valkeinen void DAC1064_global_restore(struct matrox_fb_info *minfo) 331f7018c21STomi Valkeinen { 332f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 333f7018c21STomi Valkeinen 334f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]); 335f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]); 336f7018c21STomi Valkeinen if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) { 337f7018c21STomi Valkeinen outDAC1064(minfo, 0x20, 0x04); 338f7018c21STomi Valkeinen outDAC1064(minfo, 0x1F, minfo->devflags.dfp_type); 339f7018c21STomi Valkeinen if (minfo->devflags.g450dac) { 340f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XSYNCCTRL, 0xCC); 341f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]); 342f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]); 343f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]); 344f7018c21STomi Valkeinen } 345f7018c21STomi Valkeinen } 346f7018c21STomi Valkeinen } 347f7018c21STomi Valkeinen 348f7018c21STomi Valkeinen static int DAC1064_init_1(struct matrox_fb_info *minfo, struct my_timming *m) 349f7018c21STomi Valkeinen { 350f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 351f7018c21STomi Valkeinen 352f7018c21STomi Valkeinen DBG(__func__) 353f7018c21STomi Valkeinen 354f7018c21STomi Valkeinen memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); 355f7018c21STomi Valkeinen switch (minfo->fbcon.var.bits_per_pixel) { 356f7018c21STomi Valkeinen /* case 4: not supported by MGA1064 DAC */ 357f7018c21STomi Valkeinen case 8: 358f7018c21STomi Valkeinen hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; 359f7018c21STomi Valkeinen break; 360f7018c21STomi Valkeinen case 16: 361f7018c21STomi Valkeinen if (minfo->fbcon.var.green.length == 5) 362f7018c21STomi Valkeinen hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; 363f7018c21STomi Valkeinen else 364f7018c21STomi Valkeinen hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; 365f7018c21STomi Valkeinen break; 366f7018c21STomi Valkeinen case 24: 367f7018c21STomi Valkeinen hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; 368f7018c21STomi Valkeinen break; 369f7018c21STomi Valkeinen case 32: 370f7018c21STomi Valkeinen hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; 371f7018c21STomi Valkeinen break; 372f7018c21STomi Valkeinen default: 373f7018c21STomi Valkeinen return 1; /* unsupported depth */ 374f7018c21STomi Valkeinen } 375f7018c21STomi Valkeinen hw->DACreg[POS1064_XVREFCTRL] = minfo->features.DAC1064.xvrefctrl; 376f7018c21STomi Valkeinen hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK; 377f7018c21STomi Valkeinen hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN; 378f7018c21STomi Valkeinen hw->DACreg[POS1064_XCURADDL] = 0; 379f7018c21STomi Valkeinen hw->DACreg[POS1064_XCURADDH] = 0; 380f7018c21STomi Valkeinen 381f7018c21STomi Valkeinen DAC1064_global_init(minfo); 382f7018c21STomi Valkeinen return 0; 383f7018c21STomi Valkeinen } 384f7018c21STomi Valkeinen 385f7018c21STomi Valkeinen static int DAC1064_init_2(struct matrox_fb_info *minfo, struct my_timming *m) 386f7018c21STomi Valkeinen { 387f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 388f7018c21STomi Valkeinen 389f7018c21STomi Valkeinen DBG(__func__) 390f7018c21STomi Valkeinen 391f7018c21STomi Valkeinen if (minfo->fbcon.var.bits_per_pixel > 16) { /* 256 entries */ 392f7018c21STomi Valkeinen int i; 393f7018c21STomi Valkeinen 394f7018c21STomi Valkeinen for (i = 0; i < 256; i++) { 395f7018c21STomi Valkeinen hw->DACpal[i * 3 + 0] = i; 396f7018c21STomi Valkeinen hw->DACpal[i * 3 + 1] = i; 397f7018c21STomi Valkeinen hw->DACpal[i * 3 + 2] = i; 398f7018c21STomi Valkeinen } 399f7018c21STomi Valkeinen } else if (minfo->fbcon.var.bits_per_pixel > 8) { 400f7018c21STomi Valkeinen if (minfo->fbcon.var.green.length == 5) { /* 0..31, 128..159 */ 401f7018c21STomi Valkeinen int i; 402f7018c21STomi Valkeinen 403f7018c21STomi Valkeinen for (i = 0; i < 32; i++) { 404f7018c21STomi Valkeinen /* with p15 == 0 */ 405f7018c21STomi Valkeinen hw->DACpal[i * 3 + 0] = i << 3; 406f7018c21STomi Valkeinen hw->DACpal[i * 3 + 1] = i << 3; 407f7018c21STomi Valkeinen hw->DACpal[i * 3 + 2] = i << 3; 408f7018c21STomi Valkeinen /* with p15 == 1 */ 409f7018c21STomi Valkeinen hw->DACpal[(i + 128) * 3 + 0] = i << 3; 410f7018c21STomi Valkeinen hw->DACpal[(i + 128) * 3 + 1] = i << 3; 411f7018c21STomi Valkeinen hw->DACpal[(i + 128) * 3 + 2] = i << 3; 412f7018c21STomi Valkeinen } 413f7018c21STomi Valkeinen } else { 414f7018c21STomi Valkeinen int i; 415f7018c21STomi Valkeinen 416f7018c21STomi Valkeinen for (i = 0; i < 64; i++) { /* 0..63 */ 417f7018c21STomi Valkeinen hw->DACpal[i * 3 + 0] = i << 3; 418f7018c21STomi Valkeinen hw->DACpal[i * 3 + 1] = i << 2; 419f7018c21STomi Valkeinen hw->DACpal[i * 3 + 2] = i << 3; 420f7018c21STomi Valkeinen } 421f7018c21STomi Valkeinen } 422f7018c21STomi Valkeinen } else { 423f7018c21STomi Valkeinen memset(hw->DACpal, 0, 768); 424f7018c21STomi Valkeinen } 425f7018c21STomi Valkeinen return 0; 426f7018c21STomi Valkeinen } 427f7018c21STomi Valkeinen 428f7018c21STomi Valkeinen static void DAC1064_restore_1(struct matrox_fb_info *minfo) 429f7018c21STomi Valkeinen { 430f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 431f7018c21STomi Valkeinen 432f7018c21STomi Valkeinen CRITFLAGS 433f7018c21STomi Valkeinen 434f7018c21STomi Valkeinen DBG(__func__) 435f7018c21STomi Valkeinen 436f7018c21STomi Valkeinen CRITBEGIN 437f7018c21STomi Valkeinen 438f7018c21STomi Valkeinen if ((inDAC1064(minfo, DAC1064_XSYSPLLM) != hw->DACclk[3]) || 439f7018c21STomi Valkeinen (inDAC1064(minfo, DAC1064_XSYSPLLN) != hw->DACclk[4]) || 440f7018c21STomi Valkeinen (inDAC1064(minfo, DAC1064_XSYSPLLP) != hw->DACclk[5])) { 441f7018c21STomi Valkeinen outDAC1064(minfo, DAC1064_XSYSPLLM, hw->DACclk[3]); 442f7018c21STomi Valkeinen outDAC1064(minfo, DAC1064_XSYSPLLN, hw->DACclk[4]); 443f7018c21STomi Valkeinen outDAC1064(minfo, DAC1064_XSYSPLLP, hw->DACclk[5]); 444f7018c21STomi Valkeinen } 445f7018c21STomi Valkeinen { 446f7018c21STomi Valkeinen unsigned int i; 447f7018c21STomi Valkeinen 448f7018c21STomi Valkeinen for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { 449f7018c21STomi Valkeinen if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL)) 450f7018c21STomi Valkeinen outDAC1064(minfo, MGA1064_DAC_regs[i], hw->DACreg[i]); 451f7018c21STomi Valkeinen } 452f7018c21STomi Valkeinen } 453f7018c21STomi Valkeinen 454f7018c21STomi Valkeinen DAC1064_global_restore(minfo); 455f7018c21STomi Valkeinen 456f7018c21STomi Valkeinen CRITEND 457f7018c21STomi Valkeinen }; 458f7018c21STomi Valkeinen 459f7018c21STomi Valkeinen static void DAC1064_restore_2(struct matrox_fb_info *minfo) 460f7018c21STomi Valkeinen { 461f7018c21STomi Valkeinen #ifdef DEBUG 462f7018c21STomi Valkeinen unsigned int i; 463f7018c21STomi Valkeinen #endif 464f7018c21STomi Valkeinen 465f7018c21STomi Valkeinen DBG(__func__) 466f7018c21STomi Valkeinen 467f7018c21STomi Valkeinen #ifdef DEBUG 468f7018c21STomi Valkeinen dprintk(KERN_DEBUG "DAC1064regs "); 469f7018c21STomi Valkeinen for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { 470f7018c21STomi Valkeinen dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], minfo->hw.DACreg[i]); 471f7018c21STomi Valkeinen if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... "); 472f7018c21STomi Valkeinen } 473f7018c21STomi Valkeinen dprintk(KERN_DEBUG "DAC1064clk "); 474f7018c21STomi Valkeinen for (i = 0; i < 6; i++) 475f7018c21STomi Valkeinen dprintk("C%02X=%02X ", i, minfo->hw.DACclk[i]); 476f7018c21STomi Valkeinen dprintk("\n"); 477f7018c21STomi Valkeinen #endif 478f7018c21STomi Valkeinen } 479f7018c21STomi Valkeinen 480f7018c21STomi Valkeinen static int m1064_compute(void* out, struct my_timming* m) { 481f7018c21STomi Valkeinen #define minfo ((struct matrox_fb_info*)out) 482f7018c21STomi Valkeinen { 483f7018c21STomi Valkeinen int i; 484f7018c21STomi Valkeinen int tmout; 485f7018c21STomi Valkeinen CRITFLAGS 486f7018c21STomi Valkeinen 487f7018c21STomi Valkeinen DAC1064_setpclk(minfo, m->pixclock); 488f7018c21STomi Valkeinen 489f7018c21STomi Valkeinen CRITBEGIN 490f7018c21STomi Valkeinen 491f7018c21STomi Valkeinen for (i = 0; i < 3; i++) 492f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XPIXPLLCM + i, minfo->hw.DACclk[i]); 493f7018c21STomi Valkeinen for (tmout = 500000; tmout; tmout--) { 494f7018c21STomi Valkeinen if (inDAC1064(minfo, M1064_XPIXPLLSTAT) & 0x40) 495f7018c21STomi Valkeinen break; 496f7018c21STomi Valkeinen udelay(10); 497f7018c21STomi Valkeinen } 498f7018c21STomi Valkeinen 499f7018c21STomi Valkeinen CRITEND 500f7018c21STomi Valkeinen 501f7018c21STomi Valkeinen if (!tmout) 502f7018c21STomi Valkeinen printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); 503f7018c21STomi Valkeinen } 504f7018c21STomi Valkeinen #undef minfo 505f7018c21STomi Valkeinen return 0; 506f7018c21STomi Valkeinen } 507f7018c21STomi Valkeinen 508f7018c21STomi Valkeinen static struct matrox_altout m1064 = { 509f7018c21STomi Valkeinen .name = "Primary output", 510f7018c21STomi Valkeinen .compute = m1064_compute, 511f7018c21STomi Valkeinen }; 512f7018c21STomi Valkeinen 513f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G 514f7018c21STomi Valkeinen static int g450_compute(void* out, struct my_timming* m) { 515f7018c21STomi Valkeinen #define minfo ((struct matrox_fb_info*)out) 516f7018c21STomi Valkeinen if (m->mnp < 0) { 517f7018c21STomi Valkeinen m->mnp = matroxfb_g450_setclk(minfo, m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL); 518f7018c21STomi Valkeinen if (m->mnp >= 0) { 519f7018c21STomi Valkeinen m->pixclock = g450_mnp2f(minfo, m->mnp); 520f7018c21STomi Valkeinen } 521f7018c21STomi Valkeinen } 522f7018c21STomi Valkeinen #undef minfo 523f7018c21STomi Valkeinen return 0; 524f7018c21STomi Valkeinen } 525f7018c21STomi Valkeinen 526f7018c21STomi Valkeinen static struct matrox_altout g450out = { 527f7018c21STomi Valkeinen .name = "Primary output", 528f7018c21STomi Valkeinen .compute = g450_compute, 529f7018c21STomi Valkeinen }; 530f7018c21STomi Valkeinen #endif 531f7018c21STomi Valkeinen 532f7018c21STomi Valkeinen #endif /* NEED_DAC1064 */ 533f7018c21STomi Valkeinen 534f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_MYSTIQUE 535f7018c21STomi Valkeinen static int MGA1064_init(struct matrox_fb_info *minfo, struct my_timming *m) 536f7018c21STomi Valkeinen { 537f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 538f7018c21STomi Valkeinen 539f7018c21STomi Valkeinen DBG(__func__) 540f7018c21STomi Valkeinen 541f7018c21STomi Valkeinen if (DAC1064_init_1(minfo, m)) return 1; 542f7018c21STomi Valkeinen if (matroxfb_vgaHWinit(minfo, m)) return 1; 543f7018c21STomi Valkeinen 544f7018c21STomi Valkeinen hw->MiscOutReg = 0xCB; 545f7018c21STomi Valkeinen if (m->sync & FB_SYNC_HOR_HIGH_ACT) 546f7018c21STomi Valkeinen hw->MiscOutReg &= ~0x40; 547f7018c21STomi Valkeinen if (m->sync & FB_SYNC_VERT_HIGH_ACT) 548f7018c21STomi Valkeinen hw->MiscOutReg &= ~0x80; 549f7018c21STomi Valkeinen if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ 550f7018c21STomi Valkeinen hw->CRTCEXT[3] |= 0x40; 551f7018c21STomi Valkeinen 552f7018c21STomi Valkeinen if (DAC1064_init_2(minfo, m)) return 1; 553f7018c21STomi Valkeinen return 0; 554f7018c21STomi Valkeinen } 555f7018c21STomi Valkeinen #endif 556f7018c21STomi Valkeinen 557f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G 558f7018c21STomi Valkeinen static int MGAG100_init(struct matrox_fb_info *minfo, struct my_timming *m) 559f7018c21STomi Valkeinen { 560f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 561f7018c21STomi Valkeinen 562f7018c21STomi Valkeinen DBG(__func__) 563f7018c21STomi Valkeinen 564f7018c21STomi Valkeinen if (DAC1064_init_1(minfo, m)) return 1; 565f7018c21STomi Valkeinen hw->MXoptionReg &= ~0x2000; 566f7018c21STomi Valkeinen if (matroxfb_vgaHWinit(minfo, m)) return 1; 567f7018c21STomi Valkeinen 568f7018c21STomi Valkeinen hw->MiscOutReg = 0xEF; 569f7018c21STomi Valkeinen if (m->sync & FB_SYNC_HOR_HIGH_ACT) 570f7018c21STomi Valkeinen hw->MiscOutReg &= ~0x40; 571f7018c21STomi Valkeinen if (m->sync & FB_SYNC_VERT_HIGH_ACT) 572f7018c21STomi Valkeinen hw->MiscOutReg &= ~0x80; 573f7018c21STomi Valkeinen if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ 574f7018c21STomi Valkeinen hw->CRTCEXT[3] |= 0x40; 575f7018c21STomi Valkeinen 576f7018c21STomi Valkeinen if (DAC1064_init_2(minfo, m)) return 1; 577f7018c21STomi Valkeinen return 0; 578f7018c21STomi Valkeinen } 579f7018c21STomi Valkeinen #endif /* G */ 580f7018c21STomi Valkeinen 581f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_MYSTIQUE 582f7018c21STomi Valkeinen static void MGA1064_ramdac_init(struct matrox_fb_info *minfo) 583f7018c21STomi Valkeinen { 584f7018c21STomi Valkeinen 585f7018c21STomi Valkeinen DBG(__func__) 586f7018c21STomi Valkeinen 587f7018c21STomi Valkeinen /* minfo->features.DAC1064.vco_freq_min = 120000; */ 588f7018c21STomi Valkeinen minfo->features.pll.vco_freq_min = 62000; 589f7018c21STomi Valkeinen minfo->features.pll.ref_freq = 14318; 590f7018c21STomi Valkeinen minfo->features.pll.feed_div_min = 100; 591f7018c21STomi Valkeinen minfo->features.pll.feed_div_max = 127; 592f7018c21STomi Valkeinen minfo->features.pll.in_div_min = 1; 593f7018c21STomi Valkeinen minfo->features.pll.in_div_max = 31; 594f7018c21STomi Valkeinen minfo->features.pll.post_shift_max = 3; 595f7018c21STomi Valkeinen minfo->features.DAC1064.xvrefctrl = DAC1064_XVREFCTRL_EXTERNAL; 596f7018c21STomi Valkeinen /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */ 597f7018c21STomi Valkeinen DAC1064_setmclk(minfo, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333); 598f7018c21STomi Valkeinen } 599f7018c21STomi Valkeinen #endif 600f7018c21STomi Valkeinen 601f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G 602f7018c21STomi Valkeinen /* BIOS environ */ 603f7018c21STomi Valkeinen static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */ 604f7018c21STomi Valkeinen /* G100 wants 0x10, G200 SGRAM does not care... */ 605f7018c21STomi Valkeinen #if 0 606f7018c21STomi Valkeinen static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */ 607f7018c21STomi Valkeinen #endif 608f7018c21STomi Valkeinen 609f7018c21STomi Valkeinen static void MGAG100_progPixClock(const struct matrox_fb_info *minfo, int flags, 610f7018c21STomi Valkeinen int m, int n, int p) 611f7018c21STomi Valkeinen { 612f7018c21STomi Valkeinen int reg; 613f7018c21STomi Valkeinen int selClk; 614f7018c21STomi Valkeinen int clk; 615f7018c21STomi Valkeinen 616f7018c21STomi Valkeinen DBG(__func__) 617f7018c21STomi Valkeinen 618f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XPIXCLKCTRL, inDAC1064(minfo, M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS | 619f7018c21STomi Valkeinen M1064_XPIXCLKCTRL_PLL_UP); 620f7018c21STomi Valkeinen switch (flags & 3) { 621f7018c21STomi Valkeinen case 0: reg = M1064_XPIXPLLAM; break; 622f7018c21STomi Valkeinen case 1: reg = M1064_XPIXPLLBM; break; 623f7018c21STomi Valkeinen default: reg = M1064_XPIXPLLCM; break; 624f7018c21STomi Valkeinen } 625f7018c21STomi Valkeinen outDAC1064(minfo, reg++, m); 626f7018c21STomi Valkeinen outDAC1064(minfo, reg++, n); 627f7018c21STomi Valkeinen outDAC1064(minfo, reg, p); 628f7018c21STomi Valkeinen selClk = mga_inb(M_MISC_REG_READ) & ~0xC; 629f7018c21STomi Valkeinen /* there should be flags & 0x03 & case 0/1/else */ 630f7018c21STomi Valkeinen /* and we should first select source and after that we should wait for PLL */ 631f7018c21STomi Valkeinen /* and we are waiting for PLL with oscilator disabled... Is it right? */ 632f7018c21STomi Valkeinen switch (flags & 0x03) { 633f7018c21STomi Valkeinen case 0x00: break; 634f7018c21STomi Valkeinen case 0x01: selClk |= 4; break; 635f7018c21STomi Valkeinen default: selClk |= 0x0C; break; 636f7018c21STomi Valkeinen } 637f7018c21STomi Valkeinen mga_outb(M_MISC_REG, selClk); 638f7018c21STomi Valkeinen for (clk = 500000; clk; clk--) { 639f7018c21STomi Valkeinen if (inDAC1064(minfo, M1064_XPIXPLLSTAT) & 0x40) 640f7018c21STomi Valkeinen break; 641f7018c21STomi Valkeinen udelay(10); 642f7018c21STomi Valkeinen } 643f7018c21STomi Valkeinen if (!clk) 644f7018c21STomi Valkeinen printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A'); 645f7018c21STomi Valkeinen selClk = inDAC1064(minfo, M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK; 646f7018c21STomi Valkeinen switch (flags & 0x0C) { 647f7018c21STomi Valkeinen case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break; 648f7018c21STomi Valkeinen case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break; 649f7018c21STomi Valkeinen default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break; 650f7018c21STomi Valkeinen } 651f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XPIXCLKCTRL, selClk); 652f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XPIXCLKCTRL, inDAC1064(minfo, M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS); 653f7018c21STomi Valkeinen } 654f7018c21STomi Valkeinen 655f7018c21STomi Valkeinen static void MGAG100_setPixClock(const struct matrox_fb_info *minfo, int flags, 656f7018c21STomi Valkeinen int freq) 657f7018c21STomi Valkeinen { 658f7018c21STomi Valkeinen unsigned int m, n, p; 659f7018c21STomi Valkeinen 660f7018c21STomi Valkeinen DBG(__func__) 661f7018c21STomi Valkeinen 662f7018c21STomi Valkeinen DAC1064_calcclock(minfo, freq, minfo->max_pixel_clock, &m, &n, &p); 663f7018c21STomi Valkeinen MGAG100_progPixClock(minfo, flags, m, n, p); 664f7018c21STomi Valkeinen } 665f7018c21STomi Valkeinen #endif 666f7018c21STomi Valkeinen 667f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_MYSTIQUE 668f7018c21STomi Valkeinen static int MGA1064_preinit(struct matrox_fb_info *minfo) 669f7018c21STomi Valkeinen { 670f7018c21STomi Valkeinen static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960, 671f7018c21STomi Valkeinen 1024, 1152, 1280, 1600, 1664, 1920, 672f7018c21STomi Valkeinen 2048, 0}; 673f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 674f7018c21STomi Valkeinen 675f7018c21STomi Valkeinen DBG(__func__) 676f7018c21STomi Valkeinen 677f7018c21STomi Valkeinen /* minfo->capable.cfb4 = 0; ... preinitialized by 0 */ 678f7018c21STomi Valkeinen minfo->capable.text = 1; 679f7018c21STomi Valkeinen minfo->capable.vxres = vxres_mystique; 680f7018c21STomi Valkeinen 681f7018c21STomi Valkeinen minfo->outputs[0].output = &m1064; 682f7018c21STomi Valkeinen minfo->outputs[0].src = minfo->outputs[0].default_src; 683f7018c21STomi Valkeinen minfo->outputs[0].data = minfo; 684f7018c21STomi Valkeinen minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR; 685f7018c21STomi Valkeinen 686f7018c21STomi Valkeinen if (minfo->devflags.noinit) 687f7018c21STomi Valkeinen return 0; /* do not modify settings */ 688f7018c21STomi Valkeinen hw->MXoptionReg &= 0xC0000100; 689f7018c21STomi Valkeinen hw->MXoptionReg |= 0x00094E20; 690f7018c21STomi Valkeinen if (minfo->devflags.novga) 691f7018c21STomi Valkeinen hw->MXoptionReg &= ~0x00000100; 692f7018c21STomi Valkeinen if (minfo->devflags.nobios) 693f7018c21STomi Valkeinen hw->MXoptionReg &= ~0x40000000; 694f7018c21STomi Valkeinen if (minfo->devflags.nopciretry) 695f7018c21STomi Valkeinen hw->MXoptionReg |= 0x20000000; 696f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg); 697f7018c21STomi Valkeinen mga_setr(M_SEQ_INDEX, 0x01, 0x20); 698f7018c21STomi Valkeinen mga_outl(M_CTLWTST, 0x00000000); 699f7018c21STomi Valkeinen udelay(200); 700f7018c21STomi Valkeinen mga_outl(M_MACCESS, 0x00008000); 701f7018c21STomi Valkeinen udelay(100); 702f7018c21STomi Valkeinen mga_outl(M_MACCESS, 0x0000C000); 703f7018c21STomi Valkeinen return 0; 704f7018c21STomi Valkeinen } 705f7018c21STomi Valkeinen 706f7018c21STomi Valkeinen static void MGA1064_reset(struct matrox_fb_info *minfo) 707f7018c21STomi Valkeinen { 708f7018c21STomi Valkeinen 709f7018c21STomi Valkeinen DBG(__func__); 710f7018c21STomi Valkeinen 711f7018c21STomi Valkeinen MGA1064_ramdac_init(minfo); 712f7018c21STomi Valkeinen } 713f7018c21STomi Valkeinen #endif 714f7018c21STomi Valkeinen 715f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G 716f7018c21STomi Valkeinen static void g450_mclk_init(struct matrox_fb_info *minfo) 717f7018c21STomi Valkeinen { 718f7018c21STomi Valkeinen /* switch all clocks to PCI source */ 719f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4); 720f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3 & ~0x00300C03); 721f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg); 722f7018c21STomi Valkeinen 723f7018c21STomi Valkeinen if (((minfo->values.reg.opt3 & 0x000003) == 0x000003) || 724f7018c21STomi Valkeinen ((minfo->values.reg.opt3 & 0x000C00) == 0x000C00) || 725f7018c21STomi Valkeinen ((minfo->values.reg.opt3 & 0x300000) == 0x300000)) { 726f7018c21STomi Valkeinen matroxfb_g450_setclk(minfo, minfo->values.pll.video, M_VIDEO_PLL); 727f7018c21STomi Valkeinen } else { 728f7018c21STomi Valkeinen unsigned long flags; 729f7018c21STomi Valkeinen unsigned int pwr; 730f7018c21STomi Valkeinen 731f7018c21STomi Valkeinen matroxfb_DAC_lock_irqsave(flags); 732f7018c21STomi Valkeinen pwr = inDAC1064(minfo, M1064_XPWRCTRL) & ~0x02; 733f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XPWRCTRL, pwr); 734f7018c21STomi Valkeinen matroxfb_DAC_unlock_irqrestore(flags); 735f7018c21STomi Valkeinen } 736f7018c21STomi Valkeinen matroxfb_g450_setclk(minfo, minfo->values.pll.system, M_SYSTEM_PLL); 737f7018c21STomi Valkeinen 738f7018c21STomi Valkeinen /* switch clocks to their real PLL source(s) */ 739f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4); 740f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3); 741f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg); 742f7018c21STomi Valkeinen 743f7018c21STomi Valkeinen } 744f7018c21STomi Valkeinen 745f7018c21STomi Valkeinen static void g450_memory_init(struct matrox_fb_info *minfo) 746f7018c21STomi Valkeinen { 747f7018c21STomi Valkeinen /* disable memory refresh */ 748f7018c21STomi Valkeinen minfo->hw.MXoptionReg &= ~0x001F8000; 749f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg); 750f7018c21STomi Valkeinen 751f7018c21STomi Valkeinen /* set memory interface parameters */ 752f7018c21STomi Valkeinen minfo->hw.MXoptionReg &= ~0x00207E00; 753f7018c21STomi Valkeinen minfo->hw.MXoptionReg |= 0x00207E00 & minfo->values.reg.opt; 754f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg); 755f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, minfo->values.reg.opt2); 756f7018c21STomi Valkeinen 757f7018c21STomi Valkeinen mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst); 758f7018c21STomi Valkeinen 759f7018c21STomi Valkeinen /* first set up memory interface with disabled memory interface clocks */ 760f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc & ~0x80000000U); 761f7018c21STomi Valkeinen mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk); 762f7018c21STomi Valkeinen mga_outl(M_MACCESS, minfo->values.reg.maccess); 763f7018c21STomi Valkeinen /* start memory clocks */ 764f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc | 0x80000000U); 765f7018c21STomi Valkeinen 766f7018c21STomi Valkeinen udelay(200); 767f7018c21STomi Valkeinen 768f7018c21STomi Valkeinen if (minfo->values.memory.ddr && (!minfo->values.memory.emrswen || !minfo->values.memory.dll)) { 769f7018c21STomi Valkeinen mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk & ~0x1000); 770f7018c21STomi Valkeinen } 771f7018c21STomi Valkeinen mga_outl(M_MACCESS, minfo->values.reg.maccess | 0x8000); 772f7018c21STomi Valkeinen 773f7018c21STomi Valkeinen udelay(200); 774f7018c21STomi Valkeinen 775f7018c21STomi Valkeinen minfo->hw.MXoptionReg |= 0x001F8000 & minfo->values.reg.opt; 776f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg); 777f7018c21STomi Valkeinen 778f7018c21STomi Valkeinen /* value is written to memory chips only if old != new */ 779f7018c21STomi Valkeinen mga_outl(M_PLNWT, 0); 780f7018c21STomi Valkeinen mga_outl(M_PLNWT, ~0); 781f7018c21STomi Valkeinen 782f7018c21STomi Valkeinen if (minfo->values.reg.mctlwtst != minfo->values.reg.mctlwtst_core) { 783f7018c21STomi Valkeinen mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst_core); 784f7018c21STomi Valkeinen } 785f7018c21STomi Valkeinen 786f7018c21STomi Valkeinen } 787f7018c21STomi Valkeinen 788f7018c21STomi Valkeinen static void g450_preinit(struct matrox_fb_info *minfo) 789f7018c21STomi Valkeinen { 790f7018c21STomi Valkeinen u_int32_t c2ctl; 791f7018c21STomi Valkeinen u_int8_t curctl; 792f7018c21STomi Valkeinen u_int8_t c1ctl; 793f7018c21STomi Valkeinen 794f7018c21STomi Valkeinen /* minfo->hw.MXoptionReg = minfo->values.reg.opt; */ 795f7018c21STomi Valkeinen minfo->hw.MXoptionReg &= 0xC0000100; 796f7018c21STomi Valkeinen minfo->hw.MXoptionReg |= 0x00000020; 797f7018c21STomi Valkeinen if (minfo->devflags.novga) 798f7018c21STomi Valkeinen minfo->hw.MXoptionReg &= ~0x00000100; 799f7018c21STomi Valkeinen if (minfo->devflags.nobios) 800f7018c21STomi Valkeinen minfo->hw.MXoptionReg &= ~0x40000000; 801f7018c21STomi Valkeinen if (minfo->devflags.nopciretry) 802f7018c21STomi Valkeinen minfo->hw.MXoptionReg |= 0x20000000; 803f7018c21STomi Valkeinen minfo->hw.MXoptionReg |= minfo->values.reg.opt & 0x03400040; 804f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg); 805f7018c21STomi Valkeinen 806f7018c21STomi Valkeinen /* Init system clocks */ 807f7018c21STomi Valkeinen 808f7018c21STomi Valkeinen /* stop crtc2 */ 809f7018c21STomi Valkeinen c2ctl = mga_inl(M_C2CTL); 810f7018c21STomi Valkeinen mga_outl(M_C2CTL, c2ctl & ~1); 811f7018c21STomi Valkeinen /* stop cursor */ 812f7018c21STomi Valkeinen curctl = inDAC1064(minfo, M1064_XCURCTRL); 813f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XCURCTRL, 0); 814f7018c21STomi Valkeinen /* stop crtc1 */ 815f7018c21STomi Valkeinen c1ctl = mga_readr(M_SEQ_INDEX, 1); 816f7018c21STomi Valkeinen mga_setr(M_SEQ_INDEX, 1, c1ctl | 0x20); 817f7018c21STomi Valkeinen 818f7018c21STomi Valkeinen g450_mclk_init(minfo); 819f7018c21STomi Valkeinen g450_memory_init(minfo); 820f7018c21STomi Valkeinen 821f7018c21STomi Valkeinen /* set legacy VGA clock sources for DOSEmu or VMware... */ 822f7018c21STomi Valkeinen matroxfb_g450_setclk(minfo, 25175, M_PIXEL_PLL_A); 823f7018c21STomi Valkeinen matroxfb_g450_setclk(minfo, 28322, M_PIXEL_PLL_B); 824f7018c21STomi Valkeinen 825f7018c21STomi Valkeinen /* restore crtc1 */ 826f7018c21STomi Valkeinen mga_setr(M_SEQ_INDEX, 1, c1ctl); 827f7018c21STomi Valkeinen 828f7018c21STomi Valkeinen /* restore cursor */ 829f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XCURCTRL, curctl); 830f7018c21STomi Valkeinen 831f7018c21STomi Valkeinen /* restore crtc2 */ 832f7018c21STomi Valkeinen mga_outl(M_C2CTL, c2ctl); 833f7018c21STomi Valkeinen 834f7018c21STomi Valkeinen return; 835f7018c21STomi Valkeinen } 836f7018c21STomi Valkeinen 837f7018c21STomi Valkeinen static int MGAG100_preinit(struct matrox_fb_info *minfo) 838f7018c21STomi Valkeinen { 839f7018c21STomi Valkeinen static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960, 840f7018c21STomi Valkeinen 1024, 1152, 1280, 1600, 1664, 1920, 841f7018c21STomi Valkeinen 2048, 0}; 842f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 843f7018c21STomi Valkeinen 844f7018c21STomi Valkeinen u_int32_t reg50; 845f7018c21STomi Valkeinen #if 0 846f7018c21STomi Valkeinen u_int32_t q; 847f7018c21STomi Valkeinen #endif 848f7018c21STomi Valkeinen 849f7018c21STomi Valkeinen DBG(__func__) 850f7018c21STomi Valkeinen 851f7018c21STomi Valkeinen /* there are some instabilities if in_div > 19 && vco < 61000 */ 852f7018c21STomi Valkeinen if (minfo->devflags.g450dac) { 853f7018c21STomi Valkeinen minfo->features.pll.vco_freq_min = 130000; /* my sample: >118 */ 854f7018c21STomi Valkeinen } else { 855f7018c21STomi Valkeinen minfo->features.pll.vco_freq_min = 62000; 856f7018c21STomi Valkeinen } 857f7018c21STomi Valkeinen if (!minfo->features.pll.ref_freq) { 858f7018c21STomi Valkeinen minfo->features.pll.ref_freq = 27000; 859f7018c21STomi Valkeinen } 860f7018c21STomi Valkeinen minfo->features.pll.feed_div_min = 7; 861f7018c21STomi Valkeinen minfo->features.pll.feed_div_max = 127; 862f7018c21STomi Valkeinen minfo->features.pll.in_div_min = 1; 863f7018c21STomi Valkeinen minfo->features.pll.in_div_max = 31; 864f7018c21STomi Valkeinen minfo->features.pll.post_shift_max = 3; 865f7018c21STomi Valkeinen minfo->features.DAC1064.xvrefctrl = DAC1064_XVREFCTRL_G100_DEFAULT; 866f7018c21STomi Valkeinen /* minfo->capable.cfb4 = 0; ... preinitialized by 0 */ 867f7018c21STomi Valkeinen minfo->capable.text = 1; 868f7018c21STomi Valkeinen minfo->capable.vxres = vxres_g100; 869f7018c21STomi Valkeinen minfo->capable.plnwt = minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100 870f7018c21STomi Valkeinen ? minfo->devflags.sgram : 1; 871f7018c21STomi Valkeinen 872f7018c21STomi Valkeinen if (minfo->devflags.g450dac) { 873f7018c21STomi Valkeinen minfo->outputs[0].output = &g450out; 874f7018c21STomi Valkeinen } else { 875f7018c21STomi Valkeinen minfo->outputs[0].output = &m1064; 876f7018c21STomi Valkeinen } 877f7018c21STomi Valkeinen minfo->outputs[0].src = minfo->outputs[0].default_src; 878f7018c21STomi Valkeinen minfo->outputs[0].data = minfo; 879f7018c21STomi Valkeinen minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR; 880f7018c21STomi Valkeinen 881f7018c21STomi Valkeinen if (minfo->devflags.g450dac) { 882f7018c21STomi Valkeinen /* we must do this always, BIOS does not do it for us 883f7018c21STomi Valkeinen and accelerator dies without it */ 884f7018c21STomi Valkeinen mga_outl(0x1C0C, 0); 885f7018c21STomi Valkeinen } 886f7018c21STomi Valkeinen if (minfo->devflags.noinit) 887f7018c21STomi Valkeinen return 0; 888f7018c21STomi Valkeinen if (minfo->devflags.g450dac) { 889f7018c21STomi Valkeinen g450_preinit(minfo); 890f7018c21STomi Valkeinen return 0; 891f7018c21STomi Valkeinen } 892f7018c21STomi Valkeinen hw->MXoptionReg &= 0xC0000100; 893f7018c21STomi Valkeinen hw->MXoptionReg |= 0x00000020; 894f7018c21STomi Valkeinen if (minfo->devflags.novga) 895f7018c21STomi Valkeinen hw->MXoptionReg &= ~0x00000100; 896f7018c21STomi Valkeinen if (minfo->devflags.nobios) 897f7018c21STomi Valkeinen hw->MXoptionReg &= ~0x40000000; 898f7018c21STomi Valkeinen if (minfo->devflags.nopciretry) 899f7018c21STomi Valkeinen hw->MXoptionReg |= 0x20000000; 900f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg); 901f7018c21STomi Valkeinen DAC1064_setmclk(minfo, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333); 902f7018c21STomi Valkeinen 903f7018c21STomi Valkeinen if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100) { 904f7018c21STomi Valkeinen pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, ®50); 905f7018c21STomi Valkeinen reg50 &= ~0x3000; 906f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50); 907f7018c21STomi Valkeinen 908f7018c21STomi Valkeinen hw->MXoptionReg |= 0x1080; 909f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg); 910f7018c21STomi Valkeinen mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst); 911f7018c21STomi Valkeinen udelay(100); 912f7018c21STomi Valkeinen mga_outb(0x1C05, 0x00); 913f7018c21STomi Valkeinen mga_outb(0x1C05, 0x80); 914f7018c21STomi Valkeinen udelay(100); 915f7018c21STomi Valkeinen mga_outb(0x1C05, 0x40); 916f7018c21STomi Valkeinen mga_outb(0x1C05, 0xC0); 917f7018c21STomi Valkeinen udelay(100); 918f7018c21STomi Valkeinen reg50 &= ~0xFF; 919f7018c21STomi Valkeinen reg50 |= 0x07; 920f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50); 921f7018c21STomi Valkeinen /* it should help with G100 */ 922f7018c21STomi Valkeinen mga_outb(M_GRAPHICS_INDEX, 6); 923f7018c21STomi Valkeinen mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4); 924f7018c21STomi Valkeinen mga_setr(M_EXTVGA_INDEX, 0x03, 0x81); 925f7018c21STomi Valkeinen mga_setr(M_EXTVGA_INDEX, 0x04, 0x00); 926f7018c21STomi Valkeinen mga_writeb(minfo->video.vbase, 0x0000, 0xAA); 927f7018c21STomi Valkeinen mga_writeb(minfo->video.vbase, 0x0800, 0x55); 928f7018c21STomi Valkeinen mga_writeb(minfo->video.vbase, 0x4000, 0x55); 929f7018c21STomi Valkeinen #if 0 930f7018c21STomi Valkeinen if (mga_readb(minfo->video.vbase, 0x0000) != 0xAA) { 931f7018c21STomi Valkeinen hw->MXoptionReg &= ~0x1000; 932f7018c21STomi Valkeinen } 933f7018c21STomi Valkeinen #endif 934f7018c21STomi Valkeinen hw->MXoptionReg |= 0x00078020; 935f7018c21STomi Valkeinen } else if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG200) { 936f7018c21STomi Valkeinen pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, ®50); 937f7018c21STomi Valkeinen reg50 &= ~0x3000; 938f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50); 939f7018c21STomi Valkeinen 940f7018c21STomi Valkeinen if (minfo->devflags.memtype == -1) 941f7018c21STomi Valkeinen hw->MXoptionReg |= minfo->values.reg.opt & 0x1C00; 942f7018c21STomi Valkeinen else 943f7018c21STomi Valkeinen hw->MXoptionReg |= (minfo->devflags.memtype & 7) << 10; 944f7018c21STomi Valkeinen if (minfo->devflags.sgram) 945f7018c21STomi Valkeinen hw->MXoptionReg |= 0x4000; 946f7018c21STomi Valkeinen mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst); 947f7018c21STomi Valkeinen mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk); 948f7018c21STomi Valkeinen udelay(200); 949f7018c21STomi Valkeinen mga_outl(M_MACCESS, 0x00000000); 950f7018c21STomi Valkeinen mga_outl(M_MACCESS, 0x00008000); 951f7018c21STomi Valkeinen udelay(100); 952f7018c21STomi Valkeinen mga_outw(M_MEMRDBK, minfo->values.reg.memrdbk); 953f7018c21STomi Valkeinen hw->MXoptionReg |= 0x00078020; 954f7018c21STomi Valkeinen } else { 955f7018c21STomi Valkeinen pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, ®50); 956f7018c21STomi Valkeinen reg50 &= ~0x00000100; 957f7018c21STomi Valkeinen reg50 |= 0x00000000; 958f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50); 959f7018c21STomi Valkeinen 960f7018c21STomi Valkeinen if (minfo->devflags.memtype == -1) 961f7018c21STomi Valkeinen hw->MXoptionReg |= minfo->values.reg.opt & 0x1C00; 962f7018c21STomi Valkeinen else 963f7018c21STomi Valkeinen hw->MXoptionReg |= (minfo->devflags.memtype & 7) << 10; 964f7018c21STomi Valkeinen if (minfo->devflags.sgram) 965f7018c21STomi Valkeinen hw->MXoptionReg |= 0x4000; 966f7018c21STomi Valkeinen mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst); 967f7018c21STomi Valkeinen mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk); 968f7018c21STomi Valkeinen udelay(200); 969f7018c21STomi Valkeinen mga_outl(M_MACCESS, 0x00000000); 970f7018c21STomi Valkeinen mga_outl(M_MACCESS, 0x00008000); 971f7018c21STomi Valkeinen udelay(100); 972f7018c21STomi Valkeinen mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk); 973f7018c21STomi Valkeinen hw->MXoptionReg |= 0x00040020; 974f7018c21STomi Valkeinen } 975f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg); 976f7018c21STomi Valkeinen return 0; 977f7018c21STomi Valkeinen } 978f7018c21STomi Valkeinen 979f7018c21STomi Valkeinen static void MGAG100_reset(struct matrox_fb_info *minfo) 980f7018c21STomi Valkeinen { 981f7018c21STomi Valkeinen u_int8_t b; 982f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 983f7018c21STomi Valkeinen 984f7018c21STomi Valkeinen DBG(__func__) 985f7018c21STomi Valkeinen 986f7018c21STomi Valkeinen { 987f7018c21STomi Valkeinen #ifdef G100_BROKEN_IBM_82351 988f7018c21STomi Valkeinen u_int32_t d; 989f7018c21STomi Valkeinen 990f7018c21STomi Valkeinen find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */ 991f7018c21STomi Valkeinen pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b); 992f7018c21STomi Valkeinen if (b == minfo->pcidev->bus->number) { 993f7018c21STomi Valkeinen pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */ 994f7018c21STomi Valkeinen pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */ 995f7018c21STomi Valkeinen pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */ 996f7018c21STomi Valkeinen pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */ 997f7018c21STomi Valkeinen } 998f7018c21STomi Valkeinen #endif 999f7018c21STomi Valkeinen if (!minfo->devflags.noinit) { 1000f7018c21STomi Valkeinen if (x7AF4 & 8) { 1001f7018c21STomi Valkeinen hw->MXoptionReg |= 0x40; /* FIXME... */ 1002f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg); 1003f7018c21STomi Valkeinen } 1004f7018c21STomi Valkeinen mga_setr(M_EXTVGA_INDEX, 0x06, 0x00); 1005f7018c21STomi Valkeinen } 1006f7018c21STomi Valkeinen } 1007f7018c21STomi Valkeinen if (minfo->devflags.g450dac) { 1008f7018c21STomi Valkeinen /* either leave MCLK as is... or they were set in preinit */ 1009f7018c21STomi Valkeinen hw->DACclk[3] = inDAC1064(minfo, DAC1064_XSYSPLLM); 1010f7018c21STomi Valkeinen hw->DACclk[4] = inDAC1064(minfo, DAC1064_XSYSPLLN); 1011f7018c21STomi Valkeinen hw->DACclk[5] = inDAC1064(minfo, DAC1064_XSYSPLLP); 1012f7018c21STomi Valkeinen } else { 1013f7018c21STomi Valkeinen DAC1064_setmclk(minfo, DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333); 1014f7018c21STomi Valkeinen } 1015f7018c21STomi Valkeinen if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) { 1016f7018c21STomi Valkeinen if (minfo->devflags.dfp_type == -1) { 1017f7018c21STomi Valkeinen minfo->devflags.dfp_type = inDAC1064(minfo, 0x1F); 1018f7018c21STomi Valkeinen } 1019f7018c21STomi Valkeinen } 1020f7018c21STomi Valkeinen if (minfo->devflags.noinit) 1021f7018c21STomi Valkeinen return; 1022f7018c21STomi Valkeinen if (minfo->devflags.g450dac) { 1023f7018c21STomi Valkeinen } else { 1024f7018c21STomi Valkeinen MGAG100_setPixClock(minfo, 4, 25175); 1025f7018c21STomi Valkeinen MGAG100_setPixClock(minfo, 5, 28322); 1026f7018c21STomi Valkeinen if (x7AF4 & 0x10) { 1027f7018c21STomi Valkeinen b = inDAC1064(minfo, M1064_XGENIODATA) & ~1; 1028f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XGENIODATA, b); 1029f7018c21STomi Valkeinen b = inDAC1064(minfo, M1064_XGENIOCTRL) | 1; 1030f7018c21STomi Valkeinen outDAC1064(minfo, M1064_XGENIOCTRL, b); 1031f7018c21STomi Valkeinen } 1032f7018c21STomi Valkeinen } 1033f7018c21STomi Valkeinen } 1034f7018c21STomi Valkeinen #endif 1035f7018c21STomi Valkeinen 1036f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_MYSTIQUE 1037f7018c21STomi Valkeinen static void MGA1064_restore(struct matrox_fb_info *minfo) 1038f7018c21STomi Valkeinen { 1039f7018c21STomi Valkeinen int i; 1040f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 1041f7018c21STomi Valkeinen 1042f7018c21STomi Valkeinen CRITFLAGS 1043f7018c21STomi Valkeinen 1044f7018c21STomi Valkeinen DBG(__func__) 1045f7018c21STomi Valkeinen 1046f7018c21STomi Valkeinen CRITBEGIN 1047f7018c21STomi Valkeinen 1048f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg); 1049f7018c21STomi Valkeinen mga_outb(M_IEN, 0x00); 1050f7018c21STomi Valkeinen mga_outb(M_CACHEFLUSH, 0x00); 1051f7018c21STomi Valkeinen 1052f7018c21STomi Valkeinen CRITEND 1053f7018c21STomi Valkeinen 1054f7018c21STomi Valkeinen DAC1064_restore_1(minfo); 1055f7018c21STomi Valkeinen matroxfb_vgaHWrestore(minfo); 1056f7018c21STomi Valkeinen minfo->crtc1.panpos = -1; 1057f7018c21STomi Valkeinen for (i = 0; i < 6; i++) 1058f7018c21STomi Valkeinen mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); 1059f7018c21STomi Valkeinen DAC1064_restore_2(minfo); 1060f7018c21STomi Valkeinen } 1061f7018c21STomi Valkeinen #endif 1062f7018c21STomi Valkeinen 1063f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G 1064f7018c21STomi Valkeinen static void MGAG100_restore(struct matrox_fb_info *minfo) 1065f7018c21STomi Valkeinen { 1066f7018c21STomi Valkeinen int i; 1067f7018c21STomi Valkeinen struct matrox_hw_state *hw = &minfo->hw; 1068f7018c21STomi Valkeinen 1069f7018c21STomi Valkeinen CRITFLAGS 1070f7018c21STomi Valkeinen 1071f7018c21STomi Valkeinen DBG(__func__) 1072f7018c21STomi Valkeinen 1073f7018c21STomi Valkeinen CRITBEGIN 1074f7018c21STomi Valkeinen 1075f7018c21STomi Valkeinen pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg); 1076f7018c21STomi Valkeinen CRITEND 1077f7018c21STomi Valkeinen 1078f7018c21STomi Valkeinen DAC1064_restore_1(minfo); 1079f7018c21STomi Valkeinen matroxfb_vgaHWrestore(minfo); 1080f7018c21STomi Valkeinen if (minfo->devflags.support32MB) 1081f7018c21STomi Valkeinen mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]); 1082f7018c21STomi Valkeinen minfo->crtc1.panpos = -1; 1083f7018c21STomi Valkeinen for (i = 0; i < 6; i++) 1084f7018c21STomi Valkeinen mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); 1085f7018c21STomi Valkeinen DAC1064_restore_2(minfo); 1086f7018c21STomi Valkeinen } 1087f7018c21STomi Valkeinen #endif 1088f7018c21STomi Valkeinen 1089f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_MYSTIQUE 1090f7018c21STomi Valkeinen struct matrox_switch matrox_mystique = { 1091*a641261eSKees Cook .preinit = MGA1064_preinit, 1092*a641261eSKees Cook .reset = MGA1064_reset, 1093*a641261eSKees Cook .init = MGA1064_init, 1094*a641261eSKees Cook .restore = MGA1064_restore, 1095f7018c21STomi Valkeinen }; 1096f7018c21STomi Valkeinen EXPORT_SYMBOL(matrox_mystique); 1097f7018c21STomi Valkeinen #endif 1098f7018c21STomi Valkeinen 1099f7018c21STomi Valkeinen #ifdef CONFIG_FB_MATROX_G 1100f7018c21STomi Valkeinen struct matrox_switch matrox_G100 = { 1101*a641261eSKees Cook .preinit = MGAG100_preinit, 1102*a641261eSKees Cook .reset = MGAG100_reset, 1103*a641261eSKees Cook .init = MGAG100_init, 1104*a641261eSKees Cook .restore = MGAG100_restore, 1105f7018c21STomi Valkeinen }; 1106f7018c21STomi Valkeinen EXPORT_SYMBOL(matrox_G100); 1107f7018c21STomi Valkeinen #endif 1108f7018c21STomi Valkeinen 1109f7018c21STomi Valkeinen #ifdef NEED_DAC1064 1110f7018c21STomi Valkeinen EXPORT_SYMBOL(DAC1064_global_init); 1111f7018c21STomi Valkeinen EXPORT_SYMBOL(DAC1064_global_restore); 1112f7018c21STomi Valkeinen #endif 1113f7018c21STomi Valkeinen MODULE_LICENSE("GPL"); 1114