Rev 489 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
489 | giacomo | 1 | /* |
2 | * |
||
3 | * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 |
||
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 | * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> |
||
12 | * |
||
13 | * Contributors: "menion?" <menion@mindless.com> |
||
14 | * Betatesting, fixes, ideas |
||
15 | * |
||
16 | * "Kurt Garloff" <garloff@suse.de> |
||
17 | * Betatesting, fixes, ideas, videomodes, videomodes timmings |
||
18 | * |
||
19 | * "Tom Rini" <trini@kernel.crashing.org> |
||
20 | * MTRR stuff, PPC cleanups, betatesting, fixes, ideas |
||
21 | * |
||
22 | * "Bibek Sahu" <scorpio@dodds.net> |
||
23 | * Access device through readb|w|l and write b|w|l |
||
24 | * Extensive debugging stuff |
||
25 | * |
||
26 | * "Daniel Haun" <haund@usa.net> |
||
27 | * Testing, hardware cursor fixes |
||
28 | * |
||
29 | * "Scott Wood" <sawst46+@pitt.edu> |
||
30 | * Fixes |
||
31 | * |
||
32 | * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> |
||
33 | * Betatesting |
||
34 | * |
||
35 | * "Kelly French" <targon@hazmat.com> |
||
36 | * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> |
||
37 | * Betatesting, bug reporting |
||
38 | * |
||
39 | * "Pablo Bianucci" <pbian@pccp.com.ar> |
||
40 | * Fixes, ideas, betatesting |
||
41 | * |
||
42 | * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> |
||
43 | * Fixes, enhandcements, ideas, betatesting |
||
44 | * |
||
45 | * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> |
||
46 | * PPC betatesting, PPC support, backward compatibility |
||
47 | * |
||
48 | * "Paul Womar" <Paul@pwomar.demon.co.uk> |
||
49 | * "Owen Waller" <O.Waller@ee.qub.ac.uk> |
||
50 | * PPC betatesting |
||
51 | * |
||
52 | * "Thomas Pornin" <pornin@bolet.ens.fr> |
||
53 | * Alpha betatesting |
||
54 | * |
||
55 | * "Pieter van Leuven" <pvl@iae.nl> |
||
56 | * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> |
||
57 | * G100 testing |
||
58 | * |
||
59 | * "H. Peter Arvin" <hpa@transmeta.com> |
||
60 | * Ideas |
||
61 | * |
||
62 | * "Cort Dougan" <cort@cs.nmt.edu> |
||
63 | * CHRP fixes and PReP cleanup |
||
64 | * |
||
65 | * "Mark Vojkovich" <mvojkovi@ucsd.edu> |
||
66 | * G400 support |
||
67 | * |
||
68 | * "David C. Hansen" <haveblue@us.ibm.com> |
||
69 | * Fixes |
||
70 | * |
||
71 | * (following author is not in any relation with this code, but his code |
||
72 | * is included in this driver) |
||
73 | * |
||
74 | * Based on framebuffer driver for VBE 2.0 compliant graphic boards |
||
75 | * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> |
||
76 | * |
||
77 | * (following author is not in any relation with this code, but his ideas |
||
78 | * were used when writting this driver) |
||
79 | * |
||
80 | * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> |
||
81 | * |
||
82 | */ |
||
83 | |||
84 | /* make checkconfig does not check includes for this... */ |
||
85 | |||
86 | #include <linuxcomp.h> |
||
87 | |||
88 | #include <linux/config.h> |
||
89 | |||
90 | #include "matroxfb_misc.h" |
||
91 | #include <linux/interrupt.h> |
||
92 | #include <linux/matroxfb.h> |
||
93 | |||
94 | void matroxfb_DAC_out(CPMINFO int reg, int val) { |
||
95 | DBG_REG(__FUNCTION__) |
||
96 | mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); |
||
97 | mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val); |
||
98 | } |
||
99 | |||
100 | int matroxfb_DAC_in(CPMINFO int reg) { |
||
101 | DBG_REG(__FUNCTION__) |
||
102 | mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); |
||
103 | return mga_inb(M_RAMDAC_BASE+M_X_DATAREG); |
||
104 | } |
||
105 | |||
106 | void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { |
||
107 | unsigned int pixclock = var->pixclock; |
||
108 | |||
109 | DBG(__FUNCTION__) |
||
110 | |||
111 | if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ |
||
112 | mt->pixclock = 1000000000 / pixclock; |
||
113 | if (mt->pixclock < 1) mt->pixclock = 1; |
||
114 | mt->mnp = -1; |
||
115 | mt->dblscan = var->vmode & FB_VMODE_DOUBLE; |
||
116 | mt->interlaced = var->vmode & FB_VMODE_INTERLACED; |
||
117 | mt->HDisplay = var->xres; |
||
118 | mt->HSyncStart = mt->HDisplay + var->right_margin; |
||
119 | mt->HSyncEnd = mt->HSyncStart + var->hsync_len; |
||
120 | mt->HTotal = mt->HSyncEnd + var->left_margin; |
||
121 | mt->VDisplay = var->yres; |
||
122 | mt->VSyncStart = mt->VDisplay + var->lower_margin; |
||
123 | mt->VSyncEnd = mt->VSyncStart + var->vsync_len; |
||
124 | mt->VTotal = mt->VSyncEnd + var->upper_margin; |
||
125 | mt->sync = var->sync; |
||
126 | } |
||
127 | |||
128 | int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax, |
||
129 | unsigned int* in, unsigned int* feed, unsigned int* post) { |
||
130 | unsigned int bestdiff = ~0; |
||
131 | unsigned int bestvco = 0; |
||
132 | unsigned int fxtal = pll->ref_freq; |
||
133 | unsigned int fwant; |
||
134 | unsigned int p; |
||
135 | |||
136 | DBG(__FUNCTION__) |
||
137 | |||
138 | fwant = freq; |
||
139 | |||
140 | #ifdef DEBUG |
||
141 | printk(KERN_ERR "post_shift_max: %d\n", pll->post_shift_max); |
||
142 | printk(KERN_ERR "ref_freq: %d\n", pll->ref_freq); |
||
143 | printk(KERN_ERR "freq: %d\n", freq); |
||
144 | printk(KERN_ERR "vco_freq_min: %d\n", pll->vco_freq_min); |
||
145 | printk(KERN_ERR "in_div_min: %d\n", pll->in_div_min); |
||
146 | printk(KERN_ERR "in_div_max: %d\n", pll->in_div_max); |
||
147 | printk(KERN_ERR "feed_div_min: %d\n", pll->feed_div_min); |
||
148 | printk(KERN_ERR "feed_div_max: %d\n", pll->feed_div_max); |
||
149 | printk(KERN_ERR "fmax: %d\n", fmax); |
||
150 | #endif |
||
151 | for (p = 1; p <= pll->post_shift_max; p++) { |
||
152 | if (fwant * 2 > fmax) |
||
153 | break; |
||
154 | fwant *= 2; |
||
155 | } |
||
156 | if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min; |
||
157 | if (fwant > fmax) fwant = fmax; |
||
158 | for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) { |
||
159 | unsigned int m; |
||
160 | |||
161 | if (fwant < pll->vco_freq_min) break; |
||
162 | for (m = pll->in_div_min; m <= pll->in_div_max; m++) { |
||
163 | unsigned int diff, fvco; |
||
164 | unsigned int n; |
||
165 | |||
166 | n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1; |
||
167 | if (n > pll->feed_div_max) |
||
168 | break; |
||
169 | if (n < pll->feed_div_min) |
||
170 | n = pll->feed_div_min; |
||
171 | fvco = (fxtal * (n + 1)) / (m + 1); |
||
172 | if (fvco < fwant) |
||
173 | diff = fwant - fvco; |
||
174 | else |
||
175 | diff = fvco - fwant; |
||
176 | if (diff < bestdiff) { |
||
177 | bestdiff = diff; |
||
178 | *post = p; |
||
179 | *in = m; |
||
180 | *feed = n; |
||
181 | bestvco = fvco; |
||
182 | } |
||
183 | } |
||
184 | } |
||
185 | dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant); |
||
186 | return bestvco; |
||
187 | } |
||
188 | |||
189 | int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) { |
||
190 | unsigned int hd, hs, he, hbe, ht; |
||
191 | unsigned int vd, vs, ve, vt, lc; |
||
192 | unsigned int wd; |
||
193 | unsigned int divider; |
||
194 | int i; |
||
195 | int fwidth; |
||
196 | struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); |
||
197 | |||
198 | fwidth = 8; |
||
199 | |||
200 | DBG(__FUNCTION__) |
||
201 | |||
202 | hw->SEQ[0] = 0x00; |
||
203 | if (fwidth == 9) |
||
204 | hw->SEQ[1] = 0x00; |
||
205 | else |
||
206 | hw->SEQ[1] = 0x01; /* or 0x09 */ |
||
207 | hw->SEQ[2] = 0x0F; /* bitplanes */ |
||
208 | hw->SEQ[3] = 0x00; |
||
209 | hw->SEQ[4] = 0x0E; |
||
210 | /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millennium code... Hope that by MGA1064 too */ |
||
211 | if (m->dblscan) { |
||
212 | m->VTotal <<= 1; |
||
213 | m->VDisplay <<= 1; |
||
214 | m->VSyncStart <<= 1; |
||
215 | m->VSyncEnd <<= 1; |
||
216 | } |
||
217 | if (m->interlaced) { |
||
218 | m->VTotal >>= 1; |
||
219 | m->VDisplay >>= 1; |
||
220 | m->VSyncStart >>= 1; |
||
221 | m->VSyncEnd >>= 1; |
||
222 | } |
||
223 | |||
224 | /* GCTL is ignored when not using 0xA0000 aperture */ |
||
225 | hw->GCTL[0] = 0x00; |
||
226 | hw->GCTL[1] = 0x00; |
||
227 | hw->GCTL[2] = 0x00; |
||
228 | hw->GCTL[3] = 0x00; |
||
229 | hw->GCTL[4] = 0x00; |
||
230 | hw->GCTL[5] = 0x40; |
||
231 | hw->GCTL[6] = 0x05; |
||
232 | hw->GCTL[7] = 0x0F; |
||
233 | hw->GCTL[8] = 0xFF; |
||
234 | |||
235 | /* Whole ATTR is ignored in PowerGraphics mode */ |
||
236 | for (i = 0; i < 16; i++) |
||
237 | hw->ATTR[i] = i; |
||
238 | hw->ATTR[16] = 0x41; |
||
239 | hw->ATTR[17] = 0xFF; |
||
240 | hw->ATTR[18] = 0x0F; |
||
241 | if (fwidth == 9) |
||
242 | hw->ATTR[19] = 0x08; |
||
243 | else |
||
244 | hw->ATTR[19] = 0x00; |
||
245 | hw->ATTR[20] = 0x00; |
||
246 | |||
247 | hd = m->HDisplay >> 3; |
||
248 | hs = m->HSyncStart >> 3; |
||
249 | he = m->HSyncEnd >> 3; |
||
250 | ht = m->HTotal >> 3; |
||
251 | /* standard timmings are in 8pixels, but for interleaved we cannot */ |
||
252 | /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */ |
||
253 | /* using 16 or more pixels per unit can save us */ |
||
254 | divider = ACCESS_FBINFO(curr.final_bppShift); |
||
255 | while (divider & 3) { |
||
256 | hd >>= 1; |
||
257 | hs >>= 1; |
||
258 | he >>= 1; |
||
259 | ht >>= 1; |
||
260 | divider <<= 1; |
||
261 | } |
||
262 | divider = divider / 4; |
||
263 | /* divider can be from 1 to 8 */ |
||
264 | while (divider > 8) { |
||
265 | hd <<= 1; |
||
266 | hs <<= 1; |
||
267 | he <<= 1; |
||
268 | ht <<= 1; |
||
269 | divider >>= 1; |
||
270 | } |
||
271 | hd = hd - 1; |
||
272 | hs = hs - 1; |
||
273 | he = he - 1; |
||
274 | ht = ht - 1; |
||
275 | vd = m->VDisplay - 1; |
||
276 | vs = m->VSyncStart - 1; |
||
277 | ve = m->VSyncEnd - 1; |
||
278 | vt = m->VTotal - 2; |
||
279 | lc = vd; |
||
280 | /* G200 cannot work with (ht & 7) == 6 */ |
||
281 | if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04)) |
||
282 | ht++; |
||
283 | hbe = ht; |
||
284 | wd = ACCESS_FBINFO(fbcon).var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64; |
||
285 | |||
286 | hw->CRTCEXT[0] = 0; |
||
287 | hw->CRTCEXT[5] = 0; |
||
288 | if (m->interlaced) { |
||
289 | hw->CRTCEXT[0] = 0x80; |
||
290 | hw->CRTCEXT[5] = (hs + he - ht) >> 1; |
||
291 | if (!m->dblscan) |
||
292 | wd <<= 1; |
||
293 | vt &= ~1; |
||
294 | } |
||
295 | hw->CRTCEXT[0] |= (wd & 0x300) >> 4; |
||
296 | hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) | |
||
297 | ((hd & 0x100) >> 7) | /* blanking */ |
||
298 | ((hs & 0x100) >> 6) | /* sync start */ |
||
299 | (hbe & 0x040); /* end hor. blanking */ |
||
300 | /* FIXME: Enable vidrst only on G400, and only if TV-out is used */ |
||
301 | if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) |
||
302 | hw->CRTCEXT[1] |= 0x88; /* enable horizontal and vertical vidrst */ |
||
303 | hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) | |
||
304 | ((vd & 0x400) >> 8) | /* disp end */ |
||
305 | ((vd & 0xC00) >> 7) | /* vblanking start */ |
||
306 | ((vs & 0xC00) >> 5) | |
||
307 | ((lc & 0x400) >> 3); |
||
308 | hw->CRTCEXT[3] = (divider - 1) | 0x80; |
||
309 | hw->CRTCEXT[4] = 0; |
||
310 | |||
311 | hw->CRTC[0] = ht-4; |
||
312 | hw->CRTC[1] = hd; |
||
313 | hw->CRTC[2] = hd; |
||
314 | hw->CRTC[3] = (hbe & 0x1F) | 0x80; |
||
315 | hw->CRTC[4] = hs; |
||
316 | hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F); |
||
317 | hw->CRTC[6] = vt & 0xFF; |
||
318 | hw->CRTC[7] = ((vt & 0x100) >> 8) | |
||
319 | ((vd & 0x100) >> 7) | |
||
320 | ((vs & 0x100) >> 6) | |
||
321 | ((vd & 0x100) >> 5) | |
||
322 | ((lc & 0x100) >> 4) | |
||
323 | ((vt & 0x200) >> 4) | |
||
324 | ((vd & 0x200) >> 3) | |
||
325 | ((vs & 0x200) >> 2); |
||
326 | hw->CRTC[8] = 0x00; |
||
327 | hw->CRTC[9] = ((vd & 0x200) >> 4) | |
||
328 | ((lc & 0x200) >> 3); |
||
329 | if (m->dblscan && !m->interlaced) |
||
330 | hw->CRTC[9] |= 0x80; |
||
331 | for (i = 10; i < 16; i++) |
||
332 | hw->CRTC[i] = 0x00; |
||
333 | hw->CRTC[16] = vs /* & 0xFF */; |
||
334 | hw->CRTC[17] = (ve & 0x0F) | 0x20; |
||
335 | hw->CRTC[18] = vd /* & 0xFF */; |
||
336 | hw->CRTC[19] = wd /* & 0xFF */; |
||
337 | hw->CRTC[20] = 0x00; |
||
338 | hw->CRTC[21] = vd /* & 0xFF */; |
||
339 | hw->CRTC[22] = (vt + 1) /* & 0xFF */; |
||
340 | hw->CRTC[23] = 0xC3; |
||
341 | hw->CRTC[24] = lc; |
||
342 | return 0; |
||
343 | }; |
||
344 | |||
345 | void matroxfb_vgaHWrestore(WPMINFO2) { |
||
346 | int i; |
||
347 | struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); |
||
348 | CRITFLAGS |
||
349 | |||
350 | DBG(__FUNCTION__) |
||
351 | |||
352 | dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg); |
||
353 | dprintk(KERN_INFO "SEQ regs: "); |
||
354 | for (i = 0; i < 5; i++) |
||
355 | dprintk("%02X:", hw->SEQ[i]); |
||
356 | dprintk("\n"); |
||
357 | dprintk(KERN_INFO "GDC regs: "); |
||
358 | for (i = 0; i < 9; i++) |
||
359 | dprintk("%02X:", hw->GCTL[i]); |
||
360 | dprintk("\n"); |
||
361 | dprintk(KERN_INFO "CRTC regs: "); |
||
362 | for (i = 0; i < 25; i++) |
||
363 | dprintk("%02X:", hw->CRTC[i]); |
||
364 | dprintk("\n"); |
||
365 | dprintk(KERN_INFO "ATTR regs: "); |
||
366 | for (i = 0; i < 21; i++) |
||
367 | dprintk("%02X:", hw->ATTR[i]); |
||
368 | dprintk("\n"); |
||
369 | |||
370 | CRITBEGIN |
||
371 | |||
372 | mga_inb(M_ATTR_RESET); |
||
373 | mga_outb(M_ATTR_INDEX, 0); |
||
374 | mga_outb(M_MISC_REG, hw->MiscOutReg); |
||
375 | for (i = 1; i < 5; i++) |
||
376 | mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]); |
||
377 | mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F); |
||
378 | for (i = 0; i < 25; i++) |
||
379 | mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]); |
||
380 | for (i = 0; i < 9; i++) |
||
381 | mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]); |
||
382 | for (i = 0; i < 21; i++) { |
||
383 | mga_inb(M_ATTR_RESET); |
||
384 | mga_outb(M_ATTR_INDEX, i); |
||
385 | mga_outb(M_ATTR_INDEX, hw->ATTR[i]); |
||
386 | } |
||
387 | mga_outb(M_PALETTE_MASK, 0xFF); |
||
388 | mga_outb(M_DAC_REG, 0x00); |
||
389 | for (i = 0; i < 768; i++) |
||
390 | mga_outb(M_DAC_VAL, hw->DACpal[i]); |
||
391 | mga_inb(M_ATTR_RESET); |
||
392 | mga_outb(M_ATTR_INDEX, 0x20); |
||
393 | |||
394 | CRITEND |
||
395 | } |
||
396 | |||
397 | static void get_pins(unsigned char* pins, struct matrox_bios* bd) { |
||
398 | unsigned int b0 = readb(pins); |
||
399 | |||
400 | if (b0 == 0x2E && readb(pins+1) == 0x41) { |
||
401 | unsigned int pins_len = readb(pins+2); |
||
402 | unsigned int i; |
||
403 | unsigned char cksum; |
||
404 | unsigned char* dst = bd->pins; |
||
405 | |||
406 | if (pins_len < 3 || pins_len > 128) { |
||
407 | return; |
||
408 | } |
||
409 | *dst++ = 0x2E; |
||
410 | *dst++ = 0x41; |
||
411 | *dst++ = pins_len; |
||
412 | cksum = 0x2E + 0x41 + pins_len; |
||
413 | for (i = 3; i < pins_len; i++) { |
||
414 | cksum += *dst++ = readb(pins+i); |
||
415 | } |
||
416 | if (cksum) { |
||
417 | return; |
||
418 | } |
||
419 | bd->pins_len = pins_len; |
||
420 | } else if (b0 == 0x40 && readb(pins+1) == 0x00) { |
||
421 | unsigned int i; |
||
422 | unsigned char* dst = bd->pins; |
||
423 | |||
424 | *dst++ = 0x40; |
||
425 | *dst++ = 0; |
||
426 | for (i = 2; i < 0x40; i++) { |
||
427 | *dst++ = readb(pins+i); |
||
428 | } |
||
429 | bd->pins_len = 0x40; |
||
430 | } |
||
431 | } |
||
432 | |||
433 | static void get_bios_version(unsigned char* vbios, struct matrox_bios* bd) { |
||
434 | unsigned int pcir_offset; |
||
435 | |||
436 | pcir_offset = readb(vbios + 24) | (readb(vbios + 25) << 8); |
||
437 | if (pcir_offset >= 26 && pcir_offset < 0xFFE0 && |
||
438 | readb(vbios + pcir_offset ) == 'P' && |
||
439 | readb(vbios + pcir_offset + 1) == 'C' && |
||
440 | readb(vbios + pcir_offset + 2) == 'I' && |
||
441 | readb(vbios + pcir_offset + 3) == 'R') { |
||
442 | unsigned char h; |
||
443 | |||
444 | h = readb(vbios + pcir_offset + 0x12); |
||
445 | bd->version.vMaj = (h >> 4) & 0xF; |
||
446 | bd->version.vMin = h & 0xF; |
||
447 | bd->version.vRev = readb(vbios + pcir_offset + 0x13); |
||
448 | } else { |
||
449 | unsigned char h; |
||
450 | |||
451 | h = readb(vbios + 5); |
||
452 | bd->version.vMaj = (h >> 4) & 0xF; |
||
453 | bd->version.vMin = h & 0xF; |
||
454 | bd->version.vRev = 0; |
||
455 | } |
||
456 | } |
||
457 | |||
458 | static void get_bios_output(unsigned char* vbios, struct matrox_bios* bd) { |
||
459 | unsigned char b; |
||
460 | |||
461 | b = readb(vbios + 0x7FF1); |
||
462 | if (b == 0xFF) { |
||
463 | b = 0; |
||
464 | } |
||
465 | bd->output.state = b; |
||
466 | } |
||
467 | |||
468 | static void get_bios_tvout(unsigned char* vbios, struct matrox_bios* bd) { |
||
469 | unsigned int i; |
||
470 | |||
471 | /* Check for 'IBM .*(V....TVO' string - it means TVO BIOS */ |
||
472 | bd->output.tvout = 0; |
||
473 | if (readb(vbios + 0x1D) != 'I' || |
||
474 | readb(vbios + 0x1E) != 'B' || |
||
475 | readb(vbios + 0x1F) != 'M' || |
||
476 | readb(vbios + 0x20) != ' ') { |
||
477 | return; |
||
478 | } |
||
479 | for (i = 0x2D; i < 0x2D + 128; i++) { |
||
480 | unsigned char b = readb(vbios + i); |
||
481 | |||
482 | if (b == '(' && readb(vbios + i + 1) == 'V') { |
||
483 | if (readb(vbios + i + 6) == 'T' && |
||
484 | readb(vbios + i + 7) == 'V' && |
||
485 | readb(vbios + i + 8) == 'O') { |
||
486 | bd->output.tvout = 1; |
||
487 | } |
||
488 | return; |
||
489 | } |
||
490 | if (b == 0) |
||
491 | break; |
||
492 | } |
||
493 | } |
||
494 | |||
495 | static void parse_bios(unsigned char* vbios, struct matrox_bios* bd) { |
||
496 | unsigned int pins_offset; |
||
497 | |||
498 | if (readb(vbios) != 0x55 || readb(vbios + 1) != 0xAA) { |
||
499 | return; |
||
500 | } |
||
501 | bd->bios_valid = 1; |
||
502 | get_bios_version(vbios, bd); |
||
503 | get_bios_output(vbios, bd); |
||
504 | get_bios_tvout(vbios, bd); |
||
505 | pins_offset = readb(vbios + 0x7FFC) | (readb(vbios + 0x7FFD) << 8); |
||
506 | if (pins_offset <= 0xFF80) { |
||
507 | get_pins(vbios + pins_offset, bd); |
||
508 | } |
||
509 | } |
||
510 | |||
511 | #define get_u16(x) (le16_to_cpu(get_unaligned((__u16*)(x)))) |
||
512 | #define get_u32(x) (le32_to_cpu(get_unaligned((__u32*)(x)))) |
||
513 | static int parse_pins1(WPMINFO const struct matrox_bios* bd) { |
||
514 | unsigned int maxdac; |
||
515 | |||
516 | switch (bd->pins[22]) { |
||
517 | case 0: maxdac = 175000; break; |
||
518 | case 1: maxdac = 220000; break; |
||
519 | default: maxdac = 240000; break; |
||
520 | } |
||
521 | if (get_u16(bd->pins + 24)) { |
||
522 | maxdac = get_u16(bd->pins + 24) * 10; |
||
523 | } |
||
524 | MINFO->limits.pixel.vcomax = maxdac; |
||
525 | MINFO->values.pll.system = get_u16(bd->pins + 28) ? get_u16(bd->pins + 28) * 10 : 50000; |
||
526 | /* ignore 4MB, 8MB, module clocks */ |
||
527 | MINFO->features.pll.ref_freq = 14318; |
||
528 | MINFO->values.reg.mctlwtst = 0x00030101; |
||
529 | return 0; |
||
530 | } |
||
531 | |||
532 | static void default_pins1(WPMINFO2) { |
||
533 | /* Millennium */ |
||
534 | MINFO->limits.pixel.vcomax = 220000; |
||
535 | MINFO->values.pll.system = 50000; |
||
536 | MINFO->features.pll.ref_freq = 14318; |
||
537 | MINFO->values.reg.mctlwtst = 0x00030101; |
||
538 | } |
||
539 | |||
540 | static int parse_pins2(WPMINFO const struct matrox_bios* bd) { |
||
541 | MINFO->limits.pixel.vcomax = |
||
542 | MINFO->limits.system.vcomax = (bd->pins[41] == 0xFF) ? 230000 : ((bd->pins[41] + 100) * 1000); |
||
543 | MINFO->values.reg.mctlwtst = ((bd->pins[51] & 0x01) ? 0x00000001 : 0) | |
||
544 | ((bd->pins[51] & 0x02) ? 0x00000100 : 0) | |
||
545 | ((bd->pins[51] & 0x04) ? 0x00010000 : 0) | |
||
546 | ((bd->pins[51] & 0x08) ? 0x00020000 : 0); |
||
547 | MINFO->values.pll.system = (bd->pins[43] == 0xFF) ? 50000 : ((bd->pins[43] + 100) * 1000); |
||
548 | MINFO->features.pll.ref_freq = 14318; |
||
549 | return 0; |
||
550 | } |
||
551 | |||
552 | static void default_pins2(WPMINFO2) { |
||
553 | /* Millennium II, Mystique */ |
||
554 | MINFO->limits.pixel.vcomax = |
||
555 | MINFO->limits.system.vcomax = 230000; |
||
556 | MINFO->values.reg.mctlwtst = 0x00030101; |
||
557 | MINFO->values.pll.system = 50000; |
||
558 | MINFO->features.pll.ref_freq = 14318; |
||
559 | } |
||
560 | |||
561 | static int parse_pins3(WPMINFO const struct matrox_bios* bd) { |
||
562 | MINFO->limits.pixel.vcomax = |
||
563 | MINFO->limits.system.vcomax = (bd->pins[36] == 0xFF) ? 230000 : ((bd->pins[36] + 100) * 1000); |
||
564 | MINFO->values.reg.mctlwtst = get_u32(bd->pins + 48) == 0xFFFFFFFF ? 0x01250A21 : get_u32(bd->pins + 48); |
||
565 | /* memory config */ |
||
566 | MINFO->values.reg.memrdbk = ((bd->pins[57] << 21) & 0x1E000000) | |
||
567 | ((bd->pins[57] << 22) & 0x00C00000) | |
||
568 | ((bd->pins[56] << 1) & 0x000001E0) | |
||
569 | ( bd->pins[56] & 0x0000000F); |
||
570 | MINFO->values.reg.opt = (bd->pins[54] & 7) << 10; |
||
571 | MINFO->values.reg.opt2 = bd->pins[58] << 12; |
||
572 | MINFO->features.pll.ref_freq = (bd->pins[52] & 0x20) ? 14318 : 27000; |
||
573 | return 0; |
||
574 | } |
||
575 | |||
576 | static void default_pins3(WPMINFO2) { |
||
577 | /* G100, G200 */ |
||
578 | MINFO->limits.pixel.vcomax = |
||
579 | MINFO->limits.system.vcomax = 230000; |
||
580 | MINFO->values.reg.mctlwtst = 0x01250A21; |
||
581 | MINFO->values.reg.memrdbk = 0x00000000; |
||
582 | MINFO->values.reg.opt = 0x00000C00; |
||
583 | MINFO->values.reg.opt2 = 0x00000000; |
||
584 | MINFO->features.pll.ref_freq = 27000; |
||
585 | } |
||
586 | |||
587 | static int parse_pins4(WPMINFO const struct matrox_bios* bd) { |
||
588 | MINFO->limits.pixel.vcomax = (bd->pins[ 39] == 0xFF) ? 230000 : bd->pins[ 39] * 4000; |
||
589 | MINFO->limits.system.vcomax = (bd->pins[ 38] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 38] * 4000; |
||
590 | MINFO->values.reg.mctlwtst = get_u32(bd->pins + 71); |
||
591 | MINFO->values.reg.memrdbk = ((bd->pins[87] << 21) & 0x1E000000) | |
||
592 | ((bd->pins[87] << 22) & 0x00C00000) | |
||
593 | ((bd->pins[86] << 1) & 0x000001E0) | |
||
594 | ( bd->pins[86] & 0x0000000F); |
||
595 | MINFO->values.reg.opt = ((bd->pins[53] << 15) & 0x00400000) | |
||
596 | ((bd->pins[53] << 22) & 0x10000000) | |
||
597 | ((bd->pins[53] << 7) & 0x00001C00); |
||
598 | MINFO->values.reg.opt3 = get_u32(bd->pins + 67); |
||
599 | MINFO->values.pll.system = (bd->pins[ 65] == 0xFF) ? 200000 : bd->pins[ 65] * 4000; |
||
600 | MINFO->features.pll.ref_freq = (bd->pins[ 92] & 0x01) ? 14318 : 27000; |
||
601 | return 0; |
||
602 | } |
||
603 | |||
604 | static void default_pins4(WPMINFO2) { |
||
605 | /* G400 */ |
||
606 | MINFO->limits.pixel.vcomax = |
||
607 | MINFO->limits.system.vcomax = 252000; |
||
608 | MINFO->values.reg.mctlwtst = 0x04A450A1; |
||
609 | MINFO->values.reg.memrdbk = 0x000000E7; |
||
610 | MINFO->values.reg.opt = 0x10000400; |
||
611 | MINFO->values.reg.opt3 = 0x0190A419; |
||
612 | MINFO->values.pll.system = 200000; |
||
613 | MINFO->features.pll.ref_freq = 27000; |
||
614 | } |
||
615 | |||
616 | static int parse_pins5(WPMINFO const struct matrox_bios* bd) { |
||
617 | unsigned int mult; |
||
618 | |||
619 | mult = bd->pins[4]?8000:6000; |
||
620 | |||
621 | MINFO->limits.pixel.vcomax = (bd->pins[ 38] == 0xFF) ? 600000 : bd->pins[ 38] * mult; |
||
622 | MINFO->limits.system.vcomax = (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 36] * mult; |
||
623 | MINFO->limits.video.vcomax = (bd->pins[ 37] == 0xFF) ? MINFO->limits.system.vcomax : bd->pins[ 37] * mult; |
||
624 | MINFO->limits.pixel.vcomin = (bd->pins[123] == 0xFF) ? 256000 : bd->pins[123] * mult; |
||
625 | MINFO->limits.system.vcomin = (bd->pins[121] == 0xFF) ? MINFO->limits.pixel.vcomin : bd->pins[121] * mult; |
||
626 | MINFO->limits.video.vcomin = (bd->pins[122] == 0xFF) ? MINFO->limits.system.vcomin : bd->pins[122] * mult; |
||
627 | MINFO->values.pll.system = |
||
628 | MINFO->values.pll.video = (bd->pins[ 92] == 0xFF) ? 284000 : bd->pins[ 92] * 4000; |
||
629 | MINFO->values.reg.opt = get_u32(bd->pins+ 48); |
||
630 | MINFO->values.reg.opt2 = get_u32(bd->pins+ 52); |
||
631 | MINFO->values.reg.opt3 = get_u32(bd->pins+ 94); |
||
632 | MINFO->values.reg.mctlwtst = get_u32(bd->pins+ 98); |
||
633 | MINFO->values.reg.memmisc = get_u32(bd->pins+102); |
||
634 | MINFO->values.reg.memrdbk = get_u32(bd->pins+106); |
||
635 | MINFO->features.pll.ref_freq = (bd->pins[110] & 0x01) ? 14318 : 27000; |
||
636 | MINFO->values.memory.ddr = (bd->pins[114] & 0x60) == 0x20; |
||
637 | MINFO->values.memory.dll = (bd->pins[115] & 0x02) != 0; |
||
638 | MINFO->values.memory.emrswen = (bd->pins[115] & 0x01) != 0; |
||
639 | MINFO->values.reg.maccess = MINFO->values.memory.emrswen ? 0x00004000 : 0x00000000; |
||
640 | if (bd->pins[115] & 4) { |
||
641 | MINFO->values.reg.mctlwtst_core = MINFO->values.reg.mctlwtst; |
||
642 | } else { |
||
643 | u_int32_t wtst_xlat[] = { 0, 1, 5, 6, 7, 5, 2, 3 }; |
||
644 | MINFO->values.reg.mctlwtst_core = (MINFO->values.reg.mctlwtst & ~7) | |
||
645 | wtst_xlat[MINFO->values.reg.mctlwtst & 7]; |
||
646 | } |
||
647 | return 0; |
||
648 | } |
||
649 | |||
650 | static void default_pins5(WPMINFO2) { |
||
651 | /* Mine 16MB G450 with SDRAM DDR */ |
||
652 | MINFO->limits.pixel.vcomax = |
||
653 | MINFO->limits.system.vcomax = |
||
654 | MINFO->limits.video.vcomax = 600000; |
||
655 | MINFO->limits.pixel.vcomin = |
||
656 | MINFO->limits.system.vcomin = |
||
657 | MINFO->limits.video.vcomin = 256000; |
||
658 | MINFO->values.pll.system = |
||
659 | MINFO->values.pll.video = 284000; |
||
660 | MINFO->values.reg.opt = 0x404A1160; |
||
661 | MINFO->values.reg.opt2 = 0x0000AC00; |
||
662 | MINFO->values.reg.opt3 = 0x0090A409; |
||
663 | MINFO->values.reg.mctlwtst_core = |
||
664 | MINFO->values.reg.mctlwtst = 0x0C81462B; |
||
665 | MINFO->values.reg.memmisc = 0x80000004; |
||
666 | MINFO->values.reg.memrdbk = 0x01001103; |
||
667 | MINFO->features.pll.ref_freq = 27000; |
||
668 | MINFO->values.memory.ddr = 1; |
||
669 | MINFO->values.memory.dll = 1; |
||
670 | MINFO->values.memory.emrswen = 1; |
||
671 | MINFO->values.reg.maccess = 0x00004000; |
||
672 | } |
||
673 | |||
674 | static int matroxfb_set_limits(WPMINFO const struct matrox_bios* bd) { |
||
675 | unsigned int pins_version; |
||
676 | static const unsigned int pinslen[] = { 64, 64, 64, 128, 128 }; |
||
677 | |||
678 | switch (ACCESS_FBINFO(chip)) { |
||
679 | case MGA_2064: default_pins1(PMINFO2); break; |
||
680 | case MGA_2164: |
||
681 | case MGA_1064: |
||
682 | case MGA_1164: default_pins2(PMINFO2); break; |
||
683 | case MGA_G100: |
||
684 | case MGA_G200: default_pins3(PMINFO2); break; |
||
685 | case MGA_G400: default_pins4(PMINFO2); break; |
||
686 | case MGA_G450: |
||
687 | case MGA_G550: default_pins5(PMINFO2); break; |
||
688 | } |
||
689 | if (!bd->bios_valid) { |
||
690 | printk(KERN_INFO "matroxfb: Your Matrox device does not have BIOS\n"); |
||
691 | return -1; |
||
692 | } |
||
693 | if (bd->pins_len < 64) { |
||
694 | printk(KERN_INFO "matroxfb: BIOS on your Matrox device does not contain powerup info\n"); |
||
695 | return -1; |
||
696 | } |
||
697 | if (bd->pins[0] == 0x2E && bd->pins[1] == 0x41) { |
||
698 | pins_version = bd->pins[5]; |
||
699 | if (pins_version < 2 || pins_version > 5) { |
||
700 | printk(KERN_INFO "matroxfb: Unknown version (%u) of powerup info\n", pins_version); |
||
701 | return -1; |
||
702 | } |
||
703 | } else { |
||
704 | pins_version = 1; |
||
705 | } |
||
706 | if (bd->pins_len != pinslen[pins_version - 1]) { |
||
707 | printk(KERN_INFO "matroxfb: Invalid powerup info\n"); |
||
708 | return -1; |
||
709 | } |
||
710 | switch (pins_version) { |
||
711 | case 1: |
||
712 | return parse_pins1(PMINFO bd); |
||
713 | case 2: |
||
714 | return parse_pins2(PMINFO bd); |
||
715 | case 3: |
||
716 | return parse_pins3(PMINFO bd); |
||
717 | case 4: |
||
718 | return parse_pins4(PMINFO bd); |
||
719 | case 5: |
||
720 | return parse_pins5(PMINFO bd); |
||
721 | default: |
||
722 | printk(KERN_DEBUG "matroxfb: Powerup info version %u is not yet supported\n", pins_version); |
||
723 | return -1; |
||
724 | } |
||
725 | } |
||
726 | |||
727 | void matroxfb_read_pins(WPMINFO2) { |
||
728 | u32 opt; |
||
729 | u32 biosbase; |
||
730 | u32 fbbase; |
||
731 | struct pci_dev* pdev = ACCESS_FBINFO(pcidev); |
||
732 | |||
733 | memset(&ACCESS_FBINFO(bios), 0, sizeof(ACCESS_FBINFO(bios))); |
||
734 | pci_read_config_dword(pdev, PCI_OPTION_REG, &opt); |
||
735 | pci_write_config_dword(pdev, PCI_OPTION_REG, opt | PCI_OPTION_ENABLE_ROM); |
||
736 | pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &biosbase); |
||
737 | pci_read_config_dword(pdev, ACCESS_FBINFO(devflags.fbResource), &fbbase); |
||
738 | pci_write_config_dword(pdev, PCI_ROM_ADDRESS, (fbbase & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE); |
||
739 | parse_bios(vaddr_va(ACCESS_FBINFO(video).vbase), &ACCESS_FBINFO(bios)); |
||
740 | pci_write_config_dword(pdev, PCI_ROM_ADDRESS, biosbase); |
||
741 | pci_write_config_dword(pdev, PCI_OPTION_REG, opt); |
||
742 | #ifdef CONFIG_X86 |
||
743 | if (!ACCESS_FBINFO(bios).bios_valid) { |
||
744 | unsigned char* b; |
||
745 | |||
746 | b = ioremap(0x000C0000, 65536); |
||
747 | if (!b) { |
||
748 | printk(KERN_INFO "matroxfb: Unable to map legacy BIOS\n"); |
||
749 | } else { |
||
750 | unsigned int ven = readb(b+0x64+0) | (readb(b+0x64+1) << 8); |
||
751 | unsigned int dev = readb(b+0x64+2) | (readb(b+0x64+3) << 8); |
||
752 | |||
753 | if (ven != pdev->vendor || dev != pdev->device) { |
||
754 | printk(KERN_INFO "matroxfb: Legacy BIOS is for %04X:%04X, while this device is %04X:%04X\n", |
||
755 | ven, dev, pdev->vendor, pdev->device); |
||
756 | } else { |
||
757 | parse_bios(b, &ACCESS_FBINFO(bios)); |
||
758 | } |
||
759 | iounmap(b); |
||
760 | } |
||
761 | } |
||
762 | #endif |
||
763 | matroxfb_set_limits(PMINFO &ACCESS_FBINFO(bios)); |
||
764 | } |
||
765 | |||
766 | EXPORT_SYMBOL(matroxfb_DAC_in); |
||
767 | EXPORT_SYMBOL(matroxfb_DAC_out); |
||
768 | EXPORT_SYMBOL(matroxfb_var2my); |
||
769 | EXPORT_SYMBOL(matroxfb_PLL_calcclock); |
||
770 | #ifndef CONFIG_FB_MATROX_MULTIHEAD |
||
771 | struct matrox_fb_info matroxfb_global_mxinfo; |
||
772 | EXPORT_SYMBOL(matroxfb_global_mxinfo); |
||
773 | #endif |
||
774 | EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */ |
||
775 | EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */ |
||
776 | EXPORT_SYMBOL(matroxfb_read_pins); |
||
777 | |||
778 | MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); |
||
779 | MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards"); |
||
780 | MODULE_LICENSE("GPL"); |