blob: 7662a286289865151811104f88a9e1c15b3ee4a7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 *
3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
4 *
5 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
6 *
7 * Portions Copyright (c) 2001 Matrox Graphics Inc.
8 *
9 * Version: 1.65 2002/08/14
10 *
11 * See matroxfb_base.c for contributors.
12 *
13 */
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015
16#include "matroxfb_DAC1064.h"
17#include "matroxfb_misc.h"
18#include "matroxfb_accel.h"
19#include "g450_pll.h"
20#include <linux/matroxfb.h>
21
22#ifdef NEED_DAC1064
23#define outDAC1064 matroxfb_DAC_out
24#define inDAC1064 matroxfb_DAC_in
25
26#define DAC1064_OPT_SCLK_PCI 0x00
27#define DAC1064_OPT_SCLK_PLL 0x01
28#define DAC1064_OPT_SCLK_EXT 0x02
29#define DAC1064_OPT_SCLK_MASK 0x03
30#define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */
31#define DAC1064_OPT_GDIV3 0x00
32#define DAC1064_OPT_MDIV1 0x08
33#define DAC1064_OPT_MDIV2 0x00
34#define DAC1064_OPT_RESERVED 0x10
35
36static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
37 unsigned int fvco;
38 unsigned int p;
39
Harvey Harrison5ae12172008-04-28 02:15:47 -070040 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42 /* only for devices older than G450 */
43
44 fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
45
46 p = (1 << p) - 1;
47 if (fvco <= 100000)
48 ;
49 else if (fvco <= 140000)
50 p |= 0x08;
51 else if (fvco <= 180000)
52 p |= 0x10;
53 else
54 p |= 0x18;
55 *post = p;
56}
57
58/* they must be in POS order */
59static const unsigned char MGA1064_DAC_regs[] = {
60 M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
61 M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
62 M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
63 M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE,
64 DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL,
65 M1064_XMISCCTRL,
66 M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST,
67 M1064_XCRCBITSEL,
68 M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
69
70static const unsigned char MGA1064_DAC[] = {
71 0x00, 0x00, M1064_XCURCTRL_DIS,
72 0x00, 0x00, 0x00, /* black */
73 0xFF, 0xFF, 0xFF, /* white */
74 0xFF, 0x00, 0x00, /* red */
75 0x00, 0,
76 M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL,
77 M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN,
78 M1064_XMISCCTRL_DAC_8BIT,
79 0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN,
80 0x00,
81 0x00, 0x00, 0xFF, 0xFF};
82
83static void DAC1064_setpclk(WPMINFO unsigned long fout) {
84 unsigned int m, n, p;
85
Harvey Harrison5ae12172008-04-28 02:15:47 -070086 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
Jean Delvarefc2d10d2009-09-22 16:47:48 -070088 DAC1064_calcclock(PMINFO fout, minfo->max_pixel_clock, &m, &n, &p);
89 minfo->hw.DACclk[0] = m;
90 minfo->hw.DACclk[1] = n;
91 minfo->hw.DACclk[2] = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092}
93
94static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) {
95 u_int32_t mx;
Jean Delvarefc2d10d2009-09-22 16:47:48 -070096 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Harvey Harrison5ae12172008-04-28 02:15:47 -070098 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700100 if (minfo->devflags.noinit) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 /* read MCLK and give up... */
102 hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
103 hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
104 hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
105 return;
106 }
107 mx = hw->MXoptionReg | 0x00000004;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700108 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 mx &= ~0x000000BB;
110 if (oscinfo & DAC1064_OPT_GDIV1)
111 mx |= 0x00000008;
112 if (oscinfo & DAC1064_OPT_MDIV1)
113 mx |= 0x00000010;
114 if (oscinfo & DAC1064_OPT_RESERVED)
115 mx |= 0x00000080;
116 if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
117 /* select PCI clock until we have setup oscilator... */
118 int clk;
119 unsigned int m, n, p;
120
121 /* powerup system PLL, select PCI clock */
122 mx |= 0x00000020;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700123 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 mx &= ~0x00000004;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700125 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127 /* !!! you must not access device if MCLK is not running !!!
128 Doing so cause immediate PCI lockup :-( Maybe they should
129 generate ABORT or I/O (parity...) error and Linux should
130 recover from this... (kill driver/process). But world is not
131 perfect... */
132 /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
133 select PLL... because of PLL can be stopped at this time) */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700134 DAC1064_calcclock(PMINFO fmem, minfo->max_pixel_clock, &m, &n, &p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m);
136 outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n);
137 outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p);
138 for (clk = 65536; clk; --clk) {
139 if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
140 break;
141 }
142 if (!clk)
143 printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
144 /* select PLL */
145 mx |= 0x00000005;
146 } else {
147 /* select specified system clock source */
148 mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
149 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700150 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 mx &= ~0x00000004;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700152 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 hw->MXoptionReg = mx;
154}
155
156#ifdef CONFIG_FB_MATROX_G
157static void g450_set_plls(WPMINFO2) {
158 u_int32_t c2_ctl;
159 unsigned int pxc;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700160 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 int pixelmnp;
162 int videomnp;
163
164 c2_ctl = hw->crtc2.ctl & ~0x4007; /* Clear PLL + enable for CRTC2 */
165 c2_ctl |= 0x0001; /* Enable CRTC2 */
166 hw->DACreg[POS1064_XPWRCTRL] &= ~0x02; /* Stop VIDEO PLL */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700167 pixelmnp = minfo->crtc1.mnp;
168 videomnp = minfo->crtc2.mnp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 if (videomnp < 0) {
170 c2_ctl &= ~0x0001; /* Disable CRTC2 */
171 hw->DACreg[POS1064_XPWRCTRL] &= ~0x10; /* Powerdown CRTC2 */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700172 } else if (minfo->crtc2.pixclock == minfo->features.pll.ref_freq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 c2_ctl |= 0x4002; /* Use reference directly */
174 } else if (videomnp == pixelmnp) {
175 c2_ctl |= 0x0004; /* Use pixel PLL */
176 } else {
177 if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) {
178 /* PIXEL and VIDEO PLL must not use same frequency. We modify N
179 of PIXEL PLL in such case because of VIDEO PLL may be source
180 of TVO clocks, and chroma subcarrier is derived from its
181 pixel clocks */
182 pixelmnp += 0x000100;
183 }
184 c2_ctl |= 0x0006; /* Use video PLL */
185 hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
186
187 outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
188 matroxfb_g450_setpll_cond(PMINFO videomnp, M_VIDEO_PLL);
189 }
190
191 hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
192 if (pixelmnp >= 0) {
193 hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
194
195 outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
196 matroxfb_g450_setpll_cond(PMINFO pixelmnp, M_PIXEL_PLL_C);
197 }
198 if (c2_ctl != hw->crtc2.ctl) {
199 hw->crtc2.ctl = c2_ctl;
200 mga_outl(0x3C10, c2_ctl);
201 }
202
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700203 pxc = minfo->crtc1.pixclock;
204 if (pxc == 0 || minfo->outputs[2].src == MATROXFB_SRC_CRTC2) {
205 pxc = minfo->crtc2.pixclock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700207 if (minfo->chip == MGA_G550) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 if (pxc < 45000) {
209 hw->DACreg[POS1064_XPANMODE] = 0x00; /* 0-50 */
210 } else if (pxc < 55000) {
211 hw->DACreg[POS1064_XPANMODE] = 0x08; /* 34-62 */
212 } else if (pxc < 70000) {
213 hw->DACreg[POS1064_XPANMODE] = 0x10; /* 42-78 */
214 } else if (pxc < 85000) {
215 hw->DACreg[POS1064_XPANMODE] = 0x18; /* 62-92 */
216 } else if (pxc < 100000) {
217 hw->DACreg[POS1064_XPANMODE] = 0x20; /* 74-108 */
218 } else if (pxc < 115000) {
219 hw->DACreg[POS1064_XPANMODE] = 0x28; /* 94-122 */
220 } else if (pxc < 125000) {
221 hw->DACreg[POS1064_XPANMODE] = 0x30; /* 108-132 */
222 } else {
223 hw->DACreg[POS1064_XPANMODE] = 0x38; /* 120-168 */
224 }
225 } else {
226 /* G450 */
227 if (pxc < 45000) {
228 hw->DACreg[POS1064_XPANMODE] = 0x00; /* 0-54 */
229 } else if (pxc < 65000) {
230 hw->DACreg[POS1064_XPANMODE] = 0x08; /* 38-70 */
231 } else if (pxc < 85000) {
232 hw->DACreg[POS1064_XPANMODE] = 0x10; /* 56-96 */
233 } else if (pxc < 105000) {
234 hw->DACreg[POS1064_XPANMODE] = 0x18; /* 80-114 */
235 } else if (pxc < 135000) {
236 hw->DACreg[POS1064_XPANMODE] = 0x20; /* 102-144 */
237 } else if (pxc < 160000) {
238 hw->DACreg[POS1064_XPANMODE] = 0x28; /* 132-166 */
239 } else if (pxc < 175000) {
240 hw->DACreg[POS1064_XPANMODE] = 0x30; /* 154-182 */
241 } else {
242 hw->DACreg[POS1064_XPANMODE] = 0x38; /* 170-204 */
243 }
244 }
245}
246#endif
247
248void DAC1064_global_init(WPMINFO2) {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700249 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251 hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
252 hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
253 hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
254#ifdef CONFIG_FB_MATROX_G
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700255 if (minfo->devflags.g450dac) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 hw->DACreg[POS1064_XPWRCTRL] = 0x1F; /* powerup everything */
257 hw->DACreg[POS1064_XOUTPUTCONN] = 0x00; /* disable outputs */
258 hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700259 switch (minfo->outputs[0].src) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 case MATROXFB_SRC_CRTC1:
261 case MATROXFB_SRC_CRTC2:
262 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01; /* enable output; CRTC1/2 selection is in CRTC2 ctl */
263 break;
264 case MATROXFB_SRC_NONE:
265 hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN;
266 break;
267 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700268 switch (minfo->outputs[1].src) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 case MATROXFB_SRC_CRTC1:
270 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04;
271 break;
272 case MATROXFB_SRC_CRTC2:
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700273 if (minfo->outputs[1].mode == MATROXFB_OUTPUT_MODE_MONITOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08;
275 } else {
276 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C;
277 }
278 break;
279 case MATROXFB_SRC_NONE:
280 hw->DACreg[POS1064_XPWRCTRL] &= ~0x01; /* Poweroff DAC2 */
281 break;
282 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700283 switch (minfo->outputs[2].src) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 case MATROXFB_SRC_CRTC1:
285 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20;
286 break;
287 case MATROXFB_SRC_CRTC2:
288 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40;
289 break;
290 case MATROXFB_SRC_NONE:
291#if 0
292 /* HELP! If we boot without DFP connected to DVI, we can
293 poweroff TMDS. But if we boot with DFP connected,
294 TMDS generated clocks are used instead of ALL pixclocks
295 available... If someone knows which register
296 handles it, please reveal this secret to me... */
297 hw->DACreg[POS1064_XPWRCTRL] &= ~0x04; /* Poweroff TMDS */
298#endif
299 break;
300 }
301 /* Now set timming related variables... */
302 g450_set_plls(PMINFO2);
303 } else
304#endif
305 {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700306 if (minfo->outputs[1].src == MATROXFB_SRC_CRTC1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
308 hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700309 } else if (minfo->outputs[1].src == MATROXFB_SRC_CRTC2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700311 } else if (minfo->outputs[2].src == MATROXFB_SRC_CRTC1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
313 else
314 hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
315
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700316 if (minfo->outputs[0].src != MATROXFB_SRC_NONE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
318 }
319}
320
321void DAC1064_global_restore(WPMINFO2) {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700322 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
325 outDAC1064(PMINFO M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]);
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700326 if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 outDAC1064(PMINFO 0x20, 0x04);
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700328 outDAC1064(PMINFO 0x1F, minfo->devflags.dfp_type);
329 if (minfo->devflags.g450dac) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);
331 outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
332 outDAC1064(PMINFO M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
333 outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]);
334 }
335 }
336}
337
338static int DAC1064_init_1(WPMINFO struct my_timming* m) {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700339 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Harvey Harrison5ae12172008-04-28 02:15:47 -0700341 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700344 switch (minfo->fbcon.var.bits_per_pixel) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 /* case 4: not supported by MGA1064 DAC */
346 case 8:
347 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
348 break;
349 case 16:
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700350 if (minfo->fbcon.var.green.length == 5)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
352 else
353 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
354 break;
355 case 24:
356 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
357 break;
358 case 32:
359 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
360 break;
361 default:
362 return 1; /* unsupported depth */
363 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700364 hw->DACreg[POS1064_XVREFCTRL] = minfo->features.DAC1064.xvrefctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
366 hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
367 hw->DACreg[POS1064_XCURADDL] = 0;
368 hw->DACreg[POS1064_XCURADDH] = 0;
369
370 DAC1064_global_init(PMINFO2);
371 return 0;
372}
373
374static int DAC1064_init_2(WPMINFO struct my_timming* m) {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700375 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Harvey Harrison5ae12172008-04-28 02:15:47 -0700377 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700379 if (minfo->fbcon.var.bits_per_pixel > 16) { /* 256 entries */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 int i;
381
382 for (i = 0; i < 256; i++) {
383 hw->DACpal[i * 3 + 0] = i;
384 hw->DACpal[i * 3 + 1] = i;
385 hw->DACpal[i * 3 + 2] = i;
386 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700387 } else if (minfo->fbcon.var.bits_per_pixel > 8) {
388 if (minfo->fbcon.var.green.length == 5) { /* 0..31, 128..159 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 int i;
390
391 for (i = 0; i < 32; i++) {
392 /* with p15 == 0 */
393 hw->DACpal[i * 3 + 0] = i << 3;
394 hw->DACpal[i * 3 + 1] = i << 3;
395 hw->DACpal[i * 3 + 2] = i << 3;
396 /* with p15 == 1 */
397 hw->DACpal[(i + 128) * 3 + 0] = i << 3;
398 hw->DACpal[(i + 128) * 3 + 1] = i << 3;
399 hw->DACpal[(i + 128) * 3 + 2] = i << 3;
400 }
401 } else {
402 int i;
403
404 for (i = 0; i < 64; i++) { /* 0..63 */
405 hw->DACpal[i * 3 + 0] = i << 3;
406 hw->DACpal[i * 3 + 1] = i << 2;
407 hw->DACpal[i * 3 + 2] = i << 3;
408 }
409 }
410 } else {
411 memset(hw->DACpal, 0, 768);
412 }
413 return 0;
414}
415
416static void DAC1064_restore_1(WPMINFO2) {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700417 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 CRITFLAGS
420
Harvey Harrison5ae12172008-04-28 02:15:47 -0700421 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
423 CRITBEGIN
424
425 if ((inDAC1064(PMINFO DAC1064_XSYSPLLM) != hw->DACclk[3]) ||
426 (inDAC1064(PMINFO DAC1064_XSYSPLLN) != hw->DACclk[4]) ||
427 (inDAC1064(PMINFO DAC1064_XSYSPLLP) != hw->DACclk[5])) {
428 outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
429 outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
430 outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
431 }
432 {
433 unsigned int i;
434
435 for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
436 if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL))
437 outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
438 }
439 }
440
441 DAC1064_global_restore(PMINFO2);
442
443 CRITEND
444};
445
446static void DAC1064_restore_2(WPMINFO2) {
447#ifdef DEBUG
448 unsigned int i;
449#endif
450
Harvey Harrison5ae12172008-04-28 02:15:47 -0700451 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
453#ifdef DEBUG
454 dprintk(KERN_DEBUG "DAC1064regs ");
455 for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700456 dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], minfo->hw.DACreg[i]);
Joe Perchesad361c92009-07-06 13:05:40 -0700457 if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 }
Joe Perchesad361c92009-07-06 13:05:40 -0700459 dprintk(KERN_DEBUG "DAC1064clk ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 for (i = 0; i < 6; i++)
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700461 dprintk("C%02X=%02X ", i, minfo->hw.DACclk[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 dprintk("\n");
463#endif
464}
465
466static int m1064_compute(void* out, struct my_timming* m) {
467#define minfo ((struct matrox_fb_info*)out)
468 {
469 int i;
470 int tmout;
471 CRITFLAGS
472
473 DAC1064_setpclk(PMINFO m->pixclock);
474
475 CRITBEGIN
476
477 for (i = 0; i < 3; i++)
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700478 outDAC1064(PMINFO M1064_XPIXPLLCM + i, minfo->hw.DACclk[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 for (tmout = 500000; tmout; tmout--) {
480 if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
481 break;
482 udelay(10);
483 };
484
485 CRITEND
486
487 if (!tmout)
488 printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
489 }
490#undef minfo
491 return 0;
492}
493
494static struct matrox_altout m1064 = {
495 .name = "Primary output",
496 .compute = m1064_compute,
497};
498
499#ifdef CONFIG_FB_MATROX_G
500static int g450_compute(void* out, struct my_timming* m) {
501#define minfo ((struct matrox_fb_info*)out)
502 if (m->mnp < 0) {
503 m->mnp = matroxfb_g450_setclk(PMINFO m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
504 if (m->mnp >= 0) {
505 m->pixclock = g450_mnp2f(PMINFO m->mnp);
506 }
507 }
508#undef minfo
509 return 0;
510}
511
512static struct matrox_altout g450out = {
513 .name = "Primary output",
514 .compute = g450_compute,
515};
516#endif
517
518#endif /* NEED_DAC1064 */
519
520#ifdef CONFIG_FB_MATROX_MYSTIQUE
521static int MGA1064_init(WPMINFO struct my_timming* m) {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700522 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Harvey Harrison5ae12172008-04-28 02:15:47 -0700524 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526 if (DAC1064_init_1(PMINFO m)) return 1;
527 if (matroxfb_vgaHWinit(PMINFO m)) return 1;
528
529 hw->MiscOutReg = 0xCB;
530 if (m->sync & FB_SYNC_HOR_HIGH_ACT)
531 hw->MiscOutReg &= ~0x40;
532 if (m->sync & FB_SYNC_VERT_HIGH_ACT)
533 hw->MiscOutReg &= ~0x80;
534 if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
535 hw->CRTCEXT[3] |= 0x40;
536
537 if (DAC1064_init_2(PMINFO m)) return 1;
538 return 0;
539}
540#endif
541
542#ifdef CONFIG_FB_MATROX_G
543static int MGAG100_init(WPMINFO struct my_timming* m) {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700544 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Harvey Harrison5ae12172008-04-28 02:15:47 -0700546 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548 if (DAC1064_init_1(PMINFO m)) return 1;
549 hw->MXoptionReg &= ~0x2000;
550 if (matroxfb_vgaHWinit(PMINFO m)) return 1;
551
552 hw->MiscOutReg = 0xEF;
553 if (m->sync & FB_SYNC_HOR_HIGH_ACT)
554 hw->MiscOutReg &= ~0x40;
555 if (m->sync & FB_SYNC_VERT_HIGH_ACT)
556 hw->MiscOutReg &= ~0x80;
557 if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
558 hw->CRTCEXT[3] |= 0x40;
559
560 if (DAC1064_init_2(PMINFO m)) return 1;
561 return 0;
562}
563#endif /* G */
564
565#ifdef CONFIG_FB_MATROX_MYSTIQUE
566static void MGA1064_ramdac_init(WPMINFO2) {
567
Harvey Harrison5ae12172008-04-28 02:15:47 -0700568 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700570 /* minfo->features.DAC1064.vco_freq_min = 120000; */
571 minfo->features.pll.vco_freq_min = 62000;
572 minfo->features.pll.ref_freq = 14318;
573 minfo->features.pll.feed_div_min = 100;
574 minfo->features.pll.feed_div_max = 127;
575 minfo->features.pll.in_div_min = 1;
576 minfo->features.pll.in_div_max = 31;
577 minfo->features.pll.post_shift_max = 3;
578 minfo->features.DAC1064.xvrefctrl = DAC1064_XVREFCTRL_EXTERNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
580 DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
581}
582#endif
583
584#ifdef CONFIG_FB_MATROX_G
585/* BIOS environ */
586static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
587 /* G100 wants 0x10, G200 SGRAM does not care... */
588#if 0
589static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
590#endif
591
592static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) {
593 int reg;
594 int selClk;
595 int clk;
596
Harvey Harrison5ae12172008-04-28 02:15:47 -0700597 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS |
600 M1064_XPIXCLKCTRL_PLL_UP);
601 switch (flags & 3) {
602 case 0: reg = M1064_XPIXPLLAM; break;
603 case 1: reg = M1064_XPIXPLLBM; break;
604 default: reg = M1064_XPIXPLLCM; break;
605 }
606 outDAC1064(PMINFO reg++, m);
607 outDAC1064(PMINFO reg++, n);
608 outDAC1064(PMINFO reg, p);
609 selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
610 /* there should be flags & 0x03 & case 0/1/else */
611 /* and we should first select source and after that we should wait for PLL */
612 /* and we are waiting for PLL with oscilator disabled... Is it right? */
613 switch (flags & 0x03) {
614 case 0x00: break;
615 case 0x01: selClk |= 4; break;
616 default: selClk |= 0x0C; break;
617 }
618 mga_outb(M_MISC_REG, selClk);
619 for (clk = 500000; clk; clk--) {
620 if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
621 break;
622 udelay(10);
623 };
624 if (!clk)
625 printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
626 selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
627 switch (flags & 0x0C) {
628 case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
629 case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
630 default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
631 }
632 outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk);
633 outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
634}
635
636static void MGAG100_setPixClock(CPMINFO int flags, int freq) {
637 unsigned int m, n, p;
638
Harvey Harrison5ae12172008-04-28 02:15:47 -0700639 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700641 DAC1064_calcclock(PMINFO freq, minfo->max_pixel_clock, &m, &n, &p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 MGAG100_progPixClock(PMINFO flags, m, n, p);
643}
644#endif
645
646#ifdef CONFIG_FB_MATROX_MYSTIQUE
647static int MGA1064_preinit(WPMINFO2) {
648 static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960,
649 1024, 1152, 1280, 1600, 1664, 1920,
650 2048, 0};
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700651 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
Harvey Harrison5ae12172008-04-28 02:15:47 -0700653 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700655 /* minfo->capable.cfb4 = 0; ... preinitialized by 0 */
656 minfo->capable.text = 1;
657 minfo->capable.vxres = vxres_mystique;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700659 minfo->outputs[0].output = &m1064;
660 minfo->outputs[0].src = minfo->outputs[0].default_src;
661 minfo->outputs[0].data = minfo;
662 minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700664 if (minfo->devflags.noinit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return 0; /* do not modify settings */
666 hw->MXoptionReg &= 0xC0000100;
667 hw->MXoptionReg |= 0x00094E20;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700668 if (minfo->devflags.novga)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 hw->MXoptionReg &= ~0x00000100;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700670 if (minfo->devflags.nobios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 hw->MXoptionReg &= ~0x40000000;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700672 if (minfo->devflags.nopciretry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 hw->MXoptionReg |= 0x20000000;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700674 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 mga_setr(M_SEQ_INDEX, 0x01, 0x20);
676 mga_outl(M_CTLWTST, 0x00000000);
677 udelay(200);
678 mga_outl(M_MACCESS, 0x00008000);
679 udelay(100);
680 mga_outl(M_MACCESS, 0x0000C000);
681 return 0;
682}
683
684static void MGA1064_reset(WPMINFO2) {
685
Harvey Harrison5ae12172008-04-28 02:15:47 -0700686 DBG(__func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 MGA1064_ramdac_init(PMINFO2);
689}
690#endif
691
692#ifdef CONFIG_FB_MATROX_G
693static void g450_mclk_init(WPMINFO2) {
694 /* switch all clocks to PCI source */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700695 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4);
696 pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3 & ~0x00300C03);
697 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
698
699 if (((minfo->values.reg.opt3 & 0x000003) == 0x000003) ||
700 ((minfo->values.reg.opt3 & 0x000C00) == 0x000C00) ||
701 ((minfo->values.reg.opt3 & 0x300000) == 0x300000)) {
702 matroxfb_g450_setclk(PMINFO minfo->values.pll.video, M_VIDEO_PLL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 } else {
704 unsigned long flags;
705 unsigned int pwr;
706
707 matroxfb_DAC_lock_irqsave(flags);
708 pwr = inDAC1064(PMINFO M1064_XPWRCTRL) & ~0x02;
709 outDAC1064(PMINFO M1064_XPWRCTRL, pwr);
710 matroxfb_DAC_unlock_irqrestore(flags);
711 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700712 matroxfb_g450_setclk(PMINFO minfo->values.pll.system, M_SYSTEM_PLL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
714 /* switch clocks to their real PLL source(s) */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700715 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4);
716 pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3);
717 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719}
720
721static void g450_memory_init(WPMINFO2) {
722 /* disable memory refresh */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700723 minfo->hw.MXoptionReg &= ~0x001F8000;
724 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 /* set memory interface parameters */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700727 minfo->hw.MXoptionReg &= ~0x00207E00;
728 minfo->hw.MXoptionReg |= 0x00207E00 & minfo->values.reg.opt;
729 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
730 pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, minfo->values.reg.opt2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700732 mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734 /* first set up memory interface with disabled memory interface clocks */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700735 pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc & ~0x80000000U);
736 mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
737 mga_outl(M_MACCESS, minfo->values.reg.maccess);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 /* start memory clocks */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700739 pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc | 0x80000000U);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 udelay(200);
742
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700743 if (minfo->values.memory.ddr && (!minfo->values.memory.emrswen || !minfo->values.memory.dll)) {
744 mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk & ~0x1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700746 mga_outl(M_MACCESS, minfo->values.reg.maccess | 0x8000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 udelay(200);
749
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700750 minfo->hw.MXoptionReg |= 0x001F8000 & minfo->values.reg.opt;
751 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 /* value is written to memory chips only if old != new */
754 mga_outl(M_PLNWT, 0);
755 mga_outl(M_PLNWT, ~0);
756
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700757 if (minfo->values.reg.mctlwtst != minfo->values.reg.mctlwtst_core) {
758 mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst_core);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 }
760
761}
762
763static void g450_preinit(WPMINFO2) {
764 u_int32_t c2ctl;
765 u_int8_t curctl;
766 u_int8_t c1ctl;
767
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700768 /* minfo->hw.MXoptionReg = minfo->values.reg.opt; */
769 minfo->hw.MXoptionReg &= 0xC0000100;
770 minfo->hw.MXoptionReg |= 0x00000020;
771 if (minfo->devflags.novga)
772 minfo->hw.MXoptionReg &= ~0x00000100;
773 if (minfo->devflags.nobios)
774 minfo->hw.MXoptionReg &= ~0x40000000;
775 if (minfo->devflags.nopciretry)
776 minfo->hw.MXoptionReg |= 0x20000000;
777 minfo->hw.MXoptionReg |= minfo->values.reg.opt & 0x03400040;
778 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780 /* Init system clocks */
781
782 /* stop crtc2 */
783 c2ctl = mga_inl(M_C2CTL);
784 mga_outl(M_C2CTL, c2ctl & ~1);
785 /* stop cursor */
786 curctl = inDAC1064(PMINFO M1064_XCURCTRL);
787 outDAC1064(PMINFO M1064_XCURCTRL, 0);
788 /* stop crtc1 */
789 c1ctl = mga_readr(M_SEQ_INDEX, 1);
790 mga_setr(M_SEQ_INDEX, 1, c1ctl | 0x20);
791
792 g450_mclk_init(PMINFO2);
793 g450_memory_init(PMINFO2);
794
795 /* set legacy VGA clock sources for DOSEmu or VMware... */
796 matroxfb_g450_setclk(PMINFO 25175, M_PIXEL_PLL_A);
797 matroxfb_g450_setclk(PMINFO 28322, M_PIXEL_PLL_B);
798
799 /* restore crtc1 */
800 mga_setr(M_SEQ_INDEX, 1, c1ctl);
801
802 /* restore cursor */
803 outDAC1064(PMINFO M1064_XCURCTRL, curctl);
804
805 /* restore crtc2 */
806 mga_outl(M_C2CTL, c2ctl);
807
808 return;
809}
810
811static int MGAG100_preinit(WPMINFO2) {
812 static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960,
813 1024, 1152, 1280, 1600, 1664, 1920,
814 2048, 0};
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700815 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 u_int32_t reg50;
818#if 0
819 u_int32_t q;
820#endif
821
Harvey Harrison5ae12172008-04-28 02:15:47 -0700822 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 /* there are some instabilities if in_div > 19 && vco < 61000 */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700825 if (minfo->devflags.g450dac) {
826 minfo->features.pll.vco_freq_min = 130000; /* my sample: >118 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 } else {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700828 minfo->features.pll.vco_freq_min = 62000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700830 if (!minfo->features.pll.ref_freq) {
831 minfo->features.pll.ref_freq = 27000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700833 minfo->features.pll.feed_div_min = 7;
834 minfo->features.pll.feed_div_max = 127;
835 minfo->features.pll.in_div_min = 1;
836 minfo->features.pll.in_div_max = 31;
837 minfo->features.pll.post_shift_max = 3;
838 minfo->features.DAC1064.xvrefctrl = DAC1064_XVREFCTRL_G100_DEFAULT;
839 /* minfo->capable.cfb4 = 0; ... preinitialized by 0 */
840 minfo->capable.text = 1;
841 minfo->capable.vxres = vxres_g100;
842 minfo->capable.plnwt = minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100
843 ? minfo->devflags.sgram : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845#ifdef CONFIG_FB_MATROX_G
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700846 if (minfo->devflags.g450dac) {
847 minfo->outputs[0].output = &g450out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 } else
849#endif
850 {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700851 minfo->outputs[0].output = &m1064;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700853 minfo->outputs[0].src = minfo->outputs[0].default_src;
854 minfo->outputs[0].data = minfo;
855 minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700857 if (minfo->devflags.g450dac) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 /* we must do this always, BIOS does not do it for us
859 and accelerator dies without it */
860 mga_outl(0x1C0C, 0);
861 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700862 if (minfo->devflags.noinit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return 0;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700864 if (minfo->devflags.g450dac) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 g450_preinit(PMINFO2);
866 return 0;
867 }
868 hw->MXoptionReg &= 0xC0000100;
869 hw->MXoptionReg |= 0x00000020;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700870 if (minfo->devflags.novga)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 hw->MXoptionReg &= ~0x00000100;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700872 if (minfo->devflags.nobios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 hw->MXoptionReg &= ~0x40000000;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700874 if (minfo->devflags.nopciretry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 hw->MXoptionReg |= 0x20000000;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700876 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333);
878
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700879 if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100) {
880 pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 reg50 &= ~0x3000;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700882 pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 hw->MXoptionReg |= 0x1080;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700885 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
886 mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 udelay(100);
888 mga_outb(0x1C05, 0x00);
889 mga_outb(0x1C05, 0x80);
890 udelay(100);
891 mga_outb(0x1C05, 0x40);
892 mga_outb(0x1C05, 0xC0);
893 udelay(100);
894 reg50 &= ~0xFF;
895 reg50 |= 0x07;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700896 pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 /* it should help with G100 */
898 mga_outb(M_GRAPHICS_INDEX, 6);
899 mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
900 mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
901 mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700902 mga_writeb(minfo->video.vbase, 0x0000, 0xAA);
903 mga_writeb(minfo->video.vbase, 0x0800, 0x55);
904 mga_writeb(minfo->video.vbase, 0x4000, 0x55);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905#if 0
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700906 if (mga_readb(minfo->video.vbase, 0x0000) != 0xAA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 hw->MXoptionReg &= ~0x1000;
908 }
909#endif
910 hw->MXoptionReg |= 0x00078020;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700911 } else if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG200) {
912 pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 reg50 &= ~0x3000;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700914 pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700916 if (minfo->devflags.memtype == -1)
917 hw->MXoptionReg |= minfo->values.reg.opt & 0x1C00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 else
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700919 hw->MXoptionReg |= (minfo->devflags.memtype & 7) << 10;
920 if (minfo->devflags.sgram)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 hw->MXoptionReg |= 0x4000;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700922 mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
923 mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 udelay(200);
925 mga_outl(M_MACCESS, 0x00000000);
926 mga_outl(M_MACCESS, 0x00008000);
927 udelay(100);
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700928 mga_outw(M_MEMRDBK, minfo->values.reg.memrdbk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 hw->MXoptionReg |= 0x00078020;
930 } else {
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700931 pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 reg50 &= ~0x00000100;
933 reg50 |= 0x00000000;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700934 pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700936 if (minfo->devflags.memtype == -1)
937 hw->MXoptionReg |= minfo->values.reg.opt & 0x1C00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 else
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700939 hw->MXoptionReg |= (minfo->devflags.memtype & 7) << 10;
940 if (minfo->devflags.sgram)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 hw->MXoptionReg |= 0x4000;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700942 mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
943 mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 udelay(200);
945 mga_outl(M_MACCESS, 0x00000000);
946 mga_outl(M_MACCESS, 0x00008000);
947 udelay(100);
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700948 mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 hw->MXoptionReg |= 0x00040020;
950 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700951 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 return 0;
953}
954
955static void MGAG100_reset(WPMINFO2) {
956 u_int8_t b;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700957 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Harvey Harrison5ae12172008-04-28 02:15:47 -0700959 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 {
962#ifdef G100_BROKEN_IBM_82351
963 u_int32_t d;
964
965 find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
966 pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700967 if (b == minfo->pcidev->bus->number) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */
969 pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */
970 pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */
971 pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */
972 }
973#endif
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700974 if (!minfo->devflags.noinit) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if (x7AF4 & 8) {
976 hw->MXoptionReg |= 0x40; /* FIXME... */
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700977 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 }
Ville Syrjäläf73195a2005-11-07 01:01:00 -0800979 mga_setr(M_EXTVGA_INDEX, 0x06, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 }
981 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700982 if (minfo->devflags.g450dac) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 /* either leave MCLK as is... or they were set in preinit */
984 hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
985 hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
986 hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
987 } else {
988 DAC1064_setmclk(PMINFO DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333);
989 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700990 if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) {
991 if (minfo->devflags.dfp_type == -1) {
992 minfo->devflags.dfp_type = inDAC1064(PMINFO 0x1F);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 }
994 }
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700995 if (minfo->devflags.noinit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return;
Jean Delvarefc2d10d2009-09-22 16:47:48 -0700997 if (minfo->devflags.g450dac) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 } else {
999 MGAG100_setPixClock(PMINFO 4, 25175);
1000 MGAG100_setPixClock(PMINFO 5, 28322);
1001 if (x7AF4 & 0x10) {
1002 b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1;
1003 outDAC1064(PMINFO M1064_XGENIODATA, b);
1004 b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1;
1005 outDAC1064(PMINFO M1064_XGENIOCTRL, b);
1006 }
1007 }
1008}
1009#endif
1010
1011#ifdef CONFIG_FB_MATROX_MYSTIQUE
1012static void MGA1064_restore(WPMINFO2) {
1013 int i;
Jean Delvarefc2d10d2009-09-22 16:47:48 -07001014 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 CRITFLAGS
1017
Harvey Harrison5ae12172008-04-28 02:15:47 -07001018 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
1020 CRITBEGIN
1021
Jean Delvarefc2d10d2009-09-22 16:47:48 -07001022 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 mga_outb(M_IEN, 0x00);
1024 mga_outb(M_CACHEFLUSH, 0x00);
1025
1026 CRITEND
1027
1028 DAC1064_restore_1(PMINFO2);
1029 matroxfb_vgaHWrestore(PMINFO2);
Jean Delvarefc2d10d2009-09-22 16:47:48 -07001030 minfo->crtc1.panpos = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 for (i = 0; i < 6; i++)
1032 mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
1033 DAC1064_restore_2(PMINFO2);
1034}
1035#endif
1036
1037#ifdef CONFIG_FB_MATROX_G
1038static void MGAG100_restore(WPMINFO2) {
1039 int i;
Jean Delvarefc2d10d2009-09-22 16:47:48 -07001040 struct matrox_hw_state *hw = &minfo->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
1042 CRITFLAGS
1043
Harvey Harrison5ae12172008-04-28 02:15:47 -07001044 DBG(__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
1046 CRITBEGIN
1047
Jean Delvarefc2d10d2009-09-22 16:47:48 -07001048 pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 CRITEND
1050
1051 DAC1064_restore_1(PMINFO2);
1052 matroxfb_vgaHWrestore(PMINFO2);
1053#ifdef CONFIG_FB_MATROX_32MB
Jean Delvarefc2d10d2009-09-22 16:47:48 -07001054 if (minfo->devflags.support32MB)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
1056#endif
Jean Delvarefc2d10d2009-09-22 16:47:48 -07001057 minfo->crtc1.panpos = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 for (i = 0; i < 6; i++)
1059 mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
1060 DAC1064_restore_2(PMINFO2);
1061}
1062#endif
1063
1064#ifdef CONFIG_FB_MATROX_MYSTIQUE
1065struct matrox_switch matrox_mystique = {
1066 MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore,
1067};
1068EXPORT_SYMBOL(matrox_mystique);
1069#endif
1070
1071#ifdef CONFIG_FB_MATROX_G
1072struct matrox_switch matrox_G100 = {
1073 MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore,
1074};
1075EXPORT_SYMBOL(matrox_G100);
1076#endif
1077
1078#ifdef NEED_DAC1064
1079EXPORT_SYMBOL(DAC1064_global_init);
1080EXPORT_SYMBOL(DAC1064_global_restore);
1081#endif
1082MODULE_LICENSE("GPL");