]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
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 | ||
1da177e4 LT |
15 | |
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 | ||
36 | static 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 | ||
5ae12170 | 40 | DBG(__func__) |
1da177e4 LT |
41 | |
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 */ | |
59 | static 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 | ||
70 | static 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 | ||
83 | static void DAC1064_setpclk(WPMINFO unsigned long fout) { | |
84 | unsigned int m, n, p; | |
85 | ||
5ae12170 | 86 | DBG(__func__) |
1da177e4 LT |
87 | |
88 | DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); | |
89 | ACCESS_FBINFO(hw).DACclk[0] = m; | |
90 | ACCESS_FBINFO(hw).DACclk[1] = n; | |
91 | ACCESS_FBINFO(hw).DACclk[2] = p; | |
92 | } | |
93 | ||
94 | static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) { | |
95 | u_int32_t mx; | |
96 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
97 | ||
5ae12170 | 98 | DBG(__func__) |
1da177e4 LT |
99 | |
100 | if (ACCESS_FBINFO(devflags.noinit)) { | |
101 | /* 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; | |
108 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); | |
109 | 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; | |
123 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); | |
124 | mx &= ~0x00000004; | |
125 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); | |
126 | ||
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) */ | |
134 | DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); | |
135 | 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 | } | |
150 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); | |
151 | mx &= ~0x00000004; | |
152 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); | |
153 | hw->MXoptionReg = mx; | |
154 | } | |
155 | ||
156 | #ifdef CONFIG_FB_MATROX_G | |
157 | static void g450_set_plls(WPMINFO2) { | |
158 | u_int32_t c2_ctl; | |
159 | unsigned int pxc; | |
160 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
161 | 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 */ | |
167 | pixelmnp = ACCESS_FBINFO(crtc1).mnp; | |
168 | videomnp = ACCESS_FBINFO(crtc2).mnp; | |
169 | if (videomnp < 0) { | |
170 | c2_ctl &= ~0x0001; /* Disable CRTC2 */ | |
171 | hw->DACreg[POS1064_XPWRCTRL] &= ~0x10; /* Powerdown CRTC2 */ | |
172 | } else if (ACCESS_FBINFO(crtc2).pixclock == ACCESS_FBINFO(features).pll.ref_freq) { | |
173 | 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 | ||
203 | pxc = ACCESS_FBINFO(crtc1).pixclock; | |
204 | if (pxc == 0 || ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC2) { | |
205 | pxc = ACCESS_FBINFO(crtc2).pixclock; | |
206 | } | |
207 | if (ACCESS_FBINFO(chip) == MGA_G550) { | |
208 | 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 | ||
248 | void DAC1064_global_init(WPMINFO2) { | |
249 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
250 | ||
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 | |
255 | if (ACCESS_FBINFO(devflags.g450dac)) { | |
256 | hw->DACreg[POS1064_XPWRCTRL] = 0x1F; /* powerup everything */ | |
257 | hw->DACreg[POS1064_XOUTPUTCONN] = 0x00; /* disable outputs */ | |
258 | hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN; | |
259 | switch (ACCESS_FBINFO(outputs[0]).src) { | |
260 | 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 | } | |
268 | switch (ACCESS_FBINFO(outputs[1]).src) { | |
269 | case MATROXFB_SRC_CRTC1: | |
270 | hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04; | |
271 | break; | |
272 | case MATROXFB_SRC_CRTC2: | |
273 | if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_MONITOR) { | |
274 | 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 | } | |
283 | switch (ACCESS_FBINFO(outputs[2]).src) { | |
284 | 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 | { | |
306 | if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) { | |
307 | 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; | |
309 | } else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) { | |
310 | hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12; | |
311 | } else if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) | |
312 | hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12; | |
313 | else | |
314 | hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS; | |
315 | ||
316 | if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE) | |
317 | hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN; | |
318 | } | |
319 | } | |
320 | ||
321 | void DAC1064_global_restore(WPMINFO2) { | |
322 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
323 | ||
324 | outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]); | |
325 | outDAC1064(PMINFO M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]); | |
326 | if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) { | |
327 | outDAC1064(PMINFO 0x20, 0x04); | |
328 | outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type)); | |
329 | if (ACCESS_FBINFO(devflags.g450dac)) { | |
330 | 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 | ||
338 | static int DAC1064_init_1(WPMINFO struct my_timming* m) { | |
339 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
340 | ||
5ae12170 | 341 | DBG(__func__) |
1da177e4 LT |
342 | |
343 | memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); | |
344 | switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { | |
345 | /* 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: | |
350 | if (ACCESS_FBINFO(fbcon).var.green.length == 5) | |
351 | 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 | } | |
364 | hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl); | |
365 | 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 | ||
374 | static int DAC1064_init_2(WPMINFO struct my_timming* m) { | |
375 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
376 | ||
5ae12170 | 377 | DBG(__func__) |
1da177e4 LT |
378 | |
379 | if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) { /* 256 entries */ | |
380 | 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 | } | |
387 | } else if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 8) { | |
388 | if (ACCESS_FBINFO(fbcon).var.green.length == 5) { /* 0..31, 128..159 */ | |
389 | 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 | ||
416 | static void DAC1064_restore_1(WPMINFO2) { | |
417 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
418 | ||
419 | CRITFLAGS | |
420 | ||
5ae12170 | 421 | DBG(__func__) |
1da177e4 LT |
422 | |
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 | ||
446 | static void DAC1064_restore_2(WPMINFO2) { | |
447 | #ifdef DEBUG | |
448 | unsigned int i; | |
449 | #endif | |
450 | ||
5ae12170 | 451 | DBG(__func__) |
1da177e4 LT |
452 | |
453 | #ifdef DEBUG | |
454 | dprintk(KERN_DEBUG "DAC1064regs "); | |
455 | for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { | |
456 | dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], ACCESS_FBINFO(hw).DACreg[i]); | |
ad361c98 | 457 | if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... "); |
1da177e4 | 458 | } |
ad361c98 | 459 | dprintk(KERN_DEBUG "DAC1064clk "); |
1da177e4 LT |
460 | for (i = 0; i < 6; i++) |
461 | dprintk("C%02X=%02X ", i, ACCESS_FBINFO(hw).DACclk[i]); | |
462 | dprintk("\n"); | |
463 | #endif | |
464 | } | |
465 | ||
466 | static 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++) | |
478 | outDAC1064(PMINFO M1064_XPIXPLLCM + i, ACCESS_FBINFO(hw).DACclk[i]); | |
479 | 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 | ||
494 | static struct matrox_altout m1064 = { | |
495 | .name = "Primary output", | |
496 | .compute = m1064_compute, | |
497 | }; | |
498 | ||
499 | #ifdef CONFIG_FB_MATROX_G | |
500 | static 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 | ||
512 | static 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 | |
521 | static int MGA1064_init(WPMINFO struct my_timming* m) { | |
522 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
523 | ||
5ae12170 | 524 | DBG(__func__) |
1da177e4 LT |
525 | |
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 | |
543 | static int MGAG100_init(WPMINFO struct my_timming* m) { | |
544 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
545 | ||
5ae12170 | 546 | DBG(__func__) |
1da177e4 LT |
547 | |
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 | |
566 | static void MGA1064_ramdac_init(WPMINFO2) { | |
567 | ||
5ae12170 | 568 | DBG(__func__) |
1da177e4 LT |
569 | |
570 | /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */ | |
571 | ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; | |
572 | ACCESS_FBINFO(features.pll.ref_freq) = 14318; | |
573 | ACCESS_FBINFO(features.pll.feed_div_min) = 100; | |
574 | ACCESS_FBINFO(features.pll.feed_div_max) = 127; | |
575 | ACCESS_FBINFO(features.pll.in_div_min) = 1; | |
576 | ACCESS_FBINFO(features.pll.in_div_max) = 31; | |
577 | ACCESS_FBINFO(features.pll.post_shift_max) = 3; | |
578 | ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL; | |
579 | /* 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 */ | |
586 | static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */ | |
587 | /* G100 wants 0x10, G200 SGRAM does not care... */ | |
588 | #if 0 | |
589 | static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */ | |
590 | #endif | |
591 | ||
592 | static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) { | |
593 | int reg; | |
594 | int selClk; | |
595 | int clk; | |
596 | ||
5ae12170 | 597 | DBG(__func__) |
1da177e4 LT |
598 | |
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 | ||
636 | static void MGAG100_setPixClock(CPMINFO int flags, int freq) { | |
637 | unsigned int m, n, p; | |
638 | ||
5ae12170 | 639 | DBG(__func__) |
1da177e4 LT |
640 | |
641 | DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); | |
642 | MGAG100_progPixClock(PMINFO flags, m, n, p); | |
643 | } | |
644 | #endif | |
645 | ||
646 | #ifdef CONFIG_FB_MATROX_MYSTIQUE | |
647 | static 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}; | |
651 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
652 | ||
5ae12170 | 653 | DBG(__func__) |
1da177e4 LT |
654 | |
655 | /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ | |
656 | ACCESS_FBINFO(capable.text) = 1; | |
657 | ACCESS_FBINFO(capable.vxres) = vxres_mystique; | |
1da177e4 LT |
658 | |
659 | ACCESS_FBINFO(outputs[0]).output = &m1064; | |
660 | ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src; | |
661 | ACCESS_FBINFO(outputs[0]).data = MINFO; | |
662 | ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR; | |
663 | ||
664 | if (ACCESS_FBINFO(devflags.noinit)) | |
665 | return 0; /* do not modify settings */ | |
666 | hw->MXoptionReg &= 0xC0000100; | |
667 | hw->MXoptionReg |= 0x00094E20; | |
668 | if (ACCESS_FBINFO(devflags.novga)) | |
669 | hw->MXoptionReg &= ~0x00000100; | |
670 | if (ACCESS_FBINFO(devflags.nobios)) | |
671 | hw->MXoptionReg &= ~0x40000000; | |
672 | if (ACCESS_FBINFO(devflags.nopciretry)) | |
673 | hw->MXoptionReg |= 0x20000000; | |
674 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); | |
675 | 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 | ||
684 | static void MGA1064_reset(WPMINFO2) { | |
685 | ||
5ae12170 | 686 | DBG(__func__); |
1da177e4 LT |
687 | |
688 | MGA1064_ramdac_init(PMINFO2); | |
689 | } | |
690 | #endif | |
691 | ||
692 | #ifdef CONFIG_FB_MATROX_G | |
693 | static void g450_mclk_init(WPMINFO2) { | |
694 | /* switch all clocks to PCI source */ | |
695 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4); | |
696 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION3_REG, ACCESS_FBINFO(values).reg.opt3 & ~0x00300C03); | |
697 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); | |
698 | ||
699 | if (((ACCESS_FBINFO(values).reg.opt3 & 0x000003) == 0x000003) || | |
700 | ((ACCESS_FBINFO(values).reg.opt3 & 0x000C00) == 0x000C00) || | |
701 | ((ACCESS_FBINFO(values).reg.opt3 & 0x300000) == 0x300000)) { | |
702 | matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.video), M_VIDEO_PLL); | |
703 | } 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 | } | |
712 | matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.system), M_SYSTEM_PLL); | |
713 | ||
714 | /* switch clocks to their real PLL source(s) */ | |
715 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4); | |
716 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION3_REG, ACCESS_FBINFO(values).reg.opt3); | |
717 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); | |
718 | ||
719 | } | |
720 | ||
721 | static void g450_memory_init(WPMINFO2) { | |
722 | /* disable memory refresh */ | |
723 | ACCESS_FBINFO(hw).MXoptionReg &= ~0x001F8000; | |
724 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); | |
725 | ||
726 | /* set memory interface parameters */ | |
727 | ACCESS_FBINFO(hw).MXoptionReg &= ~0x00207E00; | |
728 | ACCESS_FBINFO(hw).MXoptionReg |= 0x00207E00 & ACCESS_FBINFO(values).reg.opt; | |
729 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); | |
730 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, ACCESS_FBINFO(values).reg.opt2); | |
731 | ||
732 | mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst); | |
733 | ||
734 | /* first set up memory interface with disabled memory interface clocks */ | |
735 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MEMMISC_REG, ACCESS_FBINFO(values).reg.memmisc & ~0x80000000U); | |
736 | mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk); | |
737 | mga_outl(M_MACCESS, ACCESS_FBINFO(values).reg.maccess); | |
738 | /* start memory clocks */ | |
739 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MEMMISC_REG, ACCESS_FBINFO(values).reg.memmisc | 0x80000000U); | |
740 | ||
741 | udelay(200); | |
742 | ||
743 | if (ACCESS_FBINFO(values).memory.ddr && (!ACCESS_FBINFO(values).memory.emrswen || !ACCESS_FBINFO(values).memory.dll)) { | |
744 | mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk & ~0x1000); | |
745 | } | |
746 | mga_outl(M_MACCESS, ACCESS_FBINFO(values).reg.maccess | 0x8000); | |
747 | ||
748 | udelay(200); | |
749 | ||
750 | ACCESS_FBINFO(hw).MXoptionReg |= 0x001F8000 & ACCESS_FBINFO(values).reg.opt; | |
751 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); | |
752 | ||
753 | /* value is written to memory chips only if old != new */ | |
754 | mga_outl(M_PLNWT, 0); | |
755 | mga_outl(M_PLNWT, ~0); | |
756 | ||
757 | if (ACCESS_FBINFO(values).reg.mctlwtst != ACCESS_FBINFO(values).reg.mctlwtst_core) { | |
758 | mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst_core); | |
759 | } | |
760 | ||
761 | } | |
762 | ||
763 | static void g450_preinit(WPMINFO2) { | |
764 | u_int32_t c2ctl; | |
765 | u_int8_t curctl; | |
766 | u_int8_t c1ctl; | |
767 | ||
768 | /* ACCESS_FBINFO(hw).MXoptionReg = minfo->values.reg.opt; */ | |
769 | ACCESS_FBINFO(hw).MXoptionReg &= 0xC0000100; | |
770 | ACCESS_FBINFO(hw).MXoptionReg |= 0x00000020; | |
771 | if (ACCESS_FBINFO(devflags.novga)) | |
772 | ACCESS_FBINFO(hw).MXoptionReg &= ~0x00000100; | |
773 | if (ACCESS_FBINFO(devflags.nobios)) | |
774 | ACCESS_FBINFO(hw).MXoptionReg &= ~0x40000000; | |
775 | if (ACCESS_FBINFO(devflags.nopciretry)) | |
776 | ACCESS_FBINFO(hw).MXoptionReg |= 0x20000000; | |
777 | ACCESS_FBINFO(hw).MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x03400040; | |
778 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg); | |
779 | ||
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 | ||
811 | static 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}; | |
815 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
816 | ||
817 | u_int32_t reg50; | |
818 | #if 0 | |
819 | u_int32_t q; | |
820 | #endif | |
821 | ||
5ae12170 | 822 | DBG(__func__) |
1da177e4 LT |
823 | |
824 | /* there are some instabilities if in_div > 19 && vco < 61000 */ | |
825 | if (ACCESS_FBINFO(devflags.g450dac)) { | |
826 | ACCESS_FBINFO(features.pll.vco_freq_min) = 130000; /* my sample: >118 */ | |
827 | } else { | |
828 | ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; | |
829 | } | |
830 | if (!ACCESS_FBINFO(features.pll.ref_freq)) { | |
831 | ACCESS_FBINFO(features.pll.ref_freq) = 27000; | |
832 | } | |
833 | ACCESS_FBINFO(features.pll.feed_div_min) = 7; | |
834 | ACCESS_FBINFO(features.pll.feed_div_max) = 127; | |
835 | ACCESS_FBINFO(features.pll.in_div_min) = 1; | |
836 | ACCESS_FBINFO(features.pll.in_div_max) = 31; | |
837 | ACCESS_FBINFO(features.pll.post_shift_max) = 3; | |
838 | ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT; | |
839 | /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ | |
840 | ACCESS_FBINFO(capable.text) = 1; | |
841 | ACCESS_FBINFO(capable.vxres) = vxres_g100; | |
1da177e4 LT |
842 | ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100 |
843 | ? ACCESS_FBINFO(devflags.sgram) : 1; | |
844 | ||
845 | #ifdef CONFIG_FB_MATROX_G | |
846 | if (ACCESS_FBINFO(devflags.g450dac)) { | |
847 | ACCESS_FBINFO(outputs[0]).output = &g450out; | |
848 | } else | |
849 | #endif | |
850 | { | |
851 | ACCESS_FBINFO(outputs[0]).output = &m1064; | |
852 | } | |
853 | ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src; | |
854 | ACCESS_FBINFO(outputs[0]).data = MINFO; | |
855 | ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR; | |
856 | ||
857 | if (ACCESS_FBINFO(devflags.g450dac)) { | |
858 | /* we must do this always, BIOS does not do it for us | |
859 | and accelerator dies without it */ | |
860 | mga_outl(0x1C0C, 0); | |
861 | } | |
862 | if (ACCESS_FBINFO(devflags.noinit)) | |
863 | return 0; | |
864 | if (ACCESS_FBINFO(devflags.g450dac)) { | |
865 | g450_preinit(PMINFO2); | |
866 | return 0; | |
867 | } | |
868 | hw->MXoptionReg &= 0xC0000100; | |
869 | hw->MXoptionReg |= 0x00000020; | |
870 | if (ACCESS_FBINFO(devflags.novga)) | |
871 | hw->MXoptionReg &= ~0x00000100; | |
872 | if (ACCESS_FBINFO(devflags.nobios)) | |
873 | hw->MXoptionReg &= ~0x40000000; | |
874 | if (ACCESS_FBINFO(devflags.nopciretry)) | |
875 | hw->MXoptionReg |= 0x20000000; | |
876 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); | |
877 | DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333); | |
878 | ||
879 | if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) { | |
880 | pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, ®50); | |
881 | reg50 &= ~0x3000; | |
882 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50); | |
883 | ||
884 | hw->MXoptionReg |= 0x1080; | |
885 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); | |
886 | mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst); | |
887 | 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; | |
896 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50); | |
897 | /* 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); | |
902 | mga_writeb(ACCESS_FBINFO(video.vbase), 0x0000, 0xAA); | |
903 | mga_writeb(ACCESS_FBINFO(video.vbase), 0x0800, 0x55); | |
904 | mga_writeb(ACCESS_FBINFO(video.vbase), 0x4000, 0x55); | |
905 | #if 0 | |
906 | if (mga_readb(ACCESS_FBINFO(video.vbase), 0x0000) != 0xAA) { | |
907 | hw->MXoptionReg &= ~0x1000; | |
908 | } | |
909 | #endif | |
910 | hw->MXoptionReg |= 0x00078020; | |
911 | } else if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG200) { | |
912 | pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, ®50); | |
913 | reg50 &= ~0x3000; | |
914 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50); | |
915 | ||
916 | if (ACCESS_FBINFO(devflags.memtype) == -1) | |
917 | hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00; | |
918 | else | |
919 | hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10; | |
920 | if (ACCESS_FBINFO(devflags.sgram)) | |
921 | hw->MXoptionReg |= 0x4000; | |
922 | mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst); | |
923 | mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk); | |
924 | udelay(200); | |
925 | mga_outl(M_MACCESS, 0x00000000); | |
926 | mga_outl(M_MACCESS, 0x00008000); | |
927 | udelay(100); | |
928 | mga_outw(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk); | |
929 | hw->MXoptionReg |= 0x00078020; | |
930 | } else { | |
931 | pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, ®50); | |
932 | reg50 &= ~0x00000100; | |
933 | reg50 |= 0x00000000; | |
934 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50); | |
935 | ||
936 | if (ACCESS_FBINFO(devflags.memtype) == -1) | |
937 | hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00; | |
938 | else | |
939 | hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10; | |
940 | if (ACCESS_FBINFO(devflags.sgram)) | |
941 | hw->MXoptionReg |= 0x4000; | |
942 | mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst); | |
943 | mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk); | |
944 | udelay(200); | |
945 | mga_outl(M_MACCESS, 0x00000000); | |
946 | mga_outl(M_MACCESS, 0x00008000); | |
947 | udelay(100); | |
948 | mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk); | |
949 | hw->MXoptionReg |= 0x00040020; | |
950 | } | |
951 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); | |
952 | return 0; | |
953 | } | |
954 | ||
955 | static void MGAG100_reset(WPMINFO2) { | |
956 | u_int8_t b; | |
957 | struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); | |
958 | ||
5ae12170 | 959 | DBG(__func__) |
1da177e4 LT |
960 | |
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); | |
967 | if (b == ACCESS_FBINFO(pcidev)->bus->number) { | |
968 | 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 | |
974 | if (!ACCESS_FBINFO(devflags.noinit)) { | |
975 | if (x7AF4 & 8) { | |
976 | hw->MXoptionReg |= 0x40; /* FIXME... */ | |
977 | pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); | |
978 | } | |