aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/matrox
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/matrox')
-rw-r--r--drivers/video/matrox/Makefile11
-rw-r--r--drivers/video/matrox/g450_pll.c479
-rw-r--r--drivers/video/matrox/g450_pll.h10
-rw-r--r--drivers/video/matrox/i2c-matroxfb.c223
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.c1086
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.h164
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.c739
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.h13
-rw-r--r--drivers/video/matrox/matroxfb_accel.c497
-rw-r--r--drivers/video/matrox/matroxfb_accel.h8
-rw-r--r--drivers/video/matrox/matroxfb_base.c2589
-rw-r--r--drivers/video/matrox/matroxfb_base.h781
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c741
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.h36
-rw-r--r--drivers/video/matrox/matroxfb_g450.c626
-rw-r--r--drivers/video/matrox/matroxfb_g450.h14
-rw-r--r--drivers/video/matrox/matroxfb_maven.c1328
-rw-r--r--drivers/video/matrox/matroxfb_maven.h20
-rw-r--r--drivers/video/matrox/matroxfb_misc.c777
-rw-r--r--drivers/video/matrox/matroxfb_misc.h18
20 files changed, 10160 insertions, 0 deletions
diff --git a/drivers/video/matrox/Makefile b/drivers/video/matrox/Makefile
new file mode 100644
index 000000000000..f9c00ebe2530
--- /dev/null
+++ b/drivers/video/matrox/Makefile
@@ -0,0 +1,11 @@
1# Makefile for the Linux video drivers.
2# 5 Aug 1999, James Simmons, <mailto:jsimmons@edgeglobal.com>
3# Rewritten to use lists instead of if-statements.
4
5# Each configuration option enables a list of files.
6
7my-obj-$(CONFIG_FB_MATROX_G) += g450_pll.o matroxfb_g450.o matroxfb_crtc2.o
8
9obj-$(CONFIG_FB_MATROX) += matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o $(my-obj-y)
10obj-$(CONFIG_FB_MATROX_I2C) += i2c-matroxfb.o
11obj-$(CONFIG_FB_MATROX_MAVEN) += matroxfb_maven.o matroxfb_crtc2.o
diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c
new file mode 100644
index 000000000000..8073a73f6f35
--- /dev/null
+++ b/drivers/video/matrox/g450_pll.c
@@ -0,0 +1,479 @@
1/*
2 *
3 * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
4 *
5 * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
6 *
7 * Portions Copyright (c) 2001 Matrox Graphics Inc.
8 *
9 * Version: 1.64 2002/06/10
10 *
11 * This file is subject to the terms and conditions of the GNU General Public
12 * License. See the file COPYING in the main directory of this archive for
13 * more details.
14 *
15 */
16
17#include "g450_pll.h"
18#include "matroxfb_DAC1064.h"
19
20static inline unsigned int g450_vco2f(unsigned char p, unsigned int fvco) {
21 return (p & 0x40) ? fvco : fvco >> ((p & 3) + 1);
22}
23
24static inline unsigned int g450_f2vco(unsigned char p, unsigned int fin) {
25 return (p & 0x40) ? fin : fin << ((p & 3) + 1);
26}
27
28static unsigned int g450_mnp2vco(CPMINFO unsigned int mnp) {
29 unsigned int m, n;
30
31 m = ((mnp >> 16) & 0x0FF) + 1;
32 n = ((mnp >> 7) & 0x1FE) + 4;
33 return (ACCESS_FBINFO(features).pll.ref_freq * n + (m >> 1)) / m;
34}
35
36unsigned int g450_mnp2f(CPMINFO unsigned int mnp) {
37 return g450_vco2f(mnp, g450_mnp2vco(PMINFO mnp));
38}
39
40static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
41 if (f2 < f1) {
42 f2 = f1 - f2;
43 } else {
44 f2 = f2 - f1;
45 }
46 return f2;
47}
48
49#define NO_MORE_MNP 0x01FFFFFF
50#define G450_MNP_FREQBITS (0xFFFFFF43) /* do not mask high byte so we'll catch NO_MORE_MNP */
51
52static unsigned int g450_nextpll(CPMINFO const struct matrox_pll_limits* pi, unsigned int* fvco, unsigned int mnp) {
53 unsigned int m, n, p;
54 unsigned int tvco = *fvco;
55
56 m = (mnp >> 16) & 0xFF;
57 p = mnp & 0xFF;
58
59 do {
60 if (m == 0 || m == 0xFF) {
61 if (m == 0) {
62 if (p & 0x40) {
63 return NO_MORE_MNP;
64 }
65 if (p & 3) {
66 p--;
67 } else {
68 p = 0x40;
69 }
70 tvco >>= 1;
71 if (tvco < pi->vcomin) {
72 return NO_MORE_MNP;
73 }
74 *fvco = tvco;
75 }
76
77 p &= 0x43;
78 if (tvco < 550000) {
79/* p |= 0x00; */
80 } else if (tvco < 700000) {
81 p |= 0x08;
82 } else if (tvco < 1000000) {
83 p |= 0x10;
84 } else if (tvco < 1150000) {
85 p |= 0x18;
86 } else {
87 p |= 0x20;
88 }
89 m = 9;
90 } else {
91 m--;
92 }
93 n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
94 } while (n < 0x03 || n > 0x7A);
95 return (m << 16) | (n << 8) | p;
96}
97
98static unsigned int g450_firstpll(CPMINFO const struct matrox_pll_limits* pi, unsigned int* vco, unsigned int fout) {
99 unsigned int p;
100 unsigned int vcomax;
101
102 vcomax = pi->vcomax;
103 if (fout > (vcomax / 2)) {
104 if (fout > vcomax) {
105 *vco = vcomax;
106 } else {
107 *vco = fout;
108 }
109 p = 0x40;
110 } else {
111 unsigned int tvco;
112
113 p = 3;
114 tvco = g450_f2vco(p, fout);
115 while (p && (tvco > vcomax)) {
116 p--;
117 tvco >>= 1;
118 }
119 if (tvco < pi->vcomin) {
120 tvco = pi->vcomin;
121 }
122 *vco = tvco;
123 }
124 return g450_nextpll(PMINFO pi, vco, 0xFF0000 | p);
125}
126
127static inline unsigned int g450_setpll(CPMINFO unsigned int mnp, unsigned int pll) {
128 switch (pll) {
129 case M_PIXEL_PLL_A:
130 matroxfb_DAC_out(PMINFO M1064_XPIXPLLAM, mnp >> 16);
131 matroxfb_DAC_out(PMINFO M1064_XPIXPLLAN, mnp >> 8);
132 matroxfb_DAC_out(PMINFO M1064_XPIXPLLAP, mnp);
133 return M1064_XPIXPLLSTAT;
134
135 case M_PIXEL_PLL_B:
136 matroxfb_DAC_out(PMINFO M1064_XPIXPLLBM, mnp >> 16);
137 matroxfb_DAC_out(PMINFO M1064_XPIXPLLBN, mnp >> 8);
138 matroxfb_DAC_out(PMINFO M1064_XPIXPLLBP, mnp);
139 return M1064_XPIXPLLSTAT;
140
141 case M_PIXEL_PLL_C:
142 matroxfb_DAC_out(PMINFO M1064_XPIXPLLCM, mnp >> 16);
143 matroxfb_DAC_out(PMINFO M1064_XPIXPLLCN, mnp >> 8);
144 matroxfb_DAC_out(PMINFO M1064_XPIXPLLCP, mnp);
145 return M1064_XPIXPLLSTAT;
146
147 case M_SYSTEM_PLL:
148 matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLM, mnp >> 16);
149 matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLN, mnp >> 8);
150 matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLP, mnp);
151 return DAC1064_XSYSPLLSTAT;
152
153 case M_VIDEO_PLL:
154 matroxfb_DAC_out(PMINFO M1064_XVIDPLLM, mnp >> 16);
155 matroxfb_DAC_out(PMINFO M1064_XVIDPLLN, mnp >> 8);
156 matroxfb_DAC_out(PMINFO M1064_XVIDPLLP, mnp);
157 return M1064_XVIDPLLSTAT;
158 }
159 return 0;
160}
161
162static inline unsigned int g450_cmppll(CPMINFO unsigned int mnp, unsigned int pll) {
163 unsigned char m = mnp >> 16;
164 unsigned char n = mnp >> 8;
165 unsigned char p = mnp;
166
167 switch (pll) {
168 case M_PIXEL_PLL_A:
169 return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLAM) != m ||
170 matroxfb_DAC_in(PMINFO M1064_XPIXPLLAN) != n ||
171 matroxfb_DAC_in(PMINFO M1064_XPIXPLLAP) != p);
172
173 case M_PIXEL_PLL_B:
174 return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLBM) != m ||
175 matroxfb_DAC_in(PMINFO M1064_XPIXPLLBN) != n ||
176 matroxfb_DAC_in(PMINFO M1064_XPIXPLLBP) != p);
177
178 case M_PIXEL_PLL_C:
179 return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM) != m ||
180 matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN) != n ||
181 matroxfb_DAC_in(PMINFO M1064_XPIXPLLCP) != p);
182
183 case M_SYSTEM_PLL:
184 return (matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLM) != m ||
185 matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLN) != n ||
186 matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLP) != p);
187
188 case M_VIDEO_PLL:
189 return (matroxfb_DAC_in(PMINFO M1064_XVIDPLLM) != m ||
190 matroxfb_DAC_in(PMINFO M1064_XVIDPLLN) != n ||
191 matroxfb_DAC_in(PMINFO M1064_XVIDPLLP) != p);
192 }
193 return 1;
194}
195
196static inline int g450_isplllocked(CPMINFO unsigned int regidx) {
197 unsigned int j;
198
199 for (j = 0; j < 1000; j++) {
200 if (matroxfb_DAC_in(PMINFO regidx) & 0x40) {
201 unsigned int r = 0;
202 int i;
203
204 for (i = 0; i < 100; i++) {
205 r += matroxfb_DAC_in(PMINFO regidx) & 0x40;
206 }
207 return r >= (90 * 0x40);
208 }
209 /* udelay(1)... but DAC_in is much slower... */
210 }
211 return 0;
212}
213
214static int g450_testpll(CPMINFO unsigned int mnp, unsigned int pll) {
215 return g450_isplllocked(PMINFO g450_setpll(PMINFO mnp, pll));
216}
217
218static void updatehwstate_clk(struct matrox_hw_state* hw, unsigned int mnp, unsigned int pll) {
219 switch (pll) {
220 case M_SYSTEM_PLL:
221 hw->DACclk[3] = mnp >> 16;
222 hw->DACclk[4] = mnp >> 8;
223 hw->DACclk[5] = mnp;
224 break;
225 }
226}
227
228void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
229 if (g450_cmppll(PMINFO mnp, pll)) {
230 g450_setpll(PMINFO mnp, pll);
231 }
232}
233
234static inline unsigned int g450_findworkingpll(WPMINFO unsigned int pll, unsigned int* mnparray, unsigned int mnpcount) {
235 unsigned int found = 0;
236 unsigned int idx;
237 unsigned int mnpfound = mnparray[0];
238
239 for (idx = 0; idx < mnpcount; idx++) {
240 unsigned int sarray[3];
241 unsigned int *sptr;
242 {
243 unsigned int mnp;
244
245 sptr = sarray;
246 mnp = mnparray[idx];
247 if (mnp & 0x38) {
248 *sptr++ = mnp - 8;
249 }
250 if ((mnp & 0x38) != 0x38) {
251 *sptr++ = mnp + 8;
252 }
253 *sptr = mnp;
254 }
255 while (sptr >= sarray) {
256 unsigned int mnp = *sptr--;
257
258 if (g450_testpll(PMINFO mnp - 0x0300, pll) &&
259 g450_testpll(PMINFO mnp + 0x0300, pll) &&
260 g450_testpll(PMINFO mnp - 0x0200, pll) &&
261 g450_testpll(PMINFO mnp + 0x0200, pll) &&
262 g450_testpll(PMINFO mnp - 0x0100, pll) &&
263 g450_testpll(PMINFO mnp + 0x0100, pll)) {
264 if (g450_testpll(PMINFO mnp, pll)) {
265 return mnp;
266 }
267 } else if (!found && g450_testpll(PMINFO mnp, pll)) {
268 mnpfound = mnp;
269 found = 1;
270 }
271 }
272 }
273 g450_setpll(PMINFO mnpfound, pll);
274 return mnpfound;
275}
276
277static void g450_addcache(struct matrox_pll_cache* ci, unsigned int mnp_key, unsigned int mnp_value) {
278 if (++ci->valid > ARRAY_SIZE(ci->data)) {
279 ci->valid = ARRAY_SIZE(ci->data);
280 }
281 memmove(ci->data + 1, ci->data, (ci->valid - 1) * sizeof(*ci->data));
282 ci->data[0].mnp_key = mnp_key & G450_MNP_FREQBITS;
283 ci->data[0].mnp_value = mnp_value;
284}
285
286static int g450_checkcache(WPMINFO struct matrox_pll_cache* ci, unsigned int mnp_key) {
287 unsigned int i;
288
289 mnp_key &= G450_MNP_FREQBITS;
290 for (i = 0; i < ci->valid; i++) {
291 if (ci->data[i].mnp_key == mnp_key) {
292 unsigned int mnp;
293
294 mnp = ci->data[i].mnp_value;
295 if (i) {
296 memmove(ci->data + 1, ci->data, i * sizeof(*ci->data));
297 ci->data[0].mnp_key = mnp_key;
298 ci->data[0].mnp_value = mnp;
299 }
300 return mnp;
301 }
302 }
303 return NO_MORE_MNP;
304}
305
306static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
307 unsigned int* mnparray, unsigned int* deltaarray) {
308 unsigned int mnpcount;
309 unsigned int pixel_vco;
310 const struct matrox_pll_limits* pi;
311 struct matrox_pll_cache* ci;
312
313 pixel_vco = 0;
314 switch (pll) {
315 case M_PIXEL_PLL_A:
316 case M_PIXEL_PLL_B:
317 case M_PIXEL_PLL_C:
318 {
319 u_int8_t tmp;
320 unsigned long flags;
321
322 matroxfb_DAC_lock_irqsave(flags);
323 tmp = matroxfb_DAC_in(PMINFO M1064_XPIXCLKCTRL);
324 if (!(tmp & M1064_XPIXCLKCTRL_PLL_UP)) {
325 matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL, tmp | M1064_XPIXCLKCTRL_PLL_UP);
326 }
327 matroxfb_DAC_unlock_irqrestore(flags);
328 }
329 {
330 u_int8_t misc;
331
332 misc = mga_inb(M_MISC_REG_READ) & ~0x0C;
333 switch (pll) {
334 case M_PIXEL_PLL_A:
335 break;
336 case M_PIXEL_PLL_B:
337 misc |= 0x04;
338 break;
339 default:
340 misc |= 0x0C;
341 break;
342 }
343 mga_outb(M_MISC_REG, misc);
344 }
345 pi = &ACCESS_FBINFO(limits.pixel);
346 ci = &ACCESS_FBINFO(cache.pixel);
347 break;
348 case M_SYSTEM_PLL:
349 {
350 u_int32_t opt;
351
352 pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &opt);
353 if (!(opt & 0x20)) {
354 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, opt | 0x20);
355 }
356 }
357 pi = &ACCESS_FBINFO(limits.system);
358 ci = &ACCESS_FBINFO(cache.system);
359 break;
360 case M_VIDEO_PLL:
361 {
362 u_int8_t tmp;
363 unsigned int mnp;
364 unsigned long flags;
365
366 matroxfb_DAC_lock_irqsave(flags);
367 tmp = matroxfb_DAC_in(PMINFO M1064_XPWRCTRL);
368 if (!(tmp & 2)) {
369 matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, tmp | 2);
370 }
371
372 mnp = matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM) << 16;
373 mnp |= matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN) << 8;
374 pixel_vco = g450_mnp2vco(PMINFO mnp);
375 matroxfb_DAC_unlock_irqrestore(flags);
376 }
377 pi = &ACCESS_FBINFO(limits.video);
378 ci = &ACCESS_FBINFO(cache.video);
379 break;
380 default:
381 return -EINVAL;
382 }
383
384 mnpcount = 0;
385 {
386 unsigned int mnp;
387 unsigned int xvco;
388
389 for(mnp = g450_firstpll(PMINFO pi, &xvco, fout); mnp != NO_MORE_MNP; mnp = g450_nextpll(PMINFO pi, &xvco, mnp)) {
390 unsigned int idx;
391 unsigned int vco;
392 unsigned int delta;
393
394 vco = g450_mnp2vco(PMINFO mnp);
395#if 0
396 if (pll == M_VIDEO_PLL) {
397 unsigned int big, small;
398
399 if (vco < pixel_vco) {
400 small = vco;
401 big = pixel_vco;
402 } else {
403 small = pixel_vco;
404 big = vco;
405 }
406 while (big > small) {
407 big >>= 1;
408 }
409 if (big == small) {
410 continue;
411 }
412 }
413#endif
414 delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
415 for (idx = mnpcount; idx > 0; idx--) {
416 /* == is important; due to nextpll algorithm we get
417 sorted equally good frequencies from lower VCO
418 frequency to higher - with <= lowest wins, while
419 with < highest one wins */
420 if (delta <= deltaarray[idx-1]) {
421 mnparray[idx] = mnparray[idx-1];
422 deltaarray[idx] = deltaarray[idx-1];
423 } else {
424 break;
425 }
426 }
427 mnparray[idx] = mnp;
428 deltaarray[idx] = delta;
429 mnpcount++;
430 }
431 }
432 /* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
433 if (!mnpcount) {
434 return -EBUSY;
435 }
436 {
437 unsigned long flags;
438 unsigned int mnp;
439
440 matroxfb_DAC_lock_irqsave(flags);
441 mnp = g450_checkcache(PMINFO ci, mnparray[0]);
442 if (mnp != NO_MORE_MNP) {
443 matroxfb_g450_setpll_cond(PMINFO mnp, pll);
444 } else {
445 mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount);
446 g450_addcache(ci, mnparray[0], mnp);
447 }
448 updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll);
449 matroxfb_DAC_unlock_irqrestore(flags);
450 return mnp;
451 }
452}
453
454/* It must be greater than number of possible PLL values.
455 * Currently there is 5(p) * 10(m) = 50 possible values. */
456#define MNP_TABLE_SIZE 64
457
458int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll) {
459 unsigned int* arr;
460
461 arr = kmalloc(sizeof(*arr) * MNP_TABLE_SIZE * 2, GFP_KERNEL);
462 if (arr) {
463 int r;
464
465 r = __g450_setclk(PMINFO fout, pll, arr, arr + MNP_TABLE_SIZE);
466 kfree(arr);
467 return r;
468 }
469 return -ENOMEM;
470}
471
472EXPORT_SYMBOL(matroxfb_g450_setclk);
473EXPORT_SYMBOL(g450_mnp2f);
474EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
475
476MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
477MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
478
479MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/g450_pll.h b/drivers/video/matrox/g450_pll.h
new file mode 100644
index 000000000000..c17ed74501e9
--- /dev/null
+++ b/drivers/video/matrox/g450_pll.h
@@ -0,0 +1,10 @@
1#ifndef __G450_PLL_H__
2#define __G450_PLL_H__
3
4#include "matroxfb_base.h"
5
6int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll);
7unsigned int g450_mnp2f(CPMINFO unsigned int mnp);
8void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll);
9
10#endif /* __G450_PLL_H__ */
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
new file mode 100644
index 000000000000..57abbae5520f
--- /dev/null
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -0,0 +1,223 @@
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 * Version: 1.64 2002/06/10
8 *
9 * See matroxfb_base.c for contributors.
10 *
11 */
12
13#include "matroxfb_base.h"
14#include "matroxfb_maven.h"
15#include <linux/i2c.h>
16#include <linux/i2c-algo-bit.h>
17
18/* MGA-TVO I2C for G200, G400 */
19#define MAT_CLK 0x20
20#define MAT_DATA 0x10
21/* primary head DDC for Mystique(?), G100, G200, G400 */
22#define DDC1_CLK 0x08
23#define DDC1_DATA 0x02
24/* primary head DDC for Millennium, Millennium II */
25#define DDC1B_CLK 0x10
26#define DDC1B_DATA 0x04
27/* secondary head DDC for G400 */
28#define DDC2_CLK 0x04
29#define DDC2_DATA 0x01
30
31/******************************************************/
32
33struct matroxfb_dh_maven_info {
34 struct i2c_bit_adapter maven;
35 struct i2c_bit_adapter ddc1;
36 struct i2c_bit_adapter ddc2;
37};
38
39static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
40 unsigned long flags;
41 int v;
42
43 matroxfb_DAC_lock_irqsave(flags);
44 v = matroxfb_DAC_in(PMINFO DAC_XGENIODATA);
45 matroxfb_DAC_unlock_irqrestore(flags);
46 return v;
47}
48
49static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
50 unsigned long flags;
51 int v;
52
53 matroxfb_DAC_lock_irqsave(flags);
54 v = (matroxfb_DAC_in(PMINFO DAC_XGENIOCTRL) & mask) | val;
55 matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, v);
56 /* We must reset GENIODATA very often... XFree plays with this register */
57 matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0x00);
58 matroxfb_DAC_unlock_irqrestore(flags);
59}
60
61/* software I2C functions */
62static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
63 if (state)
64 state = 0;
65 else
66 state = mask;
67 matroxfb_set_gpio(minfo, ~mask, state);
68}
69
70static void matroxfb_gpio_setsda(void* data, int state) {
71 struct i2c_bit_adapter* b = data;
72 matroxfb_i2c_set(b->minfo, b->mask.data, state);
73}
74
75static void matroxfb_gpio_setscl(void* data, int state) {
76 struct i2c_bit_adapter* b = data;
77 matroxfb_i2c_set(b->minfo, b->mask.clock, state);
78}
79
80static int matroxfb_gpio_getsda(void* data) {
81 struct i2c_bit_adapter* b = data;
82 return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0;
83}
84
85static int matroxfb_gpio_getscl(void* data) {
86 struct i2c_bit_adapter* b = data;
87 return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0;
88}
89
90static struct i2c_adapter matrox_i2c_adapter_template =
91{
92 .owner = THIS_MODULE,
93 .id = I2C_HW_B_G400,
94};
95
96static struct i2c_algo_bit_data matrox_i2c_algo_template =
97{
98 NULL,
99 matroxfb_gpio_setsda,
100 matroxfb_gpio_setscl,
101 matroxfb_gpio_getsda,
102 matroxfb_gpio_getscl,
103 10, 10, 100,
104};
105
106static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
107 unsigned int data, unsigned int clock, const char* name) {
108 int err;
109
110 b->minfo = minfo;
111 b->mask.data = data;
112 b->mask.clock = clock;
113 b->adapter = matrox_i2c_adapter_template;
114 snprintf(b->adapter.name, I2C_NAME_SIZE, name,
115 minfo->fbcon.node);
116 i2c_set_adapdata(&b->adapter, b);
117 b->adapter.algo_data = &b->bac;
118 b->bac = matrox_i2c_algo_template;
119 b->bac.data = b;
120 err = i2c_bit_add_bus(&b->adapter);
121 b->initialized = !err;
122 return err;
123}
124
125static void i2c_bit_bus_del(struct i2c_bit_adapter* b) {
126 if (b->initialized) {
127 i2c_bit_del_bus(&b->adapter);
128 b->initialized = 0;
129 }
130}
131
132static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) {
133 i2c_bit_bus_del(&minfo2->maven);
134}
135
136static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) {
137 i2c_bit_bus_del(&minfo2->ddc1);
138}
139
140static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) {
141 i2c_bit_bus_del(&minfo2->ddc2);
142}
143
144static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
145 int err;
146 unsigned long flags;
147 struct matroxfb_dh_maven_info* m2info;
148
149 m2info = (struct matroxfb_dh_maven_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
150 if (!m2info)
151 return NULL;
152
153 matroxfb_DAC_lock_irqsave(flags);
154 matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0xFF);
155 matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0x00);
156 matroxfb_DAC_unlock_irqrestore(flags);
157
158 memset(m2info, 0, sizeof(*m2info));
159
160 switch (ACCESS_FBINFO(chip)) {
161 case MGA_2064:
162 case MGA_2164:
163 err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0");
164 break;
165 default:
166 err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0");
167 break;
168 }
169 if (err)
170 goto fail_ddc1;
171 if (ACCESS_FBINFO(devflags.dualhead)) {
172 err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1");
173 if (err == -ENODEV) {
174 printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n");
175 } else if (err)
176 printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
177 /* Register maven bus even on G450/G550 */
178 err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, "MAVEN:fb%u");
179 if (err)
180 printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
181 }
182 return m2info;
183fail_ddc1:;
184 kfree(m2info);
185 printk(KERN_ERR "i2c-matroxfb: Could not register primary adapter DDC bus.\n");
186 return NULL;
187}
188
189static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) {
190 struct matroxfb_dh_maven_info* m2info = data;
191
192 i2c_maven_done(m2info);
193 i2c_ddc2_done(m2info);
194 i2c_ddc1_done(m2info);
195 kfree(m2info);
196}
197
198static struct matroxfb_driver i2c_matroxfb = {
199 .node = LIST_HEAD_INIT(i2c_matroxfb.node),
200 .name = "i2c-matroxfb",
201 .probe = i2c_matroxfb_probe,
202 .remove = i2c_matroxfb_remove,
203};
204
205static int __init i2c_matroxfb_init(void) {
206 if (matroxfb_register_driver(&i2c_matroxfb)) {
207 printk(KERN_ERR "i2c-matroxfb: failed to register driver\n");
208 return -ENXIO;
209 }
210 return 0;
211}
212
213static void __exit i2c_matroxfb_exit(void) {
214 matroxfb_unregister_driver(&i2c_matroxfb);
215}
216
217MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
218MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards");
219
220module_init(i2c_matroxfb_init);
221module_exit(i2c_matroxfb_exit);
222/* no __setup required */
223MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c
new file mode 100644
index 000000000000..149680f8bcf0
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_DAC1064.c
@@ -0,0 +1,1086 @@
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
15/* make checkconfig does not walk through include tree :-( */
16#include <linux/config.h>
17
18#include "matroxfb_DAC1064.h"
19#include "matroxfb_misc.h"
20#include "matroxfb_accel.h"
21#include "g450_pll.h"
22#include <linux/matroxfb.h>
23
24#ifdef NEED_DAC1064
25#define outDAC1064 matroxfb_DAC_out
26#define inDAC1064 matroxfb_DAC_in
27
28#define DAC1064_OPT_SCLK_PCI 0x00
29#define DAC1064_OPT_SCLK_PLL 0x01
30#define DAC1064_OPT_SCLK_EXT 0x02
31#define DAC1064_OPT_SCLK_MASK 0x03
32#define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */
33#define DAC1064_OPT_GDIV3 0x00
34#define DAC1064_OPT_MDIV1 0x08
35#define DAC1064_OPT_MDIV2 0x00
36#define DAC1064_OPT_RESERVED 0x10
37
38static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
39 unsigned int fvco;
40 unsigned int p;
41
42 DBG(__FUNCTION__)
43
44 /* only for devices older than G450 */
45
46 fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
47
48 p = (1 << p) - 1;
49 if (fvco <= 100000)
50 ;
51 else if (fvco <= 140000)
52 p |= 0x08;
53 else if (fvco <= 180000)
54 p |= 0x10;
55 else
56 p |= 0x18;
57 *post = p;
58}
59
60/* they must be in POS order */
61static const unsigned char MGA1064_DAC_regs[] = {
62 M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
63 M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
64 M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
65 M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE,
66 DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL,
67 M1064_XMISCCTRL,
68 M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST,
69 M1064_XCRCBITSEL,
70 M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
71
72static const unsigned char MGA1064_DAC[] = {
73 0x00, 0x00, M1064_XCURCTRL_DIS,
74 0x00, 0x00, 0x00, /* black */
75 0xFF, 0xFF, 0xFF, /* white */
76 0xFF, 0x00, 0x00, /* red */
77 0x00, 0,
78 M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL,
79 M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN,
80 M1064_XMISCCTRL_DAC_8BIT,
81 0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN,
82 0x00,
83 0x00, 0x00, 0xFF, 0xFF};
84
85static void DAC1064_setpclk(WPMINFO unsigned long fout) {
86 unsigned int m, n, p;
87
88 DBG(__FUNCTION__)
89
90 DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
91 ACCESS_FBINFO(hw).DACclk[0] = m;
92 ACCESS_FBINFO(hw).DACclk[1] = n;
93 ACCESS_FBINFO(hw).DACclk[2] = p;
94}
95
96static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) {
97 u_int32_t mx;
98 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
99
100 DBG(__FUNCTION__)
101
102 if (ACCESS_FBINFO(devflags.noinit)) {
103 /* read MCLK and give up... */
104 hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
105 hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
106 hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
107 return;
108 }
109 mx = hw->MXoptionReg | 0x00000004;
110 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
111 mx &= ~0x000000BB;
112 if (oscinfo & DAC1064_OPT_GDIV1)
113 mx |= 0x00000008;
114 if (oscinfo & DAC1064_OPT_MDIV1)
115 mx |= 0x00000010;
116 if (oscinfo & DAC1064_OPT_RESERVED)
117 mx |= 0x00000080;
118 if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
119 /* select PCI clock until we have setup oscilator... */
120 int clk;
121 unsigned int m, n, p;
122
123 /* powerup system PLL, select PCI clock */
124 mx |= 0x00000020;
125 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
126 mx &= ~0x00000004;
127 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
128
129 /* !!! you must not access device if MCLK is not running !!!
130 Doing so cause immediate PCI lockup :-( Maybe they should
131 generate ABORT or I/O (parity...) error and Linux should
132 recover from this... (kill driver/process). But world is not
133 perfect... */
134 /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
135 select PLL... because of PLL can be stopped at this time) */
136 DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
137 outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m);
138 outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n);
139 outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p);
140 for (clk = 65536; clk; --clk) {
141 if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
142 break;
143 }
144 if (!clk)
145 printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
146 /* select PLL */
147 mx |= 0x00000005;
148 } else {
149 /* select specified system clock source */
150 mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
151 }
152 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
153 mx &= ~0x00000004;
154 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
155 hw->MXoptionReg = mx;
156}
157
158#ifdef CONFIG_FB_MATROX_G
159static void g450_set_plls(WPMINFO2) {
160 u_int32_t c2_ctl;
161 unsigned int pxc;
162 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
163 int pixelmnp;
164 int videomnp;
165
166 c2_ctl = hw->crtc2.ctl & ~0x4007; /* Clear PLL + enable for CRTC2 */
167 c2_ctl |= 0x0001; /* Enable CRTC2 */
168 hw->DACreg[POS1064_XPWRCTRL] &= ~0x02; /* Stop VIDEO PLL */
169 pixelmnp = ACCESS_FBINFO(crtc1).mnp;
170 videomnp = ACCESS_FBINFO(crtc2).mnp;
171 if (videomnp < 0) {
172 c2_ctl &= ~0x0001; /* Disable CRTC2 */
173 hw->DACreg[POS1064_XPWRCTRL] &= ~0x10; /* Powerdown CRTC2 */
174 } else if (ACCESS_FBINFO(crtc2).pixclock == ACCESS_FBINFO(features).pll.ref_freq) {
175 c2_ctl |= 0x4002; /* Use reference directly */
176 } else if (videomnp == pixelmnp) {
177 c2_ctl |= 0x0004; /* Use pixel PLL */
178 } else {
179 if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) {
180 /* PIXEL and VIDEO PLL must not use same frequency. We modify N
181 of PIXEL PLL in such case because of VIDEO PLL may be source
182 of TVO clocks, and chroma subcarrier is derived from its
183 pixel clocks */
184 pixelmnp += 0x000100;
185 }
186 c2_ctl |= 0x0006; /* Use video PLL */
187 hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
188
189 outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
190 matroxfb_g450_setpll_cond(PMINFO videomnp, M_VIDEO_PLL);
191 }
192
193 hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
194 if (pixelmnp >= 0) {
195 hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
196
197 outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
198 matroxfb_g450_setpll_cond(PMINFO pixelmnp, M_PIXEL_PLL_C);
199 }
200 if (c2_ctl != hw->crtc2.ctl) {
201 hw->crtc2.ctl = c2_ctl;
202 mga_outl(0x3C10, c2_ctl);
203 }
204
205 pxc = ACCESS_FBINFO(crtc1).pixclock;
206 if (pxc == 0 || ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC2) {
207 pxc = ACCESS_FBINFO(crtc2).pixclock;
208 }
209 if (ACCESS_FBINFO(chip) == MGA_G550) {
210 if (pxc < 45000) {
211 hw->DACreg[POS1064_XPANMODE] = 0x00; /* 0-50 */
212 } else if (pxc < 55000) {
213 hw->DACreg[POS1064_XPANMODE] = 0x08; /* 34-62 */
214 } else if (pxc < 70000) {
215 hw->DACreg[POS1064_XPANMODE] = 0x10; /* 42-78 */
216 } else if (pxc < 85000) {
217 hw->DACreg[POS1064_XPANMODE] = 0x18; /* 62-92 */
218 } else if (pxc < 100000) {
219 hw->DACreg[POS1064_XPANMODE] = 0x20; /* 74-108 */
220 } else if (pxc < 115000) {
221 hw->DACreg[POS1064_XPANMODE] = 0x28; /* 94-122 */
222 } else if (pxc < 125000) {
223 hw->DACreg[POS1064_XPANMODE] = 0x30; /* 108-132 */
224 } else {
225 hw->DACreg[POS1064_XPANMODE] = 0x38; /* 120-168 */
226 }
227 } else {
228 /* G450 */
229 if (pxc < 45000) {
230 hw->DACreg[POS1064_XPANMODE] = 0x00; /* 0-54 */
231 } else if (pxc < 65000) {
232 hw->DACreg[POS1064_XPANMODE] = 0x08; /* 38-70 */
233 } else if (pxc < 85000) {
234 hw->DACreg[POS1064_XPANMODE] = 0x10; /* 56-96 */
235 } else if (pxc < 105000) {
236 hw->DACreg[POS1064_XPANMODE] = 0x18; /* 80-114 */
237 } else if (pxc < 135000) {
238 hw->DACreg[POS1064_XPANMODE] = 0x20; /* 102-144 */
239 } else if (pxc < 160000) {
240 hw->DACreg[POS1064_XPANMODE] = 0x28; /* 132-166 */
241 } else if (pxc < 175000) {
242 hw->DACreg[POS1064_XPANMODE] = 0x30; /* 154-182 */
243 } else {
244 hw->DACreg[POS1064_XPANMODE] = 0x38; /* 170-204 */
245 }
246 }
247}
248#endif
249
250void DAC1064_global_init(WPMINFO2) {
251 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
252
253 hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
254 hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
255 hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
256#ifdef CONFIG_FB_MATROX_G
257 if (ACCESS_FBINFO(devflags.g450dac)) {
258 hw->DACreg[POS1064_XPWRCTRL] = 0x1F; /* powerup everything */
259 hw->DACreg[POS1064_XOUTPUTCONN] = 0x00; /* disable outputs */
260 hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
261 switch (ACCESS_FBINFO(outputs[0]).src) {
262 case MATROXFB_SRC_CRTC1:
263 case MATROXFB_SRC_CRTC2:
264 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01; /* enable output; CRTC1/2 selection is in CRTC2 ctl */
265 break;
266 case MATROXFB_SRC_NONE:
267 hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN;
268 break;
269 }
270 switch (ACCESS_FBINFO(outputs[1]).src) {
271 case MATROXFB_SRC_CRTC1:
272 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04;
273 break;
274 case MATROXFB_SRC_CRTC2:
275 if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_MONITOR) {
276 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08;
277 } else {
278 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C;
279 }
280 break;
281 case MATROXFB_SRC_NONE:
282 hw->DACreg[POS1064_XPWRCTRL] &= ~0x01; /* Poweroff DAC2 */
283 break;
284 }
285 switch (ACCESS_FBINFO(outputs[2]).src) {
286 case MATROXFB_SRC_CRTC1:
287 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20;
288 break;
289 case MATROXFB_SRC_CRTC2:
290 hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40;
291 break;
292 case MATROXFB_SRC_NONE:
293#if 0
294 /* HELP! If we boot without DFP connected to DVI, we can
295 poweroff TMDS. But if we boot with DFP connected,
296 TMDS generated clocks are used instead of ALL pixclocks
297 available... If someone knows which register
298 handles it, please reveal this secret to me... */
299 hw->DACreg[POS1064_XPWRCTRL] &= ~0x04; /* Poweroff TMDS */
300#endif
301 break;
302 }
303 /* Now set timming related variables... */
304 g450_set_plls(PMINFO2);
305 } else
306#endif
307 {
308 if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) {
309 hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
310 hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
311 } else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
312 hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
313 } else if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1)
314 hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
315 else
316 hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
317
318 if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE)
319 hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
320 }
321}
322
323void DAC1064_global_restore(WPMINFO2) {
324 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
325
326 outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
327 outDAC1064(PMINFO M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]);
328 if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
329 outDAC1064(PMINFO 0x20, 0x04);
330 outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type));
331 if (ACCESS_FBINFO(devflags.g450dac)) {
332 outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);
333 outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
334 outDAC1064(PMINFO M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
335 outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]);
336 }
337 }
338}
339
340static int DAC1064_init_1(WPMINFO struct my_timming* m) {
341 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
342
343 DBG(__FUNCTION__)
344
345 memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
346 switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
347 /* case 4: not supported by MGA1064 DAC */
348 case 8:
349 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
350 break;
351 case 16:
352 if (ACCESS_FBINFO(fbcon).var.green.length == 5)
353 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
354 else
355 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
356 break;
357 case 24:
358 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
359 break;
360 case 32:
361 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
362 break;
363 default:
364 return 1; /* unsupported depth */
365 }
366 hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
367 hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
368 hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
369 hw->DACreg[POS1064_XCURADDL] = 0;
370 hw->DACreg[POS1064_XCURADDH] = 0;
371
372 DAC1064_global_init(PMINFO2);
373 return 0;
374}
375
376static int DAC1064_init_2(WPMINFO struct my_timming* m) {
377 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
378
379 DBG(__FUNCTION__)
380
381 if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) { /* 256 entries */
382 int i;
383
384 for (i = 0; i < 256; i++) {
385 hw->DACpal[i * 3 + 0] = i;
386 hw->DACpal[i * 3 + 1] = i;
387 hw->DACpal[i * 3 + 2] = i;
388 }
389 } else if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 8) {
390 if (ACCESS_FBINFO(fbcon).var.green.length == 5) { /* 0..31, 128..159 */
391 int i;
392
393 for (i = 0; i < 32; i++) {
394 /* with p15 == 0 */
395 hw->DACpal[i * 3 + 0] = i << 3;
396 hw->DACpal[i * 3 + 1] = i << 3;
397 hw->DACpal[i * 3 + 2] = i << 3;
398 /* with p15 == 1 */
399 hw->DACpal[(i + 128) * 3 + 0] = i << 3;
400 hw->DACpal[(i + 128) * 3 + 1] = i << 3;
401 hw->DACpal[(i + 128) * 3 + 2] = i << 3;
402 }
403 } else {
404 int i;
405
406 for (i = 0; i < 64; i++) { /* 0..63 */
407 hw->DACpal[i * 3 + 0] = i << 3;
408 hw->DACpal[i * 3 + 1] = i << 2;
409 hw->DACpal[i * 3 + 2] = i << 3;
410 }
411 }
412 } else {
413 memset(hw->DACpal, 0, 768);
414 }
415 return 0;
416}
417
418static void DAC1064_restore_1(WPMINFO2) {
419 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
420
421 CRITFLAGS
422
423 DBG(__FUNCTION__)
424
425 CRITBEGIN
426
427 if ((inDAC1064(PMINFO DAC1064_XSYSPLLM) != hw->DACclk[3]) ||
428 (inDAC1064(PMINFO DAC1064_XSYSPLLN) != hw->DACclk[4]) ||
429 (inDAC1064(PMINFO DAC1064_XSYSPLLP) != hw->DACclk[5])) {
430 outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
431 outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
432 outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
433 }
434 {
435 unsigned int i;
436
437 for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
438 if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL))
439 outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
440 }
441 }
442
443 DAC1064_global_restore(PMINFO2);
444
445 CRITEND
446};
447
448static void DAC1064_restore_2(WPMINFO2) {
449#ifdef DEBUG
450 unsigned int i;
451#endif
452
453 DBG(__FUNCTION__)
454
455#ifdef DEBUG
456 dprintk(KERN_DEBUG "DAC1064regs ");
457 for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
458 dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], ACCESS_FBINFO(hw).DACreg[i]);
459 if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
460 }
461 dprintk("\n" KERN_DEBUG "DAC1064clk ");
462 for (i = 0; i < 6; i++)
463 dprintk("C%02X=%02X ", i, ACCESS_FBINFO(hw).DACclk[i]);
464 dprintk("\n");
465#endif
466}
467
468static int m1064_compute(void* out, struct my_timming* m) {
469#define minfo ((struct matrox_fb_info*)out)
470 {
471 int i;
472 int tmout;
473 CRITFLAGS
474
475 DAC1064_setpclk(PMINFO m->pixclock);
476
477 CRITBEGIN
478
479 for (i = 0; i < 3; i++)
480 outDAC1064(PMINFO M1064_XPIXPLLCM + i, ACCESS_FBINFO(hw).DACclk[i]);
481 for (tmout = 500000; tmout; tmout--) {
482 if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
483 break;
484 udelay(10);
485 };
486
487 CRITEND
488
489 if (!tmout)
490 printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
491 }
492#undef minfo
493 return 0;
494}
495
496static struct matrox_altout m1064 = {
497 .name = "Primary output",
498 .compute = m1064_compute,
499};
500
501#ifdef CONFIG_FB_MATROX_G
502static int g450_compute(void* out, struct my_timming* m) {
503#define minfo ((struct matrox_fb_info*)out)
504 if (m->mnp < 0) {
505 m->mnp = matroxfb_g450_setclk(PMINFO m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
506 if (m->mnp >= 0) {
507 m->pixclock = g450_mnp2f(PMINFO m->mnp);
508 }
509 }
510#undef minfo
511 return 0;
512}
513
514static struct matrox_altout g450out = {
515 .name = "Primary output",
516 .compute = g450_compute,
517};
518#endif
519
520#endif /* NEED_DAC1064 */
521
522#ifdef CONFIG_FB_MATROX_MYSTIQUE
523static int MGA1064_init(WPMINFO struct my_timming* m) {
524 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
525
526 DBG(__FUNCTION__)
527
528 if (DAC1064_init_1(PMINFO m)) return 1;
529 if (matroxfb_vgaHWinit(PMINFO m)) return 1;
530
531 hw->MiscOutReg = 0xCB;
532 if (m->sync & FB_SYNC_HOR_HIGH_ACT)
533 hw->MiscOutReg &= ~0x40;
534 if (m->sync & FB_SYNC_VERT_HIGH_ACT)
535 hw->MiscOutReg &= ~0x80;
536 if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
537 hw->CRTCEXT[3] |= 0x40;
538
539 if (DAC1064_init_2(PMINFO m)) return 1;
540 return 0;
541}
542#endif
543
544#ifdef CONFIG_FB_MATROX_G
545static int MGAG100_init(WPMINFO struct my_timming* m) {
546 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
547
548 DBG(__FUNCTION__)
549
550 if (DAC1064_init_1(PMINFO m)) return 1;
551 hw->MXoptionReg &= ~0x2000;
552 if (matroxfb_vgaHWinit(PMINFO m)) return 1;
553
554 hw->MiscOutReg = 0xEF;
555 if (m->sync & FB_SYNC_HOR_HIGH_ACT)
556 hw->MiscOutReg &= ~0x40;
557 if (m->sync & FB_SYNC_VERT_HIGH_ACT)
558 hw->MiscOutReg &= ~0x80;
559 if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
560 hw->CRTCEXT[3] |= 0x40;
561
562 if (DAC1064_init_2(PMINFO m)) return 1;
563 return 0;
564}
565#endif /* G */
566
567#ifdef CONFIG_FB_MATROX_MYSTIQUE
568static void MGA1064_ramdac_init(WPMINFO2) {
569
570 DBG(__FUNCTION__)
571
572 /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */
573 ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
574 ACCESS_FBINFO(features.pll.ref_freq) = 14318;
575 ACCESS_FBINFO(features.pll.feed_div_min) = 100;
576 ACCESS_FBINFO(features.pll.feed_div_max) = 127;
577 ACCESS_FBINFO(features.pll.in_div_min) = 1;
578 ACCESS_FBINFO(features.pll.in_div_max) = 31;
579 ACCESS_FBINFO(features.pll.post_shift_max) = 3;
580 ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL;
581 /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
582 DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
583}
584#endif
585
586#ifdef CONFIG_FB_MATROX_G
587/* BIOS environ */
588static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
589 /* G100 wants 0x10, G200 SGRAM does not care... */
590#if 0
591static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
592#endif
593
594static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) {
595 int reg;
596 int selClk;
597 int clk;
598
599 DBG(__FUNCTION__)
600
601 outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS |
602 M1064_XPIXCLKCTRL_PLL_UP);
603 switch (flags & 3) {
604 case 0: reg = M1064_XPIXPLLAM; break;
605 case 1: reg = M1064_XPIXPLLBM; break;
606 default: reg = M1064_XPIXPLLCM; break;
607 }
608 outDAC1064(PMINFO reg++, m);
609 outDAC1064(PMINFO reg++, n);
610 outDAC1064(PMINFO reg, p);
611 selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
612 /* there should be flags & 0x03 & case 0/1/else */
613 /* and we should first select source and after that we should wait for PLL */
614 /* and we are waiting for PLL with oscilator disabled... Is it right? */
615 switch (flags & 0x03) {
616 case 0x00: break;
617 case 0x01: selClk |= 4; break;
618 default: selClk |= 0x0C; break;
619 }
620 mga_outb(M_MISC_REG, selClk);
621 for (clk = 500000; clk; clk--) {
622 if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
623 break;
624 udelay(10);
625 };
626 if (!clk)
627 printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
628 selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
629 switch (flags & 0x0C) {
630 case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
631 case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
632 default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
633 }
634 outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk);
635 outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
636}
637
638static void MGAG100_setPixClock(CPMINFO int flags, int freq) {
639 unsigned int m, n, p;
640
641 DBG(__FUNCTION__)
642
643 DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
644 MGAG100_progPixClock(PMINFO flags, m, n, p);
645}
646#endif
647
648#ifdef CONFIG_FB_MATROX_MYSTIQUE
649static int MGA1064_preinit(WPMINFO2) {
650 static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960,
651 1024, 1152, 1280, 1600, 1664, 1920,
652 2048, 0};
653 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
654
655 DBG(__FUNCTION__)
656
657 /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
658 ACCESS_FBINFO(capable.text) = 1;
659 ACCESS_FBINFO(capable.vxres) = vxres_mystique;
660 ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
661
662 ACCESS_FBINFO(outputs[0]).output = &m1064;
663 ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src;
664 ACCESS_FBINFO(outputs[0]).data = MINFO;
665 ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
666
667 if (ACCESS_FBINFO(devflags.noinit))
668 return 0; /* do not modify settings */
669 hw->MXoptionReg &= 0xC0000100;
670 hw->MXoptionReg |= 0x00094E20;
671 if (ACCESS_FBINFO(devflags.novga))
672 hw->MXoptionReg &= ~0x00000100;
673 if (ACCESS_FBINFO(devflags.nobios))
674 hw->MXoptionReg &= ~0x40000000;
675 if (ACCESS_FBINFO(devflags.nopciretry))
676 hw->MXoptionReg |= 0x20000000;
677 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
678 mga_setr(M_SEQ_INDEX, 0x01, 0x20);
679 mga_outl(M_CTLWTST, 0x00000000);
680 udelay(200);
681 mga_outl(M_MACCESS, 0x00008000);
682 udelay(100);
683 mga_outl(M_MACCESS, 0x0000C000);
684 return 0;
685}
686
687static void MGA1064_reset(WPMINFO2) {
688
689 DBG(__FUNCTION__);
690
691 MGA1064_ramdac_init(PMINFO2);
692}
693#endif
694
695#ifdef CONFIG_FB_MATROX_G
696static void g450_mclk_init(WPMINFO2) {
697 /* switch all clocks to PCI source */
698 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4);
699 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION3_REG, ACCESS_FBINFO(values).reg.opt3 & ~0x00300C03);
700 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
701
702 if (((ACCESS_FBINFO(values).reg.opt3 & 0x000003) == 0x000003) ||
703 ((ACCESS_FBINFO(values).reg.opt3 & 0x000C00) == 0x000C00) ||
704 ((ACCESS_FBINFO(values).reg.opt3 & 0x300000) == 0x300000)) {
705 matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.video), M_VIDEO_PLL);
706 } else {
707 unsigned long flags;
708 unsigned int pwr;
709
710 matroxfb_DAC_lock_irqsave(flags);
711 pwr = inDAC1064(PMINFO M1064_XPWRCTRL) & ~0x02;
712 outDAC1064(PMINFO M1064_XPWRCTRL, pwr);
713 matroxfb_DAC_unlock_irqrestore(flags);
714 }
715 matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.system), M_SYSTEM_PLL);
716
717 /* switch clocks to their real PLL source(s) */
718 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4);
719 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION3_REG, ACCESS_FBINFO(values).reg.opt3);
720 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
721
722}
723
724static void g450_memory_init(WPMINFO2) {
725 /* disable memory refresh */
726 ACCESS_FBINFO(hw).MXoptionReg &= ~0x001F8000;
727 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
728
729 /* set memory interface parameters */
730 ACCESS_FBINFO(hw).MXoptionReg &= ~0x00207E00;
731 ACCESS_FBINFO(hw).MXoptionReg |= 0x00207E00 & ACCESS_FBINFO(values).reg.opt;
732 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
733 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, ACCESS_FBINFO(values).reg.opt2);
734
735 mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
736
737 /* first set up memory interface with disabled memory interface clocks */
738 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MEMMISC_REG, ACCESS_FBINFO(values).reg.memmisc & ~0x80000000U);
739 mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
740 mga_outl(M_MACCESS, ACCESS_FBINFO(values).reg.maccess);
741 /* start memory clocks */
742 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MEMMISC_REG, ACCESS_FBINFO(values).reg.memmisc | 0x80000000U);
743
744 udelay(200);
745
746 if (ACCESS_FBINFO(values).memory.ddr && (!ACCESS_FBINFO(values).memory.emrswen || !ACCESS_FBINFO(values).memory.dll)) {
747 mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk & ~0x1000);
748 }
749 mga_outl(M_MACCESS, ACCESS_FBINFO(values).reg.maccess | 0x8000);
750
751 udelay(200);
752
753 ACCESS_FBINFO(hw).MXoptionReg |= 0x001F8000 & ACCESS_FBINFO(values).reg.opt;
754 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
755
756 /* value is written to memory chips only if old != new */
757 mga_outl(M_PLNWT, 0);
758 mga_outl(M_PLNWT, ~0);
759
760 if (ACCESS_FBINFO(values).reg.mctlwtst != ACCESS_FBINFO(values).reg.mctlwtst_core) {
761 mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst_core);
762 }
763
764}
765
766static void g450_preinit(WPMINFO2) {
767 u_int32_t c2ctl;
768 u_int8_t curctl;
769 u_int8_t c1ctl;
770
771 /* ACCESS_FBINFO(hw).MXoptionReg = minfo->values.reg.opt; */
772 ACCESS_FBINFO(hw).MXoptionReg &= 0xC0000100;
773 ACCESS_FBINFO(hw).MXoptionReg |= 0x00000020;
774 if (ACCESS_FBINFO(devflags.novga))
775 ACCESS_FBINFO(hw).MXoptionReg &= ~0x00000100;
776 if (ACCESS_FBINFO(devflags.nobios))
777 ACCESS_FBINFO(hw).MXoptionReg &= ~0x40000000;
778 if (ACCESS_FBINFO(devflags.nopciretry))
779 ACCESS_FBINFO(hw).MXoptionReg |= 0x20000000;
780 ACCESS_FBINFO(hw).MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x03400040;
781 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
782
783 /* Init system clocks */
784
785 /* stop crtc2 */
786 c2ctl = mga_inl(M_C2CTL);
787 mga_outl(M_C2CTL, c2ctl & ~1);
788 /* stop cursor */
789 curctl = inDAC1064(PMINFO M1064_XCURCTRL);
790 outDAC1064(PMINFO M1064_XCURCTRL, 0);
791 /* stop crtc1 */
792 c1ctl = mga_readr(M_SEQ_INDEX, 1);
793 mga_setr(M_SEQ_INDEX, 1, c1ctl | 0x20);
794
795 g450_mclk_init(PMINFO2);
796 g450_memory_init(PMINFO2);
797
798 /* set legacy VGA clock sources for DOSEmu or VMware... */
799 matroxfb_g450_setclk(PMINFO 25175, M_PIXEL_PLL_A);
800 matroxfb_g450_setclk(PMINFO 28322, M_PIXEL_PLL_B);
801
802 /* restore crtc1 */
803 mga_setr(M_SEQ_INDEX, 1, c1ctl);
804
805 /* restore cursor */
806 outDAC1064(PMINFO M1064_XCURCTRL, curctl);
807
808 /* restore crtc2 */
809 mga_outl(M_C2CTL, c2ctl);
810
811 return;
812}
813
814static int MGAG100_preinit(WPMINFO2) {
815 static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960,
816 1024, 1152, 1280, 1600, 1664, 1920,
817 2048, 0};
818 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
819
820 u_int32_t reg50;
821#if 0
822 u_int32_t q;
823#endif
824
825 DBG(__FUNCTION__)
826
827 /* there are some instabilities if in_div > 19 && vco < 61000 */
828 if (ACCESS_FBINFO(devflags.g450dac)) {
829 ACCESS_FBINFO(features.pll.vco_freq_min) = 130000; /* my sample: >118 */
830 } else {
831 ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
832 }
833 if (!ACCESS_FBINFO(features.pll.ref_freq)) {
834 ACCESS_FBINFO(features.pll.ref_freq) = 27000;
835 }
836 ACCESS_FBINFO(features.pll.feed_div_min) = 7;
837 ACCESS_FBINFO(features.pll.feed_div_max) = 127;
838 ACCESS_FBINFO(features.pll.in_div_min) = 1;
839 ACCESS_FBINFO(features.pll.in_div_max) = 31;
840 ACCESS_FBINFO(features.pll.post_shift_max) = 3;
841 ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT;
842 /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
843 ACCESS_FBINFO(capable.text) = 1;
844 ACCESS_FBINFO(capable.vxres) = vxres_g100;
845 ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
846 ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
847 ? ACCESS_FBINFO(devflags.sgram) : 1;
848
849#ifdef CONFIG_FB_MATROX_G
850 if (ACCESS_FBINFO(devflags.g450dac)) {
851 ACCESS_FBINFO(outputs[0]).output = &g450out;
852 } else
853#endif
854 {
855 ACCESS_FBINFO(outputs[0]).output = &m1064;
856 }
857 ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src;
858 ACCESS_FBINFO(outputs[0]).data = MINFO;
859 ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
860
861 if (ACCESS_FBINFO(devflags.g450dac)) {
862 /* we must do this always, BIOS does not do it for us
863 and accelerator dies without it */
864 mga_outl(0x1C0C, 0);
865 }
866 if (ACCESS_FBINFO(devflags.noinit))
867 return 0;
868 if (ACCESS_FBINFO(devflags.g450dac)) {
869 g450_preinit(PMINFO2);
870 return 0;
871 }
872 hw->MXoptionReg &= 0xC0000100;
873 hw->MXoptionReg |= 0x00000020;
874 if (ACCESS_FBINFO(devflags.novga))
875 hw->MXoptionReg &= ~0x00000100;
876 if (ACCESS_FBINFO(devflags.nobios))
877 hw->MXoptionReg &= ~0x40000000;
878 if (ACCESS_FBINFO(devflags.nopciretry))
879 hw->MXoptionReg |= 0x20000000;
880 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
881 DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333);
882
883 if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) {
884 pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, &reg50);
885 reg50 &= ~0x3000;
886 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
887
888 hw->MXoptionReg |= 0x1080;
889 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
890 mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
891 udelay(100);
892 mga_outb(0x1C05, 0x00);
893 mga_outb(0x1C05, 0x80);
894 udelay(100);
895 mga_outb(0x1C05, 0x40);
896 mga_outb(0x1C05, 0xC0);
897 udelay(100);
898 reg50 &= ~0xFF;
899 reg50 |= 0x07;
900 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
901 /* it should help with G100 */
902 mga_outb(M_GRAPHICS_INDEX, 6);
903 mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
904 mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
905 mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
906 mga_writeb(ACCESS_FBINFO(video.vbase), 0x0000, 0xAA);
907 mga_writeb(ACCESS_FBINFO(video.vbase), 0x0800, 0x55);
908 mga_writeb(ACCESS_FBINFO(video.vbase), 0x4000, 0x55);
909#if 0
910 if (mga_readb(ACCESS_FBINFO(video.vbase), 0x0000) != 0xAA) {
911 hw->MXoptionReg &= ~0x1000;
912 }
913#endif
914 hw->MXoptionReg |= 0x00078020;
915 } else if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG200) {
916 pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, &reg50);
917 reg50 &= ~0x3000;
918 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
919
920 if (ACCESS_FBINFO(devflags.memtype) == -1)
921 hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00;
922 else
923 hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
924 if (ACCESS_FBINFO(devflags.sgram))
925 hw->MXoptionReg |= 0x4000;
926 mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
927 mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
928 udelay(200);
929 mga_outl(M_MACCESS, 0x00000000);
930 mga_outl(M_MACCESS, 0x00008000);
931 udelay(100);
932 mga_outw(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
933 hw->MXoptionReg |= 0x00078020;
934 } else {
935 pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, &reg50);
936 reg50 &= ~0x00000100;
937 reg50 |= 0x00000000;
938 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
939
940 if (ACCESS_FBINFO(devflags.memtype) == -1)
941 hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00;
942 else
943 hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
944 if (ACCESS_FBINFO(devflags.sgram))
945 hw->MXoptionReg |= 0x4000;
946 mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
947 mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
948 udelay(200);
949 mga_outl(M_MACCESS, 0x00000000);
950 mga_outl(M_MACCESS, 0x00008000);
951 udelay(100);
952 mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
953 hw->MXoptionReg |= 0x00040020;
954 }
955 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
956 return 0;
957}
958
959static void MGAG100_reset(WPMINFO2) {
960 u_int8_t b;
961 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
962
963 DBG(__FUNCTION__)
964
965 {
966#ifdef G100_BROKEN_IBM_82351
967 u_int32_t d;
968
969 find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
970 pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
971 if (b == ACCESS_FBINFO(pcidev)->bus->number) {
972 pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */
973 pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */
974 pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */
975 pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */
976 }
977#endif
978 if (!ACCESS_FBINFO(devflags.noinit)) {
979 if (x7AF4 & 8) {
980 hw->MXoptionReg |= 0x40; /* FIXME... */
981 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
982 }
983 mga_setr(M_EXTVGA_INDEX, 0x06, 0x50);
984 }
985 }
986 if (ACCESS_FBINFO(devflags.g450dac)) {
987 /* either leave MCLK as is... or they were set in preinit */
988 hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
989 hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
990 hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
991 } else {
992 DAC1064_setmclk(PMINFO DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333);
993 }
994 if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
995 if (ACCESS_FBINFO(devflags.dfp_type) == -1) {
996 ACCESS_FBINFO(devflags.dfp_type) = inDAC1064(PMINFO 0x1F);
997 }
998 }
999 if (ACCESS_FBINFO(devflags.noinit))
1000 return;
1001 if (ACCESS_FBINFO(devflags.g450dac)) {
1002 } else {
1003 MGAG100_setPixClock(PMINFO 4, 25175);
1004 MGAG100_setPixClock(PMINFO 5, 28322);
1005 if (x7AF4 & 0x10) {
1006 b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1;
1007 outDAC1064(PMINFO M1064_XGENIODATA, b);
1008 b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1;
1009 outDAC1064(PMINFO M1064_XGENIOCTRL, b);
1010 }
1011 }
1012}
1013#endif
1014
1015#ifdef CONFIG_FB_MATROX_MYSTIQUE
1016static void MGA1064_restore(WPMINFO2) {
1017 int i;
1018 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
1019
1020 CRITFLAGS
1021
1022 DBG(__FUNCTION__)
1023
1024 CRITBEGIN
1025
1026 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
1027 mga_outb(M_IEN, 0x00);
1028 mga_outb(M_CACHEFLUSH, 0x00);
1029
1030 CRITEND
1031
1032 DAC1064_restore_1(PMINFO2);
1033 matroxfb_vgaHWrestore(PMINFO2);
1034 ACCESS_FBINFO(crtc1.panpos) = -1;
1035 for (i = 0; i < 6; i++)
1036 mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
1037 DAC1064_restore_2(PMINFO2);
1038}
1039#endif
1040
1041#ifdef CONFIG_FB_MATROX_G
1042static void MGAG100_restore(WPMINFO2) {
1043 int i;
1044 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
1045
1046 CRITFLAGS
1047
1048 DBG(__FUNCTION__)
1049
1050 CRITBEGIN
1051
1052 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
1053 CRITEND
1054
1055 DAC1064_restore_1(PMINFO2);
1056 matroxfb_vgaHWrestore(PMINFO2);
1057#ifdef CONFIG_FB_MATROX_32MB
1058 if (ACCESS_FBINFO(devflags.support32MB))
1059 mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
1060#endif
1061 ACCESS_FBINFO(crtc1.panpos) = -1;
1062 for (i = 0; i < 6; i++)
1063 mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
1064 DAC1064_restore_2(PMINFO2);
1065}
1066#endif
1067
1068#ifdef CONFIG_FB_MATROX_MYSTIQUE
1069struct matrox_switch matrox_mystique = {
1070 MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore,
1071};
1072EXPORT_SYMBOL(matrox_mystique);
1073#endif
1074
1075#ifdef CONFIG_FB_MATROX_G
1076struct matrox_switch matrox_G100 = {
1077 MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore,
1078};
1079EXPORT_SYMBOL(matrox_G100);
1080#endif
1081
1082#ifdef NEED_DAC1064
1083EXPORT_SYMBOL(DAC1064_global_init);
1084EXPORT_SYMBOL(DAC1064_global_restore);
1085#endif
1086MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h
new file mode 100644
index 000000000000..a6a470127289
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_DAC1064.h
@@ -0,0 +1,164 @@
1#ifndef __MATROXFB_DAC1064_H__
2#define __MATROXFB_DAC1064_H__
3
4/* make checkconfig does not walk through include tree */
5#include <linux/config.h>
6
7#include "matroxfb_base.h"
8
9#ifdef CONFIG_FB_MATROX_MYSTIQUE
10extern struct matrox_switch matrox_mystique;
11#endif
12#ifdef CONFIG_FB_MATROX_G
13extern struct matrox_switch matrox_G100;
14#endif
15#ifdef NEED_DAC1064
16void DAC1064_global_init(WPMINFO2);
17void DAC1064_global_restore(WPMINFO2);
18#endif
19
20#define M1064_INDEX 0x00
21#define M1064_PALWRADD 0x00
22#define M1064_PALDATA 0x01
23#define M1064_PIXRDMSK 0x02
24#define M1064_PALRDADD 0x03
25#define M1064_X_DATAREG 0x0A
26#define M1064_CURPOSXL 0x0C /* can be accessed as DWORD */
27#define M1064_CURPOSXH 0x0D
28#define M1064_CURPOSYL 0x0E
29#define M1064_CURPOSYH 0x0F
30
31#define M1064_XCURADDL 0x04
32#define M1064_XCURADDH 0x05
33#define M1064_XCURCTRL 0x06
34#define M1064_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */
35#define M1064_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
36#define M1064_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
37#define M1064_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
38#define M1064_XCURCOL0RED 0x08
39#define M1064_XCURCOL0GREEN 0x09
40#define M1064_XCURCOL0BLUE 0x0A
41#define M1064_XCURCOL1RED 0x0C
42#define M1064_XCURCOL1GREEN 0x0D
43#define M1064_XCURCOL1BLUE 0x0E
44#define M1064_XCURCOL2RED 0x10
45#define M1064_XCURCOL2GREEN 0x11
46#define M1064_XCURCOL2BLUE 0x12
47#define DAC1064_XVREFCTRL 0x18
48#define DAC1064_XVREFCTRL_INTERNAL 0x3F
49#define DAC1064_XVREFCTRL_EXTERNAL 0x00
50#define DAC1064_XVREFCTRL_G100_DEFAULT 0x03
51#define M1064_XMULCTRL 0x19
52#define M1064_XMULCTRL_DEPTH_8BPP 0x00 /* 8 bpp paletized */
53#define M1064_XMULCTRL_DEPTH_15BPP_1BPP 0x01 /* 15 bpp paletized + 1 bpp overlay */
54#define M1064_XMULCTRL_DEPTH_16BPP 0x02 /* 16 bpp paletized */
55#define M1064_XMULCTRL_DEPTH_24BPP 0x03 /* 24 bpp paletized */
56#define M1064_XMULCTRL_DEPTH_24BPP_8BPP 0x04 /* 24 bpp direct + 8 bpp overlay paletized */
57#define M1064_XMULCTRL_2G8V16 0x05 /* 15 bpp video direct, half xres, 8bpp paletized */
58#define M1064_XMULCTRL_G16V16 0x06 /* 15 bpp video, 15bpp graphics, one of them paletized */
59#define M1064_XMULCTRL_DEPTH_32BPP 0x07 /* 24 bpp paletized + 8 bpp unused */
60#define M1064_XMULCTRL_GRAPHICS_PALETIZED 0x00
61#define M1064_XMULCTRL_VIDEO_PALETIZED 0x08
62#define M1064_XPIXCLKCTRL 0x1A
63#define M1064_XPIXCLKCTRL_SRC_PCI 0x00
64#define M1064_XPIXCLKCTRL_SRC_PLL 0x01
65#define M1064_XPIXCLKCTRL_SRC_EXT 0x02
66#define M1064_XPIXCLKCTRL_SRC_SYS 0x03 /* G200/G400 */
67#define M1064_XPIXCLKCTRL_SRC_PLL2 0x03 /* G450 */
68#define M1064_XPIXCLKCTRL_SRC_MASK 0x03
69#define M1064_XPIXCLKCTRL_EN 0x00
70#define M1064_XPIXCLKCTRL_DIS 0x04
71#define M1064_XPIXCLKCTRL_PLL_DOWN 0x00
72#define M1064_XPIXCLKCTRL_PLL_UP 0x08
73#define M1064_XGENCTRL 0x1D
74#define M1064_XGENCTRL_VS_0 0x00
75#define M1064_XGENCTRL_VS_1 0x01
76#define M1064_XGENCTRL_ALPHA_DIS 0x00
77#define M1064_XGENCTRL_ALPHA_EN 0x02
78#define M1064_XGENCTRL_BLACK_0IRE 0x00
79#define M1064_XGENCTRL_BLACK_75IRE 0x10
80#define M1064_XGENCTRL_SYNC_ON_GREEN 0x00
81#define M1064_XGENCTRL_NO_SYNC_ON_GREEN 0x20
82#define M1064_XGENCTRL_SYNC_ON_GREEN_MASK 0x20
83#define M1064_XMISCCTRL 0x1E
84#define M1064_XMISCCTRL_DAC_DIS 0x00
85#define M1064_XMISCCTRL_DAC_EN 0x01
86#define M1064_XMISCCTRL_MFC_VGA 0x00
87#define M1064_XMISCCTRL_MFC_MAFC 0x02
88#define M1064_XMISCCTRL_MFC_DIS 0x06
89#define GX00_XMISCCTRL_MFC_MAFC 0x02
90#define GX00_XMISCCTRL_MFC_PANELLINK 0x04
91#define GX00_XMISCCTRL_MFC_DIS 0x06
92#define GX00_XMISCCTRL_MFC_MASK 0x06
93#define M1064_XMISCCTRL_DAC_6BIT 0x00
94#define M1064_XMISCCTRL_DAC_8BIT 0x08
95#define M1064_XMISCCTRL_DAC_WIDTHMASK 0x08
96#define M1064_XMISCCTRL_LUT_DIS 0x00
97#define M1064_XMISCCTRL_LUT_EN 0x10
98#define G400_XMISCCTRL_VDO_MAFC12 0x00
99#define G400_XMISCCTRL_VDO_BYPASS656 0x40
100#define G400_XMISCCTRL_VDO_C2_MAFC12 0x80
101#define G400_XMISCCTRL_VDO_C2_BYPASS656 0xC0
102#define G400_XMISCCTRL_VDO_MASK 0xE0
103#define M1064_XGENIOCTRL 0x2A
104#define M1064_XGENIODATA 0x2B
105#define DAC1064_XSYSPLLM 0x2C
106#define DAC1064_XSYSPLLN 0x2D
107#define DAC1064_XSYSPLLP 0x2E
108#define DAC1064_XSYSPLLSTAT 0x2F
109#define M1064_XZOOMCTRL 0x38
110#define M1064_XZOOMCTRL_1 0x00
111#define M1064_XZOOMCTRL_2 0x01
112#define M1064_XZOOMCTRL_4 0x03
113#define M1064_XSENSETEST 0x3A
114#define M1064_XSENSETEST_BCOMP 0x01
115#define M1064_XSENSETEST_GCOMP 0x02
116#define M1064_XSENSETEST_RCOMP 0x04
117#define M1064_XSENSETEST_PDOWN 0x00
118#define M1064_XSENSETEST_PUP 0x80
119#define M1064_XCRCREML 0x3C
120#define M1064_XCRCREMH 0x3D
121#define M1064_XCRCBITSEL 0x3E
122#define M1064_XCOLKEYMASKL 0x40
123#define M1064_XCOLKEYMASKH 0x41
124#define M1064_XCOLKEYL 0x42
125#define M1064_XCOLKEYH 0x43
126#define M1064_XPIXPLLAM 0x44
127#define M1064_XPIXPLLAN 0x45
128#define M1064_XPIXPLLAP 0x46
129#define M1064_XPIXPLLBM 0x48
130#define M1064_XPIXPLLBN 0x49
131#define M1064_XPIXPLLBP 0x4A
132#define M1064_XPIXPLLCM 0x4C
133#define M1064_XPIXPLLCN 0x4D
134#define M1064_XPIXPLLCP 0x4E
135#define M1064_XPIXPLLSTAT 0x4F
136
137#define M1064_XTVO_IDX 0x87
138#define M1064_XTVO_DATA 0x88
139
140#define M1064_XOUTPUTCONN 0x8A
141#define M1064_XSYNCCTRL 0x8B
142#define M1064_XVIDPLLSTAT 0x8C
143#define M1064_XVIDPLLP 0x8D
144#define M1064_XVIDPLLM 0x8E
145#define M1064_XVIDPLLN 0x8F
146
147#define M1064_XPWRCTRL 0xA0
148
149#define M1064_XPANMODE 0xA2
150
151enum POS1064 {
152 POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL,
153 POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE,
154 POS1064_XCURCOL1RED, POS1064_XCURCOL1GREEN, POS1064_XCURCOL1BLUE,
155 POS1064_XCURCOL2RED, POS1064_XCURCOL2GREEN, POS1064_XCURCOL2BLUE,
156 POS1064_XVREFCTRL, POS1064_XMULCTRL, POS1064_XPIXCLKCTRL, POS1064_XGENCTRL,
157 POS1064_XMISCCTRL,
158 POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST,
159 POS1064_XCRCBITSEL,
160 POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH,
161 POS1064_XOUTPUTCONN, POS1064_XPANMODE, POS1064_XPWRCTRL };
162
163
164#endif /* __MATROXFB_DAC1064_H__ */
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
new file mode 100644
index 000000000000..537ade5d8b21
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_Ti3026.c
@@ -0,0 +1,739 @@
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 * (following author is not in any relation with this code, but his code
69 * is included in this driver)
70 *
71 * Based on framebuffer driver for VBE 2.0 compliant graphic boards
72 * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
73 *
74 * (following author is not in any relation with this code, but his ideas
75 * were used when writting this driver)
76 *
77 * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
78 *
79 */
80
81/* make checkconfig does not verify included files... */
82#include <linux/config.h>
83
84#include "matroxfb_Ti3026.h"
85#include "matroxfb_misc.h"
86#include "matroxfb_accel.h"
87#include <linux/matroxfb.h>
88
89#ifdef CONFIG_FB_MATROX_MILLENIUM
90#define outTi3026 matroxfb_DAC_out
91#define inTi3026 matroxfb_DAC_in
92
93#define TVP3026_INDEX 0x00
94#define TVP3026_PALWRADD 0x00
95#define TVP3026_PALDATA 0x01
96#define TVP3026_PIXRDMSK 0x02
97#define TVP3026_PALRDADD 0x03
98#define TVP3026_CURCOLWRADD 0x04
99#define TVP3026_CLOVERSCAN 0x00
100#define TVP3026_CLCOLOR0 0x01
101#define TVP3026_CLCOLOR1 0x02
102#define TVP3026_CLCOLOR2 0x03
103#define TVP3026_CURCOLDATA 0x05
104#define TVP3026_CURCOLRDADD 0x07
105#define TVP3026_CURCTRL 0x09
106#define TVP3026_X_DATAREG 0x0A
107#define TVP3026_CURRAMDATA 0x0B
108#define TVP3026_CURPOSXL 0x0C
109#define TVP3026_CURPOSXH 0x0D
110#define TVP3026_CURPOSYL 0x0E
111#define TVP3026_CURPOSYH 0x0F
112
113#define TVP3026_XSILICONREV 0x01
114#define TVP3026_XCURCTRL 0x06
115#define TVP3026_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */
116#define TVP3026_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
117#define TVP3026_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
118#define TVP3026_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
119#define TVP3026_XCURCTRL_BLANK2048 0x00
120#define TVP3026_XCURCTRL_BLANK4096 0x10
121#define TVP3026_XCURCTRL_INTERLACED 0x20
122#define TVP3026_XCURCTRL_ODD 0x00 /* ext.signal ODD/\EVEN */
123#define TVP3026_XCURCTRL_EVEN 0x40 /* ext.signal EVEN/\ODD */
124#define TVP3026_XCURCTRL_INDIRECT 0x00
125#define TVP3026_XCURCTRL_DIRECT 0x80
126#define TVP3026_XLATCHCTRL 0x0F
127#define TVP3026_XLATCHCTRL_1_1 0x06
128#define TVP3026_XLATCHCTRL_2_1 0x07
129#define TVP3026_XLATCHCTRL_4_1 0x06
130#define TVP3026_XLATCHCTRL_8_1 0x06
131#define TVP3026_XLATCHCTRL_16_1 0x06
132#define TVP3026A_XLATCHCTRL_4_3 0x06 /* ??? do not understand... but it works... !!! */
133#define TVP3026A_XLATCHCTRL_8_3 0x07
134#define TVP3026B_XLATCHCTRL_4_3 0x08
135#define TVP3026B_XLATCHCTRL_8_3 0x06 /* ??? do not understand... but it works... !!! */
136#define TVP3026_XTRUECOLORCTRL 0x18
137#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL 0x00
138#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP 0x20
139#define TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR 0x80
140#define TVP3026_XTRUECOLORCTRL_TRUECOLOR 0x40 /* paletized */
141#define TVP3026_XTRUECOLORCTRL_DIRECTCOLOR 0x00
142#define TVP3026_XTRUECOLORCTRL_24_ALTERNATE 0x08 /* 5:4/5:2 instead of 4:3/8:3 */
143#define TVP3026_XTRUECOLORCTRL_RGB_888 0x16 /* 4:3/8:3 (or 5:4/5:2) */
144#define TVP3026_XTRUECOLORCTRL_BGR_888 0x17
145#define TVP3026_XTRUECOLORCTRL_ORGB_8888 0x06
146#define TVP3026_XTRUECOLORCTRL_BGRO_8888 0x07
147#define TVP3026_XTRUECOLORCTRL_RGB_565 0x05
148#define TVP3026_XTRUECOLORCTRL_ORGB_1555 0x04
149#define TVP3026_XTRUECOLORCTRL_RGB_664 0x03
150#define TVP3026_XTRUECOLORCTRL_RGBO_4444 0x01
151#define TVP3026_XMUXCTRL 0x19
152#define TVP3026_XMUXCTRL_MEMORY_8BIT 0x01 /* - */
153#define TVP3026_XMUXCTRL_MEMORY_16BIT 0x02 /* - */
154#define TVP3026_XMUXCTRL_MEMORY_32BIT 0x03 /* 2MB RAM, 512K * 4 */
155#define TVP3026_XMUXCTRL_MEMORY_64BIT 0x04 /* >2MB RAM, 512K * 8 & more */
156#define TVP3026_XMUXCTRL_PIXEL_4BIT 0x40 /* L0,H0,L1,H1... */
157#define TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED 0x60 /* H0,L0,H1,L1... */
158#define TVP3026_XMUXCTRL_PIXEL_8BIT 0x48
159#define TVP3026_XMUXCTRL_PIXEL_16BIT 0x50
160#define TVP3026_XMUXCTRL_PIXEL_32BIT 0x58
161#define TVP3026_XMUXCTRL_VGA 0x98 /* VGA MEMORY, 8BIT PIXEL */
162#define TVP3026_XCLKCTRL 0x1A
163#define TVP3026_XCLKCTRL_DIV1 0x00
164#define TVP3026_XCLKCTRL_DIV2 0x10
165#define TVP3026_XCLKCTRL_DIV4 0x20
166#define TVP3026_XCLKCTRL_DIV8 0x30
167#define TVP3026_XCLKCTRL_DIV16 0x40
168#define TVP3026_XCLKCTRL_DIV32 0x50
169#define TVP3026_XCLKCTRL_DIV64 0x60
170#define TVP3026_XCLKCTRL_CLKSTOPPED 0x70
171#define TVP3026_XCLKCTRL_SRC_CLK0 0x00
172#define TVP3026_XCLKCTRL_SRC_CLK1 0x01
173#define TVP3026_XCLKCTRL_SRC_CLK2 0x02 /* CLK2 is TTL source*/
174#define TVP3026_XCLKCTRL_SRC_NCLK2 0x03 /* not CLK2 is TTL source */
175#define TVP3026_XCLKCTRL_SRC_ECLK2 0x04 /* CLK2 and not CLK2 is ECL source */
176#define TVP3026_XCLKCTRL_SRC_PLL 0x05
177#define TVP3026_XCLKCTRL_SRC_DIS 0x06 /* disable & poweroff internal clock */
178#define TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
179#define TVP3026_XPALETTEPAGE 0x1C
180#define TVP3026_XGENCTRL 0x1D
181#define TVP3026_XGENCTRL_HSYNC_POS 0x00
182#define TVP3026_XGENCTRL_HSYNC_NEG 0x01
183#define TVP3026_XGENCTRL_VSYNC_POS 0x00
184#define TVP3026_XGENCTRL_VSYNC_NEG 0x02
185#define TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
186#define TVP3026_XGENCTRL_BIG_ENDIAN 0x08
187#define TVP3026_XGENCTRL_BLACK_0IRE 0x00
188#define TVP3026_XGENCTRL_BLACK_75IRE 0x10
189#define TVP3026_XGENCTRL_NO_SYNC_ON_GREEN 0x00
190#define TVP3026_XGENCTRL_SYNC_ON_GREEN 0x20
191#define TVP3026_XGENCTRL_OVERSCAN_DIS 0x00
192#define TVP3026_XGENCTRL_OVERSCAN_EN 0x40
193#define TVP3026_XMISCCTRL 0x1E
194#define TVP3026_XMISCCTRL_DAC_PUP 0x00
195#define TVP3026_XMISCCTRL_DAC_PDOWN 0x01
196#define TVP3026_XMISCCTRL_DAC_EXT 0x00 /* or 8, bit 3 is ignored */
197#define TVP3026_XMISCCTRL_DAC_6BIT 0x04
198#define TVP3026_XMISCCTRL_DAC_8BIT 0x0C
199#define TVP3026_XMISCCTRL_PSEL_DIS 0x00
200#define TVP3026_XMISCCTRL_PSEL_EN 0x10
201#define TVP3026_XMISCCTRL_PSEL_LOW 0x00 /* PSEL high selects directcolor */
202#define TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
203#define TVP3026_XGENIOCTRL 0x2A
204#define TVP3026_XGENIODATA 0x2B
205#define TVP3026_XPLLADDR 0x2C
206#define TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
207#define TVP3026_XPLLDATA_N 0x00
208#define TVP3026_XPLLDATA_M 0x01
209#define TVP3026_XPLLDATA_P 0x02
210#define TVP3026_XPLLDATA_STAT 0x03
211#define TVP3026_XPIXPLLDATA 0x2D
212#define TVP3026_XMEMPLLDATA 0x2E
213#define TVP3026_XLOOPPLLDATA 0x2F
214#define TVP3026_XCOLKEYOVRMIN 0x30
215#define TVP3026_XCOLKEYOVRMAX 0x31
216#define TVP3026_XCOLKEYREDMIN 0x32
217#define TVP3026_XCOLKEYREDMAX 0x33
218#define TVP3026_XCOLKEYGREENMIN 0x34
219#define TVP3026_XCOLKEYGREENMAX 0x35
220#define TVP3026_XCOLKEYBLUEMIN 0x36
221#define TVP3026_XCOLKEYBLUEMAX 0x37
222#define TVP3026_XCOLKEYCTRL 0x38
223#define TVP3026_XCOLKEYCTRL_OVR_EN 0x01
224#define TVP3026_XCOLKEYCTRL_RED_EN 0x02
225#define TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
226#define TVP3026_XCOLKEYCTRL_BLUE_EN 0x08
227#define TVP3026_XCOLKEYCTRL_NEGATE 0x10
228#define TVP3026_XCOLKEYCTRL_ZOOM1 0x00
229#define TVP3026_XCOLKEYCTRL_ZOOM2 0x20
230#define TVP3026_XCOLKEYCTRL_ZOOM4 0x40
231#define TVP3026_XCOLKEYCTRL_ZOOM8 0x60
232#define TVP3026_XCOLKEYCTRL_ZOOM16 0x80
233#define TVP3026_XCOLKEYCTRL_ZOOM32 0xA0
234#define TVP3026_XMEMPLLCTRL 0x39
235#define TVP3026_XMEMPLLCTRL_DIV(X) (((X)-1)>>1) /* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */
236#define TVP3026_XMEMPLLCTRL_STROBEMKC4 0x08
237#define TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK 0x00 /* MKC4 */
238#define TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL 0x10 /* MKC4 */
239#define TVP3026_XMEMPLLCTRL_RCLK_PIXPLL 0x00
240#define TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL 0x20
241#define TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN 0x40 /* dot clock divided by loop pclk N prescaler */
242#define TVP3026_XSENSETEST 0x3A
243#define TVP3026_XTESTMODEDATA 0x3B
244#define TVP3026_XCRCREML 0x3C
245#define TVP3026_XCRCREMH 0x3D
246#define TVP3026_XCRCBITSEL 0x3E
247#define TVP3026_XID 0x3F
248
249static const unsigned char DACseq[] =
250{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL,
251 TVP3026_XMUXCTRL, TVP3026_XCLKCTRL,
252 TVP3026_XPALETTEPAGE,
253 TVP3026_XGENCTRL,
254 TVP3026_XMISCCTRL,
255 TVP3026_XGENIOCTRL,
256 TVP3026_XGENIODATA,
257 TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
258 TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
259 TVP3026_XCOLKEYCTRL,
260 TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
261
262#define POS3026_XLATCHCTRL 0
263#define POS3026_XTRUECOLORCTRL 1
264#define POS3026_XMUXCTRL 2
265#define POS3026_XCLKCTRL 3
266#define POS3026_XGENCTRL 5
267#define POS3026_XMISCCTRL 6
268#define POS3026_XMEMPLLCTRL 18
269#define POS3026_XCURCTRL 20
270
271static const unsigned char MGADACbpp32[] =
272{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
273 0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL,
274 0x00,
275 TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS,
276 TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH,
277 0x00,
278 0x1E,
279 0xFF, 0xFF, 0xFF, 0xFF,
280 0xFF, 0xFF, 0xFF, 0xFF,
281 TVP3026_XCOLKEYCTRL_ZOOM1,
282 0x00, 0x00, TVP3026_XCURCTRL_DIS };
283
284static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) {
285 unsigned int fvco;
286 unsigned int lin, lfeed, lpost;
287
288 DBG(__FUNCTION__)
289
290 fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost);
291 fvco >>= (*post = lpost);
292 *in = 64 - lin;
293 *feed = 64 - lfeed;
294 return fvco;
295}
296
297static int Ti3026_setpclk(WPMINFO int clk) {
298 unsigned int f_pll;
299 unsigned int pixfeed, pixin, pixpost;
300 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
301
302 DBG(__FUNCTION__)
303
304 f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost);
305
306 hw->DACclk[0] = pixin | 0xC0;
307 hw->DACclk[1] = pixfeed;
308 hw->DACclk[2] = pixpost | 0xB0;
309
310 {
311 unsigned int loopfeed, loopin, looppost, loopdiv, z;
312 unsigned int Bpp;
313
314 Bpp = ACCESS_FBINFO(curr.final_bppShift);
315
316 if (ACCESS_FBINFO(fbcon).var.bits_per_pixel == 24) {
317 loopfeed = 3; /* set lm to any possible value */
318 loopin = 3 * 32 / Bpp;
319 } else {
320 loopfeed = 4;
321 loopin = 4 * 32 / Bpp;
322 }
323 z = (110000 * loopin) / (f_pll * loopfeed);
324 loopdiv = 0; /* div 2 */
325 if (z < 2)
326 looppost = 0;
327 else if (z < 4)
328 looppost = 1;
329 else if (z < 8)
330 looppost = 2;
331 else {
332 looppost = 3;
333 loopdiv = z/16;
334 }
335 if (ACCESS_FBINFO(fbcon).var.bits_per_pixel == 24) {
336 hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
337 hw->DACclk[4] = (65 - loopfeed) | 0x80;
338 if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) {
339 if (isInterleave(MINFO))
340 hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
341 else {
342 hw->DACclk[4] &= ~0xC0;
343 hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
344 }
345 } else {
346 if (isInterleave(MINFO))
347 ; /* default... */
348 else {
349 hw->DACclk[4] ^= 0xC0; /* change from 0x80 to 0x40 */
350 hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3;
351 }
352 }
353 hw->DACclk[5] = looppost | 0xF8;
354 if (ACCESS_FBINFO(devflags.mga_24bpp_fix))
355 hw->DACclk[5] ^= 0x40;
356 } else {
357 hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
358 hw->DACclk[4] = 65 - loopfeed;
359 hw->DACclk[5] = looppost | 0xF0;
360 }
361 hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
362 }
363 return 0;
364}
365
366static int Ti3026_init(WPMINFO struct my_timming* m) {
367 u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
368 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
369
370 DBG(__FUNCTION__)
371
372 memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
373 switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
374 case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1; /* or _8_1, they are same */
375 hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
376 hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
377 hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
378 hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
379 break;
380 case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; /* or _4_1, they are same */
381 hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
382 hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
383 hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
384 hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
385 break;
386 case 16:
387 /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */
388 hw->DACreg[POS3026_XTRUECOLORCTRL] = (ACCESS_FBINFO(fbcon).var.green.length == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565);
389 hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
390 hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
391 break;
392 case 24:
393 /* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
394 hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
395 hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
396 hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
397 break;
398 case 32:
399 /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */
400 hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
401 break;
402 default:
403 return 1; /* TODO: failed */
404 }
405 if (matroxfb_vgaHWinit(PMINFO m)) return 1;
406
407 /* set SYNC */
408 hw->MiscOutReg = 0xCB;
409 if (m->sync & FB_SYNC_HOR_HIGH_ACT)
410 hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
411 if (m->sync & FB_SYNC_VERT_HIGH_ACT)
412 hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
413 if (m->sync & FB_SYNC_ON_GREEN)
414 hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
415
416 /* set DELAY */
417 if (ACCESS_FBINFO(video.len) < 0x400000)
418 hw->CRTCEXT[3] |= 0x08;
419 else if (ACCESS_FBINFO(video.len) > 0x400000)
420 hw->CRTCEXT[3] |= 0x10;
421
422 /* set HWCURSOR */
423 if (m->interlaced) {
424 hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
425 }
426 if (m->HTotal >= 1536)
427 hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096;
428
429 /* set interleaving */
430 hw->MXoptionReg &= ~0x00001000;
431 if (isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
432
433 /* set DAC */
434 Ti3026_setpclk(PMINFO m->pixclock);
435 return 0;
436}
437
438static void ti3026_setMCLK(WPMINFO int fout){
439 unsigned int f_pll;
440 unsigned int pclk_m, pclk_n, pclk_p;
441 unsigned int mclk_m, mclk_n, mclk_p;
442 unsigned int rfhcnt, mclk_ctl;
443 int tmout;
444
445 DBG(__FUNCTION__)
446
447 f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p);
448
449 /* save pclk */
450 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
451 pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
452 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD);
453 pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
454 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
455 pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
456
457 /* stop pclk */
458 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
459 outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
460
461 /* set pclk to new mclk */
462 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
463 outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
464 outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m);
465 outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
466
467 /* wait for PLL to lock */
468 for (tmout = 500000; tmout; tmout--) {
469 if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
470 break;
471 udelay(10);
472 };
473 if (!tmout)
474 printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
475
476 /* output pclk on mclk pin */
477 mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL);
478 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
479 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
480
481 /* stop MCLK */
482 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB);
483 outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00);
484
485 /* set mclk to new freq */
486 outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3);
487 outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
488 outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m);
489 outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
490
491 /* wait for PLL to lock */
492 for (tmout = 500000; tmout; tmout--) {
493 if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40)
494 break;
495 udelay(10);
496 }
497 if (!tmout)
498 printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
499
500 f_pll = f_pll * 333 / (10000 << mclk_p);
501 if (isMilleniumII(MINFO)) {
502 rfhcnt = (f_pll - 128) / 256;
503 if (rfhcnt > 15)
504 rfhcnt = 15;
505 } else {
506 rfhcnt = (f_pll - 64) / 128;
507 if (rfhcnt > 15)
508 rfhcnt = 0;
509 }
510 ACCESS_FBINFO(hw).MXoptionReg = (ACCESS_FBINFO(hw).MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
511 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
512
513 /* output MCLK to MCLK pin */
514 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
515 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
516
517 /* stop PCLK */
518 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
519 outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
520
521 /* restore pclk */
522 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
523 outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n);
524 outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m);
525 outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p);
526
527 /* wait for PLL to lock */
528 for (tmout = 500000; tmout; tmout--) {
529 if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
530 break;
531 udelay(10);
532 }
533 if (!tmout)
534 printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
535}
536
537static void ti3026_ramdac_init(WPMINFO2) {
538
539 DBG(__FUNCTION__)
540
541 ACCESS_FBINFO(features.pll.vco_freq_min) = 110000;
542 ACCESS_FBINFO(features.pll.ref_freq) = 114545;
543 ACCESS_FBINFO(features.pll.feed_div_min) = 2;
544 ACCESS_FBINFO(features.pll.feed_div_max) = 24;
545 ACCESS_FBINFO(features.pll.in_div_min) = 2;
546 ACCESS_FBINFO(features.pll.in_div_max) = 63;
547 ACCESS_FBINFO(features.pll.post_shift_max) = 3;
548 if (ACCESS_FBINFO(devflags.noinit))
549 return;
550 ti3026_setMCLK(PMINFO 60000);
551}
552
553static void Ti3026_restore(WPMINFO2) {
554 int i;
555 unsigned char progdac[6];
556 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
557 CRITFLAGS
558
559 DBG(__FUNCTION__)
560
561#ifdef DEBUG
562 dprintk(KERN_INFO "EXTVGA regs: ");
563 for (i = 0; i < 6; i++)
564 dprintk("%02X:", hw->CRTCEXT[i]);
565 dprintk("\n");
566#endif
567
568 CRITBEGIN
569
570 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
571
572 CRITEND
573
574 matroxfb_vgaHWrestore(PMINFO2);
575
576 CRITBEGIN
577
578 ACCESS_FBINFO(crtc1.panpos) = -1;
579 for (i = 0; i < 6; i++)
580 mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
581
582 for (i = 0; i < 21; i++) {
583 outTi3026(PMINFO DACseq[i], hw->DACreg[i]);
584 }
585
586 outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
587 progdac[0] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
588 progdac[3] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
589 outTi3026(PMINFO TVP3026_XPLLADDR, 0x15);
590 progdac[1] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
591 progdac[4] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
592 outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
593 progdac[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
594 progdac[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
595
596 CRITEND
597 if (memcmp(hw->DACclk, progdac, 6)) {
598 /* agrhh... setting up PLL is very slow on Millennium... */
599 /* Mystique PLL is locked in few ms, but Millennium PLL lock takes about 0.15 s... */
600 /* Maybe even we should call schedule() ? */
601
602 CRITBEGIN
603 outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
604 outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
605 outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
606 outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0);
607
608 outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
609 for (i = 0; i < 3; i++)
610 outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]);
611 /* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */
612 if (hw->MiscOutReg & 0x08) {
613 int tmout;
614 outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
615 for (tmout = 500000; tmout; --tmout) {
616 if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
617 break;
618 udelay(10);
619 }
620
621 CRITEND
622
623 if (!tmout)
624 printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
625 else
626 dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
627 CRITBEGIN
628 }
629 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
630 outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
631 for (i = 3; i < 6; i++)
632 outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
633 CRITEND
634 if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
635 int tmout;
636
637 CRITBEGIN
638 outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
639 for (tmout = 500000; tmout; --tmout) {
640 if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40)
641 break;
642 udelay(10);
643 }
644 CRITEND
645 if (!tmout)
646 printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
647 else
648 dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
649 }
650 }
651
652#ifdef DEBUG
653 dprintk(KERN_DEBUG "3026DACregs ");
654 for (i = 0; i < 21; i++) {
655 dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
656 if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
657 }
658 dprintk("\n" KERN_DEBUG "DACclk ");
659 for (i = 0; i < 6; i++)
660 dprintk("C%02X=%02X ", i, hw->DACclk[i]);
661 dprintk("\n");
662#endif
663}
664
665static void Ti3026_reset(WPMINFO2) {
666
667 DBG(__FUNCTION__)
668
669 ti3026_ramdac_init(PMINFO2);
670}
671
672static struct matrox_altout ti3026_output = {
673 .name = "Primary output",
674};
675
676static int Ti3026_preinit(WPMINFO2) {
677 static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960,
678 1024, 1152, 1280, 1600, 1664, 1920,
679 2048, 0};
680 static const int vxres_mill1[] = { 640, 768, 800, 960,
681 1024, 1152, 1280, 1600, 1920,
682 2048, 0};
683 struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
684
685 DBG(__FUNCTION__)
686
687 ACCESS_FBINFO(millenium) = 1;
688 ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL);
689 ACCESS_FBINFO(capable.cfb4) = 1;
690 ACCESS_FBINFO(capable.text) = 1; /* isMilleniumII(MINFO); */
691 ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
692
693 ACCESS_FBINFO(outputs[0]).data = MINFO;
694 ACCESS_FBINFO(outputs[0]).output = &ti3026_output;
695 ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src;
696 ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
697
698 if (ACCESS_FBINFO(devflags.noinit))
699 return 0;
700 /* preserve VGA I/O, BIOS and PPC */
701 hw->MXoptionReg &= 0xC0000100;
702 hw->MXoptionReg |= 0x002C0000;
703 if (ACCESS_FBINFO(devflags.novga))
704 hw->MXoptionReg &= ~0x00000100;
705 if (ACCESS_FBINFO(devflags.nobios))
706 hw->MXoptionReg &= ~0x40000000;
707 if (ACCESS_FBINFO(devflags.nopciretry))
708 hw->MXoptionReg |= 0x20000000;
709 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
710
711 ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV);
712
713 outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
714 outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
715 outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
716
717 outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
718 outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00);
719 outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
720
721 mga_outb(M_MISC_REG, 0x67);
722
723 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
724
725 mga_outl(M_RESET, 1);
726 udelay(250);
727 mga_outl(M_RESET, 0);
728 udelay(250);
729 mga_outl(M_MACCESS, 0x00008000);
730 udelay(10);
731 return 0;
732}
733
734struct matrox_switch matrox_millennium = {
735 Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore
736};
737EXPORT_SYMBOL(matrox_millennium);
738#endif
739MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_Ti3026.h b/drivers/video/matrox/matroxfb_Ti3026.h
new file mode 100644
index 000000000000..541933d7e4ea
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_Ti3026.h
@@ -0,0 +1,13 @@
1#ifndef __MATROXFB_TI3026_H__
2#define __MATROXFB_TI3026_H__
3
4/* make checkconfig does not walk through whole include tree */
5#include <linux/config.h>
6
7#include "matroxfb_base.h"
8
9#ifdef CONFIG_FB_MATROX_MILLENIUM
10extern struct matrox_switch matrox_millennium;
11#endif
12
13#endif /* __MATROXFB_TI3026_H__ */
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
new file mode 100644
index 000000000000..c7f3e1321224
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -0,0 +1,497 @@
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 * Version: 1.65 2002/08/14
8 *
9 * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
10 *
11 * Contributors: "menion?" <menion@mindless.com>
12 * Betatesting, fixes, ideas
13 *
14 * "Kurt Garloff" <garloff@suse.de>
15 * Betatesting, fixes, ideas, videomodes, videomodes timmings
16 *
17 * "Tom Rini" <trini@kernel.crashing.org>
18 * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
19 *
20 * "Bibek Sahu" <scorpio@dodds.net>
21 * Access device through readb|w|l and write b|w|l
22 * Extensive debugging stuff
23 *
24 * "Daniel Haun" <haund@usa.net>
25 * Testing, hardware cursor fixes
26 *
27 * "Scott Wood" <sawst46+@pitt.edu>
28 * Fixes
29 *
30 * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
31 * Betatesting
32 *
33 * "Kelly French" <targon@hazmat.com>
34 * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
35 * Betatesting, bug reporting
36 *
37 * "Pablo Bianucci" <pbian@pccp.com.ar>
38 * Fixes, ideas, betatesting
39 *
40 * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
41 * Fixes, enhandcements, ideas, betatesting
42 *
43 * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
44 * PPC betatesting, PPC support, backward compatibility
45 *
46 * "Paul Womar" <Paul@pwomar.demon.co.uk>
47 * "Owen Waller" <O.Waller@ee.qub.ac.uk>
48 * PPC betatesting
49 *
50 * "Thomas Pornin" <pornin@bolet.ens.fr>
51 * Alpha betatesting
52 *
53 * "Pieter van Leuven" <pvl@iae.nl>
54 * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
55 * G100 testing
56 *
57 * "H. Peter Arvin" <hpa@transmeta.com>
58 * Ideas
59 *
60 * "Cort Dougan" <cort@cs.nmt.edu>
61 * CHRP fixes and PReP cleanup
62 *
63 * "Mark Vojkovich" <mvojkovi@ucsd.edu>
64 * G400 support
65 *
66 * (following author is not in any relation with this code, but his code
67 * is included in this driver)
68 *
69 * Based on framebuffer driver for VBE 2.0 compliant graphic boards
70 * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
71 *
72 * (following author is not in any relation with this code, but his ideas
73 * were used when writting this driver)
74 *
75 * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
76 *
77 */
78
79#include "matroxfb_accel.h"
80#include "matroxfb_DAC1064.h"
81#include "matroxfb_Ti3026.h"
82#include "matroxfb_misc.h"
83
84#define curr_ydstorg(x) ACCESS_FBINFO2(x, curr.ydstorg.pixels)
85
86#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
87
88static inline void matrox_cfb4_pal(u_int32_t* pal) {
89 unsigned int i;
90
91 for (i = 0; i < 16; i++) {
92 pal[i] = i * 0x11111111U;
93 }
94 pal[i] = 0xFFFFFFFF;
95}
96
97static inline void matrox_cfb8_pal(u_int32_t* pal) {
98 unsigned int i;
99
100 for (i = 0; i < 16; i++) {
101 pal[i] = i * 0x01010101U;
102 }
103 pal[i] = 0x0F0F0F0F;
104}
105
106static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area);
107static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
108static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image);
109static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
110static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area);
111
112void matrox_cfbX_init(WPMINFO2) {
113 u_int32_t maccess;
114 u_int32_t mpitch;
115 u_int32_t mopmode;
116 int accel;
117
118 DBG(__FUNCTION__)
119
120 mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual;
121
122 ACCESS_FBINFO(fbops).fb_copyarea = cfb_copyarea;
123 ACCESS_FBINFO(fbops).fb_fillrect = cfb_fillrect;
124 ACCESS_FBINFO(fbops).fb_imageblit = cfb_imageblit;
125 ACCESS_FBINFO(fbops).fb_cursor = soft_cursor;
126
127 accel = (ACCESS_FBINFO(fbcon).var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT;
128
129 switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
130 case 4: maccess = 0x00000000; /* accelerate as 8bpp video */
131 mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
132 mopmode = M_OPMODE_4BPP;
133 matrox_cfb4_pal(ACCESS_FBINFO(cmap));
134 if (accel && !(mpitch & 1)) {
135 ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_cfb4_copyarea;
136 ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_cfb4_fillrect;
137 }
138 break;
139 case 8: maccess = 0x00000000;
140 mopmode = M_OPMODE_8BPP;
141 matrox_cfb8_pal(ACCESS_FBINFO(cmap));
142 if (accel) {
143 ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
144 ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
145 ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
146 }
147 break;
148 case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5) {
149 maccess = 0xC0000001;
150 ACCESS_FBINFO(cmap[16]) = 0x7FFF7FFF;
151 } else {
152 maccess = 0x40000001;
153 ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
154 }
155 mopmode = M_OPMODE_16BPP;
156 if (accel) {
157 ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
158 ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
159 ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
160 }
161 break;
162 case 24: maccess = 0x00000003;
163 mopmode = M_OPMODE_24BPP;
164 ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
165 if (accel) {
166 ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
167 ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
168 ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
169 }
170 break;
171 case 32: maccess = 0x00000002;
172 mopmode = M_OPMODE_32BPP;
173 ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
174 if (accel) {
175 ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
176 ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
177 ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
178 }
179 break;
180 default: maccess = 0x00000000;
181 mopmode = 0x00000000;
182 break; /* turn off acceleration!!! */
183 }
184 mga_fifo(8);
185 mga_outl(M_PITCH, mpitch);
186 mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
187 if (ACCESS_FBINFO(capable.plnwt))
188 mga_outl(M_PLNWT, -1);
189 if (ACCESS_FBINFO(capable.srcorg)) {
190 mga_outl(M_SRCORG, 0);
191 mga_outl(M_DSTORG, 0);
192 }
193 mga_outl(M_OPMODE, mopmode);
194 mga_outl(M_CXBNDRY, 0xFFFF0000);
195 mga_outl(M_YTOP, 0);
196 mga_outl(M_YBOT, 0x01FFFFFF);
197 mga_outl(M_MACCESS, maccess);
198 ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
199 if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
200 ACCESS_FBINFO(accel.m_opmode) = mopmode;
201}
202
203EXPORT_SYMBOL(matrox_cfbX_init);
204
205static void matrox_accel_bmove(WPMINFO int vxres, int sy, int sx, int dy, int dx, int height, int width) {
206 int start, end;
207 CRITFLAGS
208
209 DBG(__FUNCTION__)
210
211 CRITBEGIN
212
213 if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
214 mga_fifo(2);
215 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
216 M_DWG_BFCOL | M_DWG_REPLACE);
217 mga_outl(M_AR5, vxres);
218 width--;
219 start = sy*vxres+sx+curr_ydstorg(MINFO);
220 end = start+width;
221 } else {
222 mga_fifo(3);
223 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
224 mga_outl(M_SGN, 5);
225 mga_outl(M_AR5, -vxres);
226 width--;
227 end = (sy+height-1)*vxres+sx+curr_ydstorg(MINFO);
228 start = end+width;
229 dy += height-1;
230 }
231 mga_fifo(4);
232 mga_outl(M_AR0, end);
233 mga_outl(M_AR3, start);
234 mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
235 mga_ydstlen(dy, height);
236 WaitTillIdle();
237
238 CRITEND
239}
240
241static void matrox_accel_bmove_lin(WPMINFO int vxres, int sy, int sx, int dy, int dx, int height, int width) {
242 int start, end;
243 CRITFLAGS
244
245 DBG(__FUNCTION__)
246
247 CRITBEGIN
248
249 if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
250 mga_fifo(2);
251 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
252 M_DWG_BFCOL | M_DWG_REPLACE);
253 mga_outl(M_AR5, vxres);
254 width--;
255 start = sy*vxres+sx+curr_ydstorg(MINFO);
256 end = start+width;
257 } else {
258 mga_fifo(3);
259 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
260 mga_outl(M_SGN, 5);
261 mga_outl(M_AR5, -vxres);
262 width--;
263 end = (sy+height-1)*vxres+sx+curr_ydstorg(MINFO);
264 start = end+width;
265 dy += height-1;
266 }
267 mga_fifo(5);
268 mga_outl(M_AR0, end);
269 mga_outl(M_AR3, start);
270 mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
271 mga_outl(M_YDST, dy*vxres >> 5);
272 mga_outl(M_LEN | M_EXEC, height);
273 WaitTillIdle();
274
275 CRITEND
276}
277
278static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
279 MINFO_FROM_INFO(info);
280
281 if ((area->sx | area->dx | area->width) & 1)
282 cfb_copyarea(info, area);
283 else
284 matrox_accel_bmove_lin(PMINFO ACCESS_FBINFO(fbcon.var.xres_virtual) >> 1, area->sy, area->sx >> 1, area->dy, area->dx >> 1, area->height, area->width >> 1);
285}
286
287static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
288 MINFO_FROM_INFO(info);
289
290 matrox_accel_bmove(PMINFO ACCESS_FBINFO(fbcon.var.xres_virtual), area->sy, area->sx, area->dy, area->dx, area->height, area->width);
291}
292
293static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int height,
294 int width) {
295 CRITFLAGS
296
297 DBG(__FUNCTION__)
298
299 CRITBEGIN
300
301 mga_fifo(5);
302 mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
303 mga_outl(M_FCOL, color);
304 mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
305 mga_ydstlen(sy, height);
306 WaitTillIdle();
307
308 CRITEND
309}
310
311static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
312 MINFO_FROM_INFO(info);
313
314 switch (rect->rop) {
315 case ROP_COPY:
316 matroxfb_accel_clear(PMINFO ((u_int32_t*)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
317 break;
318 }
319}
320
321static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx, int sy, int sx, int height, int width) {
322 int whattodo;
323 CRITFLAGS
324
325 DBG(__FUNCTION__)
326
327 CRITBEGIN
328
329 whattodo = 0;
330 if (sx & 1) {
331 sx ++;
332 if (!width) return;
333 width --;
334 whattodo = 1;
335 }
336 if (width & 1) {
337 whattodo |= 2;
338 }
339 width >>= 1;
340 sx >>= 1;
341 if (width) {
342 mga_fifo(5);
343 mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2);
344 mga_outl(M_FCOL, bgx);
345 mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
346 mga_outl(M_YDST, sy * ACCESS_FBINFO(fbcon).var.xres_virtual >> 6);
347 mga_outl(M_LEN | M_EXEC, height);
348 WaitTillIdle();
349 }
350 if (whattodo) {
351 u_int32_t step = ACCESS_FBINFO(fbcon).var.xres_virtual >> 1;
352 vaddr_t vbase = ACCESS_FBINFO(video.vbase);
353 if (whattodo & 1) {
354 unsigned int uaddr = sy * step + sx - 1;
355 u_int32_t loop;
356 u_int8_t bgx2 = bgx & 0xF0;
357 for (loop = height; loop > 0; loop --) {
358 mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2);
359 uaddr += step;
360 }
361 }
362 if (whattodo & 2) {
363 unsigned int uaddr = sy * step + sx + width;
364 u_int32_t loop;
365 u_int8_t bgx2 = bgx & 0x0F;
366 for (loop = height; loop > 0; loop --) {
367 mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2);
368 uaddr += step;
369 }
370 }
371 }
372
373 CRITEND
374}
375
376static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
377 MINFO_FROM_INFO(info);
378
379 switch (rect->rop) {
380 case ROP_COPY:
381 matroxfb_cfb4_clear(PMINFO ((u_int32_t*)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
382 break;
383 }
384}
385
386static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx,
387 const u_int8_t* chardata, int width, int height, int yy, int xx) {
388 u_int32_t step;
389 u_int32_t ydstlen;
390 u_int32_t xlen;
391 u_int32_t ar0;
392 u_int32_t charcell;
393 u_int32_t fxbndry;
394 vaddr_t mmio;
395 int easy;
396 CRITFLAGS
397
398 DBG_HEAVY(__FUNCTION__);
399
400 step = (width + 7) >> 3;
401 charcell = height * step;
402 xlen = (charcell + 3) & ~3;
403 ydstlen = (yy << 16) | height;
404 if (width == step << 3) {
405 ar0 = height * width - 1;
406 easy = 1;
407 } else {
408 ar0 = width - 1;
409 easy = 0;
410 }
411
412 CRITBEGIN
413
414 mga_fifo(3);
415 if (easy)
416 mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
417 else
418 mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
419 mga_outl(M_FCOL, fgx);
420 mga_outl(M_BCOL, bgx);
421 fxbndry = ((xx + width - 1) << 16) | xx;
422 mmio = ACCESS_FBINFO(mmio.vbase);
423
424 mga_fifo(6);
425 mga_writel(mmio, M_FXBNDRY, fxbndry);
426 mga_writel(mmio, M_AR0, ar0);
427 mga_writel(mmio, M_AR3, 0);
428 if (easy) {
429 mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
430 mga_memcpy_toio(mmio, chardata, xlen);
431 } else {
432 mga_writel(mmio, M_AR5, 0);
433 mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
434 if ((step & 3) == 0) {
435 /* Great. Source has 32bit aligned lines, so we can feed them
436 directly to the accelerator. */
437 mga_memcpy_toio(mmio, chardata, charcell);
438 } else if (step == 1) {
439 /* Special case for 1..8bit widths */
440 while (height--) {
441#if defined(__BIG_ENDIAN)
442 fb_writel((*chardata) << 24, mmio.vaddr);
443#else
444 fb_writel(*chardata, mmio.vaddr);
445#endif
446 chardata++;
447 }
448 } else if (step == 2) {
449 /* Special case for 9..15bit widths */
450 while (height--) {
451#if defined(__BIG_ENDIAN)
452 fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr);
453#else
454 fb_writel(*(u_int16_t*)chardata, mmio.vaddr);
455#endif
456 chardata += 2;
457 }
458 } else {
459 /* Tell... well, why bother... */
460 while (height--) {
461 size_t i;
462
463 for (i = 0; i < step; i += 4) {
464 /* Hope that there are at least three readable bytes beyond the end of bitmap */
465 fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr);
466 }
467 chardata += step;
468 }
469 }
470 }
471 WaitTillIdle();
472 CRITEND
473}
474
475
476static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) {
477 MINFO_FROM_INFO(info);
478
479 DBG_HEAVY(__FUNCTION__);
480
481 if (image->depth == 1) {
482 u_int32_t fgx, bgx;
483
484 fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color];
485 bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color];
486 matroxfb_1bpp_imageblit(PMINFO fgx, bgx, image->data, image->width, image->height, image->dy, image->dx);
487 } else {
488 /* Danger! image->depth is useless: logo painting code always
489 passes framebuffer color depth here, although logo data are
490 always 8bpp and info->pseudo_palette is changed to contain
491 logo palette to be used (but only for true/direct-color... sic...).
492 So do it completely in software... */
493 cfb_imageblit(info, image);
494 }
495}
496
497MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_accel.h b/drivers/video/matrox/matroxfb_accel.h
new file mode 100644
index 000000000000..f40c314b4c30
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_accel.h
@@ -0,0 +1,8 @@
1#ifndef __MATROXFB_ACCEL_H__
2#define __MATROXFB_ACCEL_H__
3
4#include "matroxfb_base.h"
5
6void matrox_cfbX_init(WPMINFO2);
7
8#endif
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
new file mode 100644
index 000000000000..98e00d8601e5
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -0,0 +1,2589 @@
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 * "Samuel Hocevar" <sam@via.ecp.fr>
69 * Fixes
70 *
71 * "Anton Altaparmakov" <AntonA@bigfoot.com>
72 * G400 MAX/non-MAX distinction
73 *
74 * "Ken Aaker" <kdaaker@rchland.vnet.ibm.com>
75 * memtype extension (needed for GXT130P RS/6000 adapter)
76 *
77 * "Uns Lider" <unslider@miranda.org>
78 * G100 PLNWT fixes
79 *
80 * "Denis Zaitsev" <zzz@cd-club.ru>
81 * Fixes
82 *
83 * "Mike Pieper" <mike@pieper-family.de>
84 * TVOut enhandcements, V4L2 control interface.
85 *
86 * "Diego Biurrun" <diego@biurrun.de>
87 * DFP testing
88 *
89 * (following author is not in any relation with this code, but his code
90 * is included in this driver)
91 *
92 * Based on framebuffer driver for VBE 2.0 compliant graphic boards
93 * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
94 *
95 * (following author is not in any relation with this code, but his ideas
96 * were used when writting this driver)
97 *
98 * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
99 *
100 */
101
102/* make checkconfig does not check included files... */
103#include <linux/config.h>
104#include <linux/version.h>
105
106#include "matroxfb_base.h"
107#include "matroxfb_misc.h"
108#include "matroxfb_accel.h"
109#include "matroxfb_DAC1064.h"
110#include "matroxfb_Ti3026.h"
111#include "matroxfb_maven.h"
112#include "matroxfb_crtc2.h"
113#include "matroxfb_g450.h"
114#include <linux/matroxfb.h>
115#include <linux/interrupt.h>
116#include <asm/uaccess.h>
117
118#ifdef CONFIG_PPC_PMAC
119unsigned char nvram_read_byte(int);
120static int default_vmode = VMODE_NVRAM;
121static int default_cmode = CMODE_NVRAM;
122#endif
123
124static void matroxfb_unregister_device(struct matrox_fb_info* minfo);
125
126/* --------------------------------------------------------------------- */
127
128/*
129 * card parameters
130 */
131
132/* --------------------------------------------------------------------- */
133
134static struct fb_var_screeninfo vesafb_defined = {
135 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
136 0,0, /* virtual -> visible no offset */
137 8, /* depth -> load bits_per_pixel */
138 0, /* greyscale ? */
139 {0,0,0}, /* R */
140 {0,0,0}, /* G */
141 {0,0,0}, /* B */
142 {0,0,0}, /* transparency */
143 0, /* standard pixel format */
144 FB_ACTIVATE_NOW,
145 -1,-1,
146 FB_ACCELF_TEXT, /* accel flags */
147 39721L,48L,16L,33L,10L,
148 96L,2L,~0, /* No sync info */
149 FB_VMODE_NONINTERLACED,
150 0, {0,0,0,0,0}
151};
152
153
154
155/* --------------------------------------------------------------------- */
156static void update_crtc2(WPMINFO unsigned int pos) {
157 struct matroxfb_dh_fb_info* info = ACCESS_FBINFO(crtc2.info);
158
159 /* Make sure that displays are compatible */
160 if (info && (info->fbcon.var.bits_per_pixel == ACCESS_FBINFO(fbcon).var.bits_per_pixel)
161 && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
162 && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
163 ) {
164 switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
165 case 16:
166 case 32:
167 pos = pos * 8;
168 if (info->interlaced) {
169 mga_outl(0x3C2C, pos);
170 mga_outl(0x3C28, pos + ACCESS_FBINFO(fbcon).var.xres_virtual * ACCESS_FBINFO(fbcon).var.bits_per_pixel / 8);
171 } else {
172 mga_outl(0x3C28, pos);
173 }
174 break;
175 }
176 }
177}
178
179static void matroxfb_crtc1_panpos(WPMINFO2) {
180 if (ACCESS_FBINFO(crtc1.panpos) >= 0) {
181 unsigned long flags;
182 int panpos;
183
184 matroxfb_DAC_lock_irqsave(flags);
185 panpos = ACCESS_FBINFO(crtc1.panpos);
186 if (panpos >= 0) {
187 unsigned int extvga_reg;
188
189 ACCESS_FBINFO(crtc1.panpos) = -1; /* No update pending anymore */
190 extvga_reg = mga_inb(M_EXTVGA_INDEX);
191 mga_setr(M_EXTVGA_INDEX, 0x00, panpos);
192 if (extvga_reg != 0x00) {
193 mga_outb(M_EXTVGA_INDEX, extvga_reg);
194 }
195 }
196 matroxfb_DAC_unlock_irqrestore(flags);
197 }
198}
199
200static irqreturn_t matrox_irq(int irq, void *dev_id, struct pt_regs *fp)
201{
202 u_int32_t status;
203 int handled = 0;
204
205 MINFO_FROM(dev_id);
206
207 status = mga_inl(M_STATUS);
208
209 if (status & 0x20) {
210 mga_outl(M_ICLEAR, 0x20);
211 ACCESS_FBINFO(crtc1.vsync.cnt)++;
212 matroxfb_crtc1_panpos(PMINFO2);
213 wake_up_interruptible(&ACCESS_FBINFO(crtc1.vsync.wait));
214 handled = 1;
215 }
216 if (status & 0x200) {
217 mga_outl(M_ICLEAR, 0x200);
218 ACCESS_FBINFO(crtc2.vsync.cnt)++;
219 wake_up_interruptible(&ACCESS_FBINFO(crtc2.vsync.wait));
220 handled = 1;
221 }
222 return IRQ_RETVAL(handled);
223}
224
225int matroxfb_enable_irq(WPMINFO int reenable) {
226 u_int32_t bm;
227
228 if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
229 bm = 0x220;
230 else
231 bm = 0x020;
232
233 if (!test_and_set_bit(0, &ACCESS_FBINFO(irq_flags))) {
234 if (request_irq(ACCESS_FBINFO(pcidev)->irq, matrox_irq,
235 SA_SHIRQ, "matroxfb", MINFO)) {
236 clear_bit(0, &ACCESS_FBINFO(irq_flags));
237 return -EINVAL;
238 }
239 /* Clear any pending field interrupts */
240 mga_outl(M_ICLEAR, bm);
241 mga_outl(M_IEN, mga_inl(M_IEN) | bm);
242 } else if (reenable) {
243 u_int32_t ien;
244
245 ien = mga_inl(M_IEN);
246 if ((ien & bm) != bm) {
247 printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien);
248 mga_outl(M_IEN, ien | bm);
249 }
250 }
251 return 0;
252}
253
254static void matroxfb_disable_irq(WPMINFO2) {
255 if (test_and_clear_bit(0, &ACCESS_FBINFO(irq_flags))) {
256 /* Flush pending pan-at-vbl request... */
257 matroxfb_crtc1_panpos(PMINFO2);
258 if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
259 mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220);
260 else
261 mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20);
262 free_irq(ACCESS_FBINFO(pcidev)->irq, MINFO);
263 }
264}
265
266int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc) {
267 wait_queue_t __wait;
268 struct matrox_vsync *vs;
269 unsigned int cnt;
270 int ret;
271
272 switch (crtc) {
273 case 0:
274 vs = &ACCESS_FBINFO(crtc1.vsync);
275 break;
276 case 1:
277 if (ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG400) {
278 return -ENODEV;
279 }
280 vs = &ACCESS_FBINFO(crtc2.vsync);
281 break;
282 default:
283 return -ENODEV;
284 }
285 ret = matroxfb_enable_irq(PMINFO 0);
286 if (ret) {
287 return ret;
288 }
289 init_waitqueue_entry(&__wait, current);
290
291 cnt = vs->cnt;
292 ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10);
293 if (ret < 0) {
294 return ret;
295 }
296 if (ret == 0) {
297 matroxfb_enable_irq(PMINFO 1);
298 return -ETIMEDOUT;
299 }
300 return 0;
301}
302
303/* --------------------------------------------------------------------- */
304
305static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
306 unsigned int pos;
307 unsigned short p0, p1, p2;
308#ifdef CONFIG_FB_MATROX_32MB
309 unsigned int p3;
310#endif
311 int vbl;
312 unsigned long flags;
313
314 CRITFLAGS
315
316 DBG(__FUNCTION__)
317
318 if (ACCESS_FBINFO(dead))
319 return;
320
321 ACCESS_FBINFO(fbcon).var.xoffset = var->xoffset;
322 ACCESS_FBINFO(fbcon).var.yoffset = var->yoffset;
323 pos = (ACCESS_FBINFO(fbcon).var.yoffset * ACCESS_FBINFO(fbcon).var.xres_virtual + ACCESS_FBINFO(fbcon).var.xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
324 pos += ACCESS_FBINFO(curr.ydstorg.chunks);
325 p0 = ACCESS_FBINFO(hw).CRTC[0x0D] = pos & 0xFF;
326 p1 = ACCESS_FBINFO(hw).CRTC[0x0C] = (pos & 0xFF00) >> 8;
327 p2 = ACCESS_FBINFO(hw).CRTCEXT[0] = (ACCESS_FBINFO(hw).CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
328#ifdef CONFIG_FB_MATROX_32MB
329 p3 = ACCESS_FBINFO(hw).CRTCEXT[8] = pos >> 21;
330#endif
331
332 /* FB_ACTIVATE_VBL and we can acquire interrupts? Honor FB_ACTIVATE_VBL then... */
333 vbl = (var->activate & FB_ACTIVATE_VBL) && (matroxfb_enable_irq(PMINFO 0) == 0);
334
335 CRITBEGIN
336
337 matroxfb_DAC_lock_irqsave(flags);
338 mga_setr(M_CRTC_INDEX, 0x0D, p0);
339 mga_setr(M_CRTC_INDEX, 0x0C, p1);
340#ifdef CONFIG_FB_MATROX_32MB
341 if (ACCESS_FBINFO(devflags.support32MB))
342 mga_setr(M_EXTVGA_INDEX, 0x08, p3);
343#endif
344 if (vbl) {
345 ACCESS_FBINFO(crtc1.panpos) = p2;
346 } else {
347 /* Abort any pending change */
348 ACCESS_FBINFO(crtc1.panpos) = -1;
349 mga_setr(M_EXTVGA_INDEX, 0x00, p2);
350 }
351 matroxfb_DAC_unlock_irqrestore(flags);
352
353 update_crtc2(PMINFO pos);
354
355 CRITEND
356}
357
358static void matroxfb_remove(WPMINFO int dummy) {
359 /* Currently we are holding big kernel lock on all dead & usecount updates.
360 * Destroy everything after all users release it. Especially do not unregister
361 * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check
362 * for device unplugged when in use.
363 * In future we should point mmio.vbase & video.vbase somewhere where we can
364 * write data without causing too much damage...
365 */
366
367 ACCESS_FBINFO(dead) = 1;
368 if (ACCESS_FBINFO(usecount)) {
369 /* destroy it later */
370 return;
371 }
372 matroxfb_unregister_device(MINFO);
373 unregister_framebuffer(&ACCESS_FBINFO(fbcon));
374 matroxfb_g450_shutdown(PMINFO2);
375#ifdef CONFIG_MTRR
376 if (ACCESS_FBINFO(mtrr.vram_valid))
377 mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len));
378#endif
379 mga_iounmap(ACCESS_FBINFO(mmio.vbase));
380 mga_iounmap(ACCESS_FBINFO(video.vbase));
381 release_mem_region(ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len_maximum));
382 release_mem_region(ACCESS_FBINFO(mmio.base), 16384);
383#ifdef CONFIG_FB_MATROX_MULTIHEAD
384 kfree(minfo);
385#endif
386}
387
388 /*
389 * Open/Release the frame buffer device
390 */
391
392static int matroxfb_open(struct fb_info *info, int user)
393{
394 MINFO_FROM_INFO(info);
395
396 DBG_LOOP(__FUNCTION__)
397
398 if (ACCESS_FBINFO(dead)) {
399 return -ENXIO;
400 }
401 ACCESS_FBINFO(usecount)++;
402 if (user) {
403 ACCESS_FBINFO(userusecount)++;
404 }
405 return(0);
406}
407
408static int matroxfb_release(struct fb_info *info, int user)
409{
410 MINFO_FROM_INFO(info);
411
412 DBG_LOOP(__FUNCTION__)
413
414 if (user) {
415 if (0 == --ACCESS_FBINFO(userusecount)) {
416 matroxfb_disable_irq(PMINFO2);
417 }
418 }
419 if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) {
420 matroxfb_remove(PMINFO 0);
421 }
422 return(0);
423}
424
425static int matroxfb_pan_display(struct fb_var_screeninfo *var,
426 struct fb_info* info) {
427 MINFO_FROM_INFO(info);
428
429 DBG(__FUNCTION__)
430
431 matrox_pan_var(PMINFO var);
432 return 0;
433}
434
435static int matroxfb_get_final_bppShift(CPMINFO int bpp) {
436 int bppshft2;
437
438 DBG(__FUNCTION__)
439
440 bppshft2 = bpp;
441 if (!bppshft2) {
442 return 8;
443 }
444 if (isInterleave(MINFO))
445 bppshft2 >>= 1;
446 if (ACCESS_FBINFO(devflags.video64bits))
447 bppshft2 >>= 1;
448 return bppshft2;
449}
450
451static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) {
452 int over;
453 int rounding;
454
455 DBG(__FUNCTION__)
456
457 switch (bpp) {
458 case 0: return xres;
459 case 4: rounding = 128;
460 break;
461 case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */
462 break;
463 case 16: rounding = 32;
464 break;
465 case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */
466 break;
467 default: rounding = 16;
468 /* on G400, 16 really does not work */
469 if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
470 rounding = 32;
471 break;
472 }
473 if (isInterleave(MINFO)) {
474 rounding *= 2;
475 }
476 over = xres % rounding;
477 if (over)
478 xres += rounding-over;
479 return xres;
480}
481
482static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) {
483 const int* width;
484 int xres_new;
485
486 DBG(__FUNCTION__)
487
488 if (!bpp) return xres;
489
490 width = ACCESS_FBINFO(capable.vxres);
491
492 if (ACCESS_FBINFO(devflags.precise_width)) {
493 while (*width) {
494 if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) {
495 break;
496 }
497 width++;
498 }
499 xres_new = *width;
500 } else {
501 xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp);
502 }
503 if (!xres_new) return 0;
504 if (xres != xres_new) {
505 printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new);
506 }
507 return xres_new;
508}
509
510static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
511
512 DBG(__FUNCTION__)
513
514 switch (var->bits_per_pixel) {
515 case 4:
516 return 16; /* pseudocolor... 16 entries HW palette */
517 case 8:
518 return 256; /* pseudocolor... 256 entries HW palette */
519 case 16:
520 return 16; /* directcolor... 16 entries SW palette */
521 /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
522 case 24:
523 return 16; /* directcolor... 16 entries SW palette */
524 /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
525 case 32:
526 return 16; /* directcolor... 16 entries SW palette */
527 /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
528 }
529 return 16; /* return something reasonable... or panic()? */
530}
531
532static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) {
533 struct RGBT {
534 unsigned char bpp;
535 struct {
536 unsigned char offset,
537 length;
538 } red,
539 green,
540 blue,
541 transp;
542 signed char visual;
543 };
544 static const struct RGBT table[]= {
545 { 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
546 {15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR},
547 {16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR},
548 {24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR},
549 {32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR}
550 };
551 struct RGBT const *rgbt;
552 unsigned int bpp = var->bits_per_pixel;
553 unsigned int vramlen;
554 unsigned int memlen;
555
556 DBG(__FUNCTION__)
557
558 switch (bpp) {
559 case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL;
560 break;
561 case 8: break;
562 case 16: break;
563 case 24: break;
564 case 32: break;
565 default: return -EINVAL;
566 }
567 *ydstorg = 0;
568 vramlen = ACCESS_FBINFO(video.len_usable);
569 if (var->yres_virtual < var->yres)
570 var->yres_virtual = var->yres;
571 if (var->xres_virtual < var->xres)
572 var->xres_virtual = var->xres;
573
574 var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp);
575 memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
576 if (memlen > vramlen) {
577 var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp);
578 memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
579 }
580 /* There is hardware bug that no line can cross 4MB boundary */
581 /* give up for CFB24, it is impossible to easy workaround it */
582 /* for other try to do something */
583 if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) {
584 if (bpp == 24) {
585 /* sorry */
586 } else {
587 unsigned int linelen;
588 unsigned int m1 = linelen = var->xres_virtual * bpp / 8;
589 unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */
590 unsigned int max_yres;
591
592 while (m1) {
593 int t;
594
595 while (m2 >= m1) m2 -= m1;
596 t = m1;
597 m1 = m2;
598 m2 = t;
599 }
600 m2 = linelen * PAGE_SIZE / m2;
601 *ydstorg = m2 = 0x400000 % m2;
602 max_yres = (vramlen - m2) / linelen;
603 if (var->yres_virtual > max_yres)
604 var->yres_virtual = max_yres;
605 }
606 }
607 /* YDSTLEN contains only signed 16bit value */
608 if (var->yres_virtual > 32767)
609 var->yres_virtual = 32767;
610 /* we must round yres/xres down, we already rounded y/xres_virtual up
611 if it was possible. We should return -EINVAL, but I disagree */
612 if (var->yres_virtual < var->yres)
613 var->yres = var->yres_virtual;
614 if (var->xres_virtual < var->xres)
615 var->xres = var->xres_virtual;
616 if (var->xoffset + var->xres > var->xres_virtual)
617 var->xoffset = var->xres_virtual - var->xres;
618 if (var->yoffset + var->yres > var->yres_virtual)
619 var->yoffset = var->yres_virtual - var->yres;
620
621 if (bpp == 16 && var->green.length == 5) {
622 bpp--; /* an artifical value - 15 */
623 }
624
625 for (rgbt = table; rgbt->bpp < bpp; rgbt++);
626#define SETCLR(clr)\
627 var->clr.offset = rgbt->clr.offset;\
628 var->clr.length = rgbt->clr.length
629 SETCLR(red);
630 SETCLR(green);
631 SETCLR(blue);
632 SETCLR(transp);
633#undef SETCLR
634 *visual = rgbt->visual;
635
636 if (bpp > 8)
637 dprintk("matroxfb: truecolor: "
638 "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
639 var->transp.length, var->red.length, var->green.length, var->blue.length,
640 var->transp.offset, var->red.offset, var->green.offset, var->blue.offset);
641
642 *video_cmap_len = matroxfb_get_cmap_len(var);
643 dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
644 var->xres_virtual, var->yres_virtual);
645 return 0;
646}
647
648static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
649 unsigned blue, unsigned transp,
650 struct fb_info *fb_info)
651{
652#ifdef CONFIG_FB_MATROX_MULTIHEAD
653 struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon);
654#endif
655
656 DBG(__FUNCTION__)
657
658 /*
659 * Set a single color register. The values supplied are
660 * already rounded down to the hardware's capabilities
661 * (according to the entries in the `var' structure). Return
662 * != 0 for invalid regno.
663 */
664
665 if (regno >= ACCESS_FBINFO(curr.cmap_len))
666 return 1;
667
668 if (ACCESS_FBINFO(fbcon).var.grayscale) {
669 /* gray = 0.30*R + 0.59*G + 0.11*B */
670 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
671 }
672
673 red = CNVT_TOHW(red, ACCESS_FBINFO(fbcon).var.red.length);
674 green = CNVT_TOHW(green, ACCESS_FBINFO(fbcon).var.green.length);
675 blue = CNVT_TOHW(blue, ACCESS_FBINFO(fbcon).var.blue.length);
676 transp = CNVT_TOHW(transp, ACCESS_FBINFO(fbcon).var.transp.length);
677
678 switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
679 case 4:
680 case 8:
681 mga_outb(M_DAC_REG, regno);
682 mga_outb(M_DAC_VAL, red);
683 mga_outb(M_DAC_VAL, green);
684 mga_outb(M_DAC_VAL, blue);
685 break;
686 case 16:
687 {
688 u_int16_t col =
689 (red << ACCESS_FBINFO(fbcon).var.red.offset) |
690 (green << ACCESS_FBINFO(fbcon).var.green.offset) |
691 (blue << ACCESS_FBINFO(fbcon).var.blue.offset) |
692 (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* for 1:5:5:5 */
693 ACCESS_FBINFO(cmap[regno]) = col | (col << 16);
694 }
695 break;
696 case 24:
697 case 32:
698 ACCESS_FBINFO(cmap[regno]) =
699 (red << ACCESS_FBINFO(fbcon).var.red.offset) |
700 (green << ACCESS_FBINFO(fbcon).var.green.offset) |
701 (blue << ACCESS_FBINFO(fbcon).var.blue.offset) |
702 (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* 8:8:8:8 */
703 break;
704 }
705 return 0;
706}
707
708static void matroxfb_init_fix(WPMINFO2)
709{
710 struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
711 DBG(__FUNCTION__)
712
713 strcpy(fix->id,"MATROX");
714
715 fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
716 fix->ypanstep = 1;
717 fix->ywrapstep = 0;
718 fix->mmio_start = ACCESS_FBINFO(mmio.base);
719 fix->mmio_len = ACCESS_FBINFO(mmio.len);
720 fix->accel = ACCESS_FBINFO(devflags.accelerator);
721}
722
723static void matroxfb_update_fix(WPMINFO2)
724{
725 struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
726 DBG(__FUNCTION__)
727
728 fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
729 fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
730}
731
732static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
733{
734 int err;
735 int visual;
736 int cmap_len;
737 unsigned int ydstorg;
738 MINFO_FROM_INFO(info);
739
740 if (ACCESS_FBINFO(dead)) {
741 return -ENXIO;
742 }
743 if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len, &ydstorg)) != 0)
744 return err;
745 return 0;
746}
747
748static int matroxfb_set_par(struct fb_info *info)
749{
750 int err;
751 int visual;
752 int cmap_len;
753 unsigned int ydstorg;
754 struct fb_var_screeninfo *var;
755 MINFO_FROM_INFO(info);
756
757 DBG(__FUNCTION__)
758
759 if (ACCESS_FBINFO(dead)) {
760 return -ENXIO;
761 }
762
763 var = &info->var;
764 if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len, &ydstorg)) != 0)
765 return err;
766 ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
767 matroxfb_update_fix(PMINFO2);
768 ACCESS_FBINFO(fbcon).fix.visual = visual;
769 ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_PACKED_PIXELS;
770 ACCESS_FBINFO(fbcon).fix.type_aux = 0;
771 ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
772 {
773 unsigned int pos;
774
775 ACCESS_FBINFO(curr.cmap_len) = cmap_len;
776 ydstorg += ACCESS_FBINFO(devflags.ydstorg);
777 ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg;
778 ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2);
779 if (var->bits_per_pixel == 4)
780 ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg;
781 else
782 ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel;
783 ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel);
784 { struct my_timming mt;
785 struct matrox_hw_state* hw;
786 int out;
787
788 matroxfb_var2my(var, &mt);
789 mt.crtc = MATROXFB_SRC_CRTC1;
790 /* CRTC1 delays */
791 switch (var->bits_per_pixel) {
792 case 0: mt.delay = 31 + 0; break;
793 case 16: mt.delay = 21 + 8; break;
794 case 24: mt.delay = 17 + 8; break;
795 case 32: mt.delay = 16 + 8; break;
796 default: mt.delay = 31 + 8; break;
797 }
798
799 hw = &ACCESS_FBINFO(hw);
800
801 down_read(&ACCESS_FBINFO(altout).lock);
802 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
803 if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
804 ACCESS_FBINFO(outputs[out]).output->compute) {
805 ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
806 }
807 }
808 up_read(&ACCESS_FBINFO(altout).lock);
809 ACCESS_FBINFO(crtc1).pixclock = mt.pixclock;
810 ACCESS_FBINFO(crtc1).mnp = mt.mnp;
811 ACCESS_FBINFO(hw_switch->init(PMINFO &mt));
812 pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
813 pos += ACCESS_FBINFO(curr.ydstorg.chunks);
814
815 hw->CRTC[0x0D] = pos & 0xFF;
816 hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
817 hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
818 hw->CRTCEXT[8] = pos >> 21;
819 ACCESS_FBINFO(hw_switch->restore(PMINFO2));
820 update_crtc2(PMINFO pos);
821 down_read(&ACCESS_FBINFO(altout).lock);
822 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
823 if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
824 ACCESS_FBINFO(outputs[out]).output->program) {
825 ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
826 }
827 }
828 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
829 if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
830 ACCESS_FBINFO(outputs[out]).output->start) {
831 ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
832 }
833 }
834 up_read(&ACCESS_FBINFO(altout).lock);
835 matrox_cfbX_init(PMINFO2);
836 }
837 }
838 ACCESS_FBINFO(initialized) = 1;
839 return 0;
840}
841
842static int matroxfb_get_vblank(WPMINFO struct fb_vblank *vblank)
843{
844 unsigned int sts1;
845
846 matroxfb_enable_irq(PMINFO 0);
847 memset(vblank, 0, sizeof(*vblank));
848 vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC |
849 FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK;
850 sts1 = mga_inb(M_INSTS1);
851 vblank->vcount = mga_inl(M_VCOUNT);
852 /* BTW, on my PIII/450 with G400, reading M_INSTS1
853 byte makes this call about 12% slower (1.70 vs. 2.05 us
854 per ioctl()) */
855 if (sts1 & 1)
856 vblank->flags |= FB_VBLANK_HBLANKING;
857 if (sts1 & 8)
858 vblank->flags |= FB_VBLANK_VSYNCING;
859 if (vblank->vcount >= ACCESS_FBINFO(fbcon).var.yres)
860 vblank->flags |= FB_VBLANK_VBLANKING;
861 if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
862 vblank->flags |= FB_VBLANK_HAVE_COUNT;
863 /* Only one writer, aligned int value...
864 it should work without lock and without atomic_t */
865 vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt;
866 }
867 return 0;
868}
869
870static struct matrox_altout panellink_output = {
871 .name = "Panellink output",
872};
873
874static int matroxfb_ioctl(struct inode *inode, struct file *file,
875 unsigned int cmd, unsigned long arg,
876 struct fb_info *info)
877{
878 void __user *argp = (void __user *)arg;
879 MINFO_FROM_INFO(info);
880
881 DBG(__FUNCTION__)
882
883 if (ACCESS_FBINFO(dead)) {
884 return -ENXIO;
885 }
886
887 switch (cmd) {
888 case FBIOGET_VBLANK:
889 {
890 struct fb_vblank vblank;
891 int err;
892
893 err = matroxfb_get_vblank(PMINFO &vblank);
894 if (err)
895 return err;
896 if (copy_to_user(argp, &vblank, sizeof(vblank)))
897 return -EFAULT;
898 return 0;
899 }
900 case FBIO_WAITFORVSYNC:
901 {
902 u_int32_t crt;
903
904 if (get_user(crt, (u_int32_t __user *)arg))
905 return -EFAULT;
906
907 return matroxfb_wait_for_sync(PMINFO crt);
908 }
909 case MATROXFB_SET_OUTPUT_MODE:
910 {
911 struct matroxioc_output_mode mom;
912 struct matrox_altout *oproc;
913 int val;
914
915 if (copy_from_user(&mom, argp, sizeof(mom)))
916 return -EFAULT;
917 if (mom.output >= MATROXFB_MAX_OUTPUTS)
918 return -ENXIO;
919 down_read(&ACCESS_FBINFO(altout.lock));
920 oproc = ACCESS_FBINFO(outputs[mom.output]).output;
921 if (!oproc) {
922 val = -ENXIO;
923 } else if (!oproc->verifymode) {
924 if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
925 val = 0;
926 } else {
927 val = -EINVAL;
928 }
929 } else {
930 val = oproc->verifymode(ACCESS_FBINFO(outputs[mom.output]).data, mom.mode);
931 }
932 if (!val) {
933 if (ACCESS_FBINFO(outputs[mom.output]).mode != mom.mode) {
934 ACCESS_FBINFO(outputs[mom.output]).mode = mom.mode;
935 val = 1;
936 }
937 }
938 up_read(&ACCESS_FBINFO(altout.lock));
939 if (val != 1)
940 return val;
941 switch (ACCESS_FBINFO(outputs[mom.output]).src) {
942 case MATROXFB_SRC_CRTC1:
943 matroxfb_set_par(info);
944 break;
945 case MATROXFB_SRC_CRTC2:
946 {
947 struct matroxfb_dh_fb_info* crtc2;
948
949 down_read(&ACCESS_FBINFO(crtc2.lock));
950 crtc2 = ACCESS_FBINFO(crtc2.info);
951 if (crtc2)
952 crtc2->fbcon.fbops->fb_set_par(&crtc2->fbcon);
953 up_read(&ACCESS_FBINFO(crtc2.lock));
954 }
955 break;
956 }
957 return 0;
958 }
959 case MATROXFB_GET_OUTPUT_MODE:
960 {
961 struct matroxioc_output_mode mom;
962 struct matrox_altout *oproc;
963 int val;
964
965 if (copy_from_user(&mom, argp, sizeof(mom)))
966 return -EFAULT;
967 if (mom.output >= MATROXFB_MAX_OUTPUTS)
968 return -ENXIO;
969 down_read(&ACCESS_FBINFO(altout.lock));
970 oproc = ACCESS_FBINFO(outputs[mom.output]).output;
971 if (!oproc) {
972 val = -ENXIO;
973 } else {
974 mom.mode = ACCESS_FBINFO(outputs[mom.output]).mode;
975 val = 0;
976 }
977 up_read(&ACCESS_FBINFO(altout.lock));
978 if (val)
979 return val;
980 if (copy_to_user(argp, &mom, sizeof(mom)))
981 return -EFAULT;
982 return 0;
983 }
984 case MATROXFB_SET_OUTPUT_CONNECTION:
985 {
986 u_int32_t tmp;
987 int i;
988 int changes;
989
990 if (copy_from_user(&tmp, argp, sizeof(tmp)))
991 return -EFAULT;
992 for (i = 0; i < 32; i++) {
993 if (tmp & (1 << i)) {
994 if (i >= MATROXFB_MAX_OUTPUTS)
995 return -ENXIO;
996 if (!ACCESS_FBINFO(outputs[i]).output)
997 return -ENXIO;
998 switch (ACCESS_FBINFO(outputs[i]).src) {
999 case MATROXFB_SRC_NONE:
1000 case MATROXFB_SRC_CRTC1:
1001 break;
1002 default:
1003 return -EBUSY;
1004 }
1005 }
1006 }
1007 if (ACCESS_FBINFO(devflags.panellink)) {
1008 if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
1009 if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
1010 return -EINVAL;
1011 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
1012 if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC2) {
1013 return -EBUSY;
1014 }
1015 }
1016 }
1017 }
1018 changes = 0;
1019 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
1020 if (tmp & (1 << i)) {
1021 if (ACCESS_FBINFO(outputs[i]).src != MATROXFB_SRC_CRTC1) {
1022 changes = 1;
1023 ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_CRTC1;
1024 }
1025 } else if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
1026 changes = 1;
1027 ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_NONE;
1028 }
1029 }
1030 if (!changes)
1031 return 0;
1032 matroxfb_set_par(info);
1033 return 0;
1034 }
1035 case MATROXFB_GET_OUTPUT_CONNECTION:
1036 {
1037 u_int32_t conn = 0;
1038 int i;
1039
1040 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
1041 if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
1042 conn |= 1 << i;
1043 }
1044 }
1045 if (put_user(conn, (u_int32_t __user *)arg))
1046 return -EFAULT;
1047 return 0;
1048 }
1049 case MATROXFB_GET_AVAILABLE_OUTPUTS:
1050 {
1051 u_int32_t conn = 0;
1052 int i;
1053
1054 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
1055 if (ACCESS_FBINFO(outputs[i]).output) {
1056 switch (ACCESS_FBINFO(outputs[i]).src) {
1057 case MATROXFB_SRC_NONE:
1058 case MATROXFB_SRC_CRTC1:
1059 conn |= 1 << i;
1060 break;
1061 }
1062 }
1063 }
1064 if (ACCESS_FBINFO(devflags.panellink)) {
1065 if (conn & MATROXFB_OUTPUT_CONN_DFP)
1066 conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
1067 if (conn & MATROXFB_OUTPUT_CONN_SECONDARY)
1068 conn &= ~MATROXFB_OUTPUT_CONN_DFP;
1069 }
1070 if (put_user(conn, (u_int32_t __user *)arg))
1071 return -EFAULT;
1072 return 0;
1073 }
1074 case MATROXFB_GET_ALL_OUTPUTS:
1075 {
1076 u_int32_t conn = 0;
1077 int i;
1078
1079 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
1080 if (ACCESS_FBINFO(outputs[i]).output) {
1081 conn |= 1 << i;
1082 }
1083 }
1084 if (put_user(conn, (u_int32_t __user *)arg))
1085 return -EFAULT;
1086 return 0;
1087 }
1088 case VIDIOC_QUERYCAP:
1089 {
1090 struct v4l2_capability r;
1091
1092 memset(&r, 0, sizeof(r));
1093 strcpy(r.driver, "matroxfb");
1094 strcpy(r.card, "Matrox");
1095 sprintf(r.bus_info, "PCI:%s", pci_name(ACCESS_FBINFO(pcidev)));
1096 r.version = KERNEL_VERSION(1,0,0);
1097 r.capabilities = V4L2_CAP_VIDEO_OUTPUT;
1098 if (copy_to_user(argp, &r, sizeof(r)))
1099 return -EFAULT;
1100 return 0;
1101
1102 }
1103 case VIDIOC_QUERYCTRL:
1104 {
1105 struct v4l2_queryctrl qctrl;
1106 int err;
1107
1108 if (copy_from_user(&qctrl, argp, sizeof(qctrl)))
1109 return -EFAULT;
1110
1111 down_read(&ACCESS_FBINFO(altout).lock);
1112 if (!ACCESS_FBINFO(outputs[1]).output) {
1113 err = -ENXIO;
1114 } else if (ACCESS_FBINFO(outputs[1]).output->getqueryctrl) {
1115 err = ACCESS_FBINFO(outputs[1]).output->getqueryctrl(ACCESS_FBINFO(outputs[1]).data, &qctrl);
1116 } else {
1117 err = -EINVAL;
1118 }
1119 up_read(&ACCESS_FBINFO(altout).lock);
1120 if (err >= 0 &&
1121 copy_to_user(argp, &qctrl, sizeof(qctrl)))
1122 return -EFAULT;
1123 return err;
1124 }
1125 case VIDIOC_G_CTRL:
1126 {
1127 struct v4l2_control ctrl;
1128 int err;
1129
1130 if (copy_from_user(&ctrl, argp, sizeof(ctrl)))
1131 return -EFAULT;
1132
1133 down_read(&ACCESS_FBINFO(altout).lock);
1134 if (!ACCESS_FBINFO(outputs[1]).output) {
1135 err = -ENXIO;
1136 } else if (ACCESS_FBINFO(outputs[1]).output->getctrl) {
1137 err = ACCESS_FBINFO(outputs[1]).output->getctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl);
1138 } else {
1139 err = -EINVAL;
1140 }
1141 up_read(&ACCESS_FBINFO(altout).lock);
1142 if (err >= 0 &&
1143 copy_to_user(argp, &ctrl, sizeof(ctrl)))
1144 return -EFAULT;
1145 return err;
1146 }
1147 case VIDIOC_S_CTRL_OLD:
1148 case VIDIOC_S_CTRL:
1149 {
1150 struct v4l2_control ctrl;
1151 int err;
1152
1153 if (copy_from_user(&ctrl, argp, sizeof(ctrl)))
1154 return -EFAULT;
1155
1156 down_read(&ACCESS_FBINFO(altout).lock);
1157 if (!ACCESS_FBINFO(outputs[1]).output) {
1158 err = -ENXIO;
1159 } else if (ACCESS_FBINFO(outputs[1]).output->setctrl) {
1160 err = ACCESS_FBINFO(outputs[1]).output->setctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl);
1161 } else {
1162 err = -EINVAL;
1163 }
1164 up_read(&ACCESS_FBINFO(altout).lock);
1165 return err;
1166 }
1167 }
1168 return -ENOTTY;
1169}
1170
1171/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
1172
1173static int matroxfb_blank(int blank, struct fb_info *info)
1174{
1175 int seq;
1176 int crtc;
1177 CRITFLAGS
1178 MINFO_FROM_INFO(info);
1179
1180 DBG(__FUNCTION__)
1181
1182 if (ACCESS_FBINFO(dead))
1183 return 1;
1184
1185 switch (blank) {
1186 case FB_BLANK_NORMAL: seq = 0x20; crtc = 0x00; break; /* works ??? */
1187 case FB_BLANK_VSYNC_SUSPEND: seq = 0x20; crtc = 0x10; break;
1188 case FB_BLANK_HSYNC_SUSPEND: seq = 0x20; crtc = 0x20; break;
1189 case FB_BLANK_POWERDOWN: seq = 0x20; crtc = 0x30; break;
1190 default: seq = 0x00; crtc = 0x00; break;
1191 }
1192
1193 CRITBEGIN
1194
1195 mga_outb(M_SEQ_INDEX, 1);
1196 mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
1197 mga_outb(M_EXTVGA_INDEX, 1);
1198 mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
1199
1200 CRITEND
1201 return 0;
1202}
1203
1204static struct fb_ops matroxfb_ops = {
1205 .owner = THIS_MODULE,
1206 .fb_open = matroxfb_open,
1207 .fb_release = matroxfb_release,
1208 .fb_check_var = matroxfb_check_var,
1209 .fb_set_par = matroxfb_set_par,
1210 .fb_setcolreg = matroxfb_setcolreg,
1211 .fb_pan_display =matroxfb_pan_display,
1212 .fb_blank = matroxfb_blank,
1213 .fb_ioctl = matroxfb_ioctl,
1214/* .fb_fillrect = <set by matrox_cfbX_init>, */
1215/* .fb_copyarea = <set by matrox_cfbX_init>, */
1216/* .fb_imageblit = <set by matrox_cfbX_init>, */
1217/* .fb_cursor = <set by matrox_cfbX_init>, */
1218};
1219
1220#define RSDepth(X) (((X) >> 8) & 0x0F)
1221#define RS8bpp 0x1
1222#define RS15bpp 0x2
1223#define RS16bpp 0x3
1224#define RS32bpp 0x4
1225#define RS4bpp 0x5
1226#define RS24bpp 0x6
1227#define RSText 0x7
1228#define RSText8 0x8
1229/* 9-F */
1230static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] = {
1231 { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 },
1232 { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 },
1233 { { 11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 },
1234 { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 },
1235 { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 },
1236 { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 },
1237 { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */
1238 { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */
1239};
1240
1241/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
1242static unsigned int mem; /* "matrox:mem:xxxxxM" */
1243static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */
1244static int inv24; /* "matrox:inv24" */
1245static int cross4MB = -1; /* "matrox:cross4MB" */
1246static int disabled; /* "matrox:disabled" */
1247static int noaccel; /* "matrox:noaccel" */
1248static int nopan; /* "matrox:nopan" */
1249static int no_pci_retry; /* "matrox:nopciretry" */
1250static int novga; /* "matrox:novga" */
1251static int nobios; /* "matrox:nobios" */
1252static int noinit = 1; /* "matrox:init" */
1253static int inverse; /* "matrox:inverse" */
1254static int sgram; /* "matrox:sgram" */
1255#ifdef CONFIG_MTRR
1256static int mtrr = 1; /* "matrox:nomtrr" */
1257#endif
1258static int grayscale; /* "matrox:grayscale" */
1259static int dev = -1; /* "matrox:dev:xxxxx" */
1260static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */
1261static int depth = -1; /* "matrox:depth:xxxxx" */
1262static unsigned int xres; /* "matrox:xres:xxxxx" */
1263static unsigned int yres; /* "matrox:yres:xxxxx" */
1264static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */
1265static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */
1266static unsigned int vslen; /* "matrox:vslen:xxxxx" */
1267static unsigned int left = ~0; /* "matrox:left:xxxxx" */
1268static unsigned int right = ~0; /* "matrox:right:xxxxx" */
1269static unsigned int hslen; /* "matrox:hslen:xxxxx" */
1270static unsigned int pixclock; /* "matrox:pixclock:xxxxx" */
1271static int sync = -1; /* "matrox:sync:xxxxx" */
1272static unsigned int fv; /* "matrox:fv:xxxxx" */
1273static unsigned int fh; /* "matrox:fh:xxxxxk" */
1274static unsigned int maxclk; /* "matrox:maxclk:xxxxM" */
1275static int dfp; /* "matrox:dfp */
1276static int dfp_type = -1; /* "matrox:dfp:xxx */
1277static int memtype = -1; /* "matrox:memtype:xxx" */
1278static char outputs[8]; /* "matrox:outputs:xxx" */
1279
1280#ifndef MODULE
1281static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */
1282#endif
1283
1284static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSize){
1285 vaddr_t vm;
1286 unsigned int offs;
1287 unsigned int offs2;
1288 unsigned char store;
1289 unsigned char bytes[32];
1290 unsigned char* tmp;
1291
1292 DBG(__FUNCTION__)
1293
1294 vm = ACCESS_FBINFO(video.vbase);
1295 maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */
1296 /* at least 2MB */
1297 if (maxSize < 0x0200000) return 0;
1298 if (maxSize > 0x2000000) maxSize = 0x2000000;
1299
1300 mga_outb(M_EXTVGA_INDEX, 0x03);
1301 mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
1302
1303 store = mga_readb(vm, 0x1234);
1304 tmp = bytes;
1305 for (offs = 0x100000; offs < maxSize; offs += 0x200000)
1306 *tmp++ = mga_readb(vm, offs);
1307 for (offs = 0x100000; offs < maxSize; offs += 0x200000)
1308 mga_writeb(vm, offs, 0x02);
1309 if (ACCESS_FBINFO(features.accel.has_cacheflush))
1310 mga_outb(M_CACHEFLUSH, 0x00);
1311 else
1312 mga_writeb(vm, 0x1234, 0x99);
1313 for (offs = 0x100000; offs < maxSize; offs += 0x200000) {
1314 if (mga_readb(vm, offs) != 0x02)
1315 break;
1316 mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02);
1317 if (mga_readb(vm, offs))
1318 break;
1319 }
1320 tmp = bytes;
1321 for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000)
1322 mga_writeb(vm, offs2, *tmp++);
1323 mga_writeb(vm, 0x1234, store);
1324
1325 mga_outb(M_EXTVGA_INDEX, 0x03);
1326 mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80);
1327
1328 *realSize = offs - 0x100000;
1329#ifdef CONFIG_FB_MATROX_MILLENIUM
1330 ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || ((offs - 0x100000) & 0x3FFFFF));
1331#endif
1332 return 1;
1333}
1334
1335struct video_board {
1336 int maxvram;
1337 int maxdisplayable;
1338 int accelID;
1339 struct matrox_switch* lowlevel;
1340 };
1341#ifdef CONFIG_FB_MATROX_MILLENIUM
1342static struct video_board vbMillennium = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millennium};
1343static struct video_board vbMillennium2 = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W, &matrox_millennium};
1344static struct video_board vbMillennium2A = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millennium};
1345#endif /* CONFIG_FB_MATROX_MILLENIUM */
1346#ifdef CONFIG_FB_MATROX_MYSTIQUE
1347static struct video_board vbMystique = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique};
1348#endif /* CONFIG_FB_MATROX_MYSTIQUE */
1349#ifdef CONFIG_FB_MATROX_G
1350static struct video_board vbG100 = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100};
1351static struct video_board vbG200 = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100};
1352#ifdef CONFIG_FB_MATROX_32MB
1353/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for
1354 whole 32MB */
1355static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100};
1356#else
1357static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100};
1358#endif
1359#endif
1360
1361#define DEVF_VIDEO64BIT 0x0001
1362#define DEVF_SWAPS 0x0002
1363#define DEVF_SRCORG 0x0004
1364#define DEVF_DUALHEAD 0x0008
1365#define DEVF_CROSS4MB 0x0010
1366#define DEVF_TEXT4B 0x0020
1367/* #define DEVF_recycled 0x0040 */
1368/* #define DEVF_recycled 0x0080 */
1369#define DEVF_SUPPORT32MB 0x0100
1370#define DEVF_ANY_VXRES 0x0200
1371#define DEVF_TEXT16B 0x0400
1372#define DEVF_CRTC2 0x0800
1373#define DEVF_MAVEN_CAPABLE 0x1000
1374#define DEVF_PANELLINK_CAPABLE 0x2000
1375#define DEVF_G450DAC 0x4000
1376
1377#define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB)
1378#define DEVF_G2CORE (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG | DEVF_DUALHEAD)
1379#define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */
1380#define DEVF_G200 (DEVF_G2CORE)
1381#define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
1382/* if you'll find how to drive DFP... */
1383#define DEVF_G450 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD)
1384#define DEVF_G550 (DEVF_G450)
1385
1386static struct board {
1387 unsigned short vendor, device, rev, svid, sid;
1388 unsigned int flags;
1389 unsigned int maxclk;
1390 enum mga_chip chip;
1391 struct video_board* base;
1392 const char* name;
1393 } dev_list[] = {
1394#ifdef CONFIG_FB_MATROX_MILLENIUM
1395 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF,
1396 0, 0,
1397 DEVF_TEXT4B,
1398 230000,
1399 MGA_2064,
1400 &vbMillennium,
1401 "Millennium (PCI)"},
1402 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF,
1403 0, 0,
1404 DEVF_SWAPS,
1405 220000,
1406 MGA_2164,
1407 &vbMillennium2,
1408 "Millennium II (PCI)"},
1409 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF,
1410 0, 0,
1411 DEVF_SWAPS,
1412 250000,
1413 MGA_2164,
1414 &vbMillennium2A,
1415 "Millennium II (AGP)"},
1416#endif
1417#ifdef CONFIG_FB_MATROX_MYSTIQUE
1418 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02,
1419 0, 0,
1420 DEVF_VIDEO64BIT | DEVF_CROSS4MB,
1421 180000,
1422 MGA_1064,
1423 &vbMystique,
1424 "Mystique (PCI)"},
1425 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF,
1426 0, 0,
1427 DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
1428 220000,
1429 MGA_1164,
1430 &vbMystique,
1431 "Mystique 220 (PCI)"},
1432#endif
1433#ifdef CONFIG_FB_MATROX_G
1434 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 0xFF,
1435 0, 0,
1436 DEVF_G100,
1437 230000,
1438 MGA_G100,
1439 &vbG100,
1440 "MGA-G100 (PCI)"},
1441 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
1442 0, 0,
1443 DEVF_G100,
1444 230000,
1445 MGA_G100,
1446 &vbG100,
1447 "MGA-G100 (AGP)"},
1448 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF,
1449 0, 0,
1450 DEVF_G200,
1451 250000,
1452 MGA_G200,
1453 &vbG200,
1454 "MGA-G200 (PCI)"},
1455 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
1456 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC,
1457 DEVF_G200,
1458 220000,
1459 MGA_G200,
1460 &vbG200,
1461 "MGA-G200 (AGP)"},
1462 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
1463 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
1464 DEVF_G200,
1465 230000,
1466 MGA_G200,
1467 &vbG200,
1468 "Mystique G200 (AGP)"},
1469 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
1470 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
1471 DEVF_G200,
1472 250000,
1473 MGA_G200,
1474 &vbG200,
1475 "Millennium G200 (AGP)"},
1476 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
1477 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP,
1478 DEVF_G200,
1479 230000,
1480 MGA_G200,
1481 &vbG200,
1482 "Marvel G200 (AGP)"},
1483 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
1484 PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP,
1485 DEVF_G200,
1486 230000,
1487 MGA_G200,
1488 &vbG200,
1489 "MGA-G200 (AGP)"},
1490 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
1491 0, 0,
1492 DEVF_G200,
1493 230000,
1494 MGA_G200,
1495 &vbG200,
1496 "G200 (AGP)"},
1497 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80,
1498 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP,
1499 DEVF_G400,
1500 360000,
1501 MGA_G400,
1502 &vbG400,
1503 "Millennium G400 MAX (AGP)"},
1504 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80,
1505 0, 0,
1506 DEVF_G400,
1507 300000,
1508 MGA_G400,
1509 &vbG400,
1510 "G400 (AGP)"},
1511 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0xFF,
1512 0, 0,
1513 DEVF_G450,
1514 360000,
1515 MGA_G450,
1516 &vbG400,
1517 "G450"},
1518 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, 0xFF,
1519 0, 0,
1520 DEVF_G550,
1521 360000,
1522 MGA_G550,
1523 &vbG400,
1524 "G550"},
1525#endif
1526 {0, 0, 0xFF,
1527 0, 0,
1528 0,
1529 0,
1530 0,
1531 NULL,
1532 NULL}};
1533
1534#ifndef MODULE
1535static struct fb_videomode defaultmode = {
1536 /* 640x480 @ 60Hz, 31.5 kHz */
1537 NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
1538 0, FB_VMODE_NONINTERLACED
1539};
1540#endif /* !MODULE */
1541
1542static int hotplug = 0;
1543
1544static void setDefaultOutputs(WPMINFO2) {
1545 unsigned int i;
1546 const char* ptr;
1547
1548 ACCESS_FBINFO(outputs[0]).default_src = MATROXFB_SRC_CRTC1;
1549 if (ACCESS_FBINFO(devflags.g450dac)) {
1550 ACCESS_FBINFO(outputs[1]).default_src = MATROXFB_SRC_CRTC1;
1551 ACCESS_FBINFO(outputs[2]).default_src = MATROXFB_SRC_CRTC1;
1552 } else if (dfp) {
1553 ACCESS_FBINFO(outputs[2]).default_src = MATROXFB_SRC_CRTC1;
1554 }
1555 ptr = outputs;
1556 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
1557 char c = *ptr++;
1558
1559 if (c == 0) {
1560 break;
1561 }
1562 if (c == '0') {
1563 ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_NONE;
1564 } else if (c == '1') {
1565 ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_CRTC1;
1566 } else if (c == '2' && ACCESS_FBINFO(devflags.crtc2)) {
1567 ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_CRTC2;
1568 } else {
1569 printk(KERN_ERR "matroxfb: Unknown outputs setting\n");
1570 break;
1571 }
1572 }
1573 /* Nullify this option for subsequent adapters */
1574 outputs[0] = 0;
1575}
1576
1577static int initMatrox2(WPMINFO struct board* b){
1578 unsigned long ctrlptr_phys = 0;
1579 unsigned long video_base_phys = 0;
1580 unsigned int memsize;
1581 int err;
1582
1583 static struct pci_device_id intel_82437[] = {
1584 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) },
1585 { },
1586 };
1587
1588 DBG(__FUNCTION__)
1589
1590 /* set default values... */
1591 vesafb_defined.accel_flags = FB_ACCELF_TEXT;
1592
1593 ACCESS_FBINFO(hw_switch) = b->base->lowlevel;
1594 ACCESS_FBINFO(devflags.accelerator) = b->base->accelID;
1595 ACCESS_FBINFO(max_pixel_clock) = b->maxclk;
1596
1597 printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
1598 ACCESS_FBINFO(capable.plnwt) = 1;
1599 ACCESS_FBINFO(chip) = b->chip;
1600 ACCESS_FBINFO(capable.srcorg) = b->flags & DEVF_SRCORG;
1601 ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
1602 if (b->flags & DEVF_TEXT4B) {
1603 ACCESS_FBINFO(devflags.vgastep) = 4;
1604 ACCESS_FBINFO(devflags.textmode) = 4;
1605 ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
1606 } else if (b->flags & DEVF_TEXT16B) {
1607 ACCESS_FBINFO(devflags.vgastep) = 16;
1608 ACCESS_FBINFO(devflags.textmode) = 1;
1609 ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
1610 } else {
1611 ACCESS_FBINFO(devflags.vgastep) = 8;
1612 ACCESS_FBINFO(devflags.textmode) = 1;
1613 ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
1614 }
1615#ifdef CONFIG_FB_MATROX_32MB
1616 ACCESS_FBINFO(devflags.support32MB) = (b->flags & DEVF_SUPPORT32MB) != 0;
1617#endif
1618 ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
1619 ACCESS_FBINFO(devflags.crtc2) = (b->flags & DEVF_CRTC2) != 0;
1620 ACCESS_FBINFO(devflags.maven_capable) = (b->flags & DEVF_MAVEN_CAPABLE) != 0;
1621 ACCESS_FBINFO(devflags.dualhead) = (b->flags & DEVF_DUALHEAD) != 0;
1622 ACCESS_FBINFO(devflags.dfp_type) = dfp_type;
1623 ACCESS_FBINFO(devflags.g450dac) = (b->flags & DEVF_G450DAC) != 0;
1624 ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
1625 ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
1626 setDefaultOutputs(PMINFO2);
1627 if (b->flags & DEVF_PANELLINK_CAPABLE) {
1628 ACCESS_FBINFO(outputs[2]).data = MINFO;
1629 ACCESS_FBINFO(outputs[2]).output = &panellink_output;
1630 ACCESS_FBINFO(outputs[2]).src = ACCESS_FBINFO(outputs[2]).default_src;
1631 ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1632 ACCESS_FBINFO(devflags.panellink) = 1;
1633 }
1634
1635 if (ACCESS_FBINFO(capable.cross4MB) < 0)
1636 ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB;
1637 if (b->flags & DEVF_SWAPS) {
1638 ctrlptr_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 1);
1639 video_base_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 0);
1640 ACCESS_FBINFO(devflags.fbResource) = PCI_BASE_ADDRESS_0;
1641 } else {
1642 ctrlptr_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 0);
1643 video_base_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 1);
1644 ACCESS_FBINFO(devflags.fbResource) = PCI_BASE_ADDRESS_1;
1645 }
1646 err = -EINVAL;
1647 if (!ctrlptr_phys) {
1648 printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
1649 goto fail;
1650 }
1651 if (!video_base_phys) {
1652 printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n");
1653 goto fail;
1654 }
1655 memsize = b->base->maxvram;
1656 if (!request_mem_region(ctrlptr_phys, 16384, "matroxfb MMIO")) {
1657 goto fail;
1658 }
1659 if (!request_mem_region(video_base_phys, memsize, "matroxfb FB")) {
1660 goto failCtrlMR;
1661 }
1662 ACCESS_FBINFO(video.len_maximum) = memsize;
1663 /* convert mem (autodetect k, M) */
1664 if (mem < 1024) mem *= 1024;
1665 if (mem < 0x00100000) mem *= 1024;
1666
1667 if (mem && (mem < memsize))
1668 memsize = mem;
1669 err = -ENOMEM;
1670 if (mga_ioremap(ctrlptr_phys, 16384, MGA_IOREMAP_MMIO, &ACCESS_FBINFO(mmio.vbase))) {
1671 printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys);
1672 goto failVideoMR;
1673 }
1674 ACCESS_FBINFO(mmio.base) = ctrlptr_phys;
1675 ACCESS_FBINFO(mmio.len) = 16384;
1676 ACCESS_FBINFO(video.base) = video_base_phys;
1677 if (mga_ioremap(video_base_phys, memsize, MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) {
1678 printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
1679 video_base_phys, memsize);
1680 goto failCtrlIO;
1681 }
1682 {
1683 u_int32_t cmd;
1684 u_int32_t mga_option;
1685
1686 pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option);
1687 pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
1688 mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
1689 mga_option |= MX_OPTION_BSWAP;
1690 /* disable palette snooping */
1691 cmd &= ~PCI_COMMAND_VGA_PALETTE;
1692 if (pci_dev_present(intel_82437)) {
1693 if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
1694 printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
1695 }
1696 mga_option |= 0x20000000;
1697 ACCESS_FBINFO(devflags.nopciretry) = 1;
1698 }
1699 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd);
1700 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option);
1701 ACCESS_FBINFO(hw).MXoptionReg = mga_option;
1702
1703 /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */
1704 /* maybe preinit() candidate, but it is same... for all devices... at this time... */
1705 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00);
1706 }
1707
1708 err = -ENXIO;
1709 matroxfb_read_pins(PMINFO2);
1710 if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO2)) {
1711 goto failVideoIO;
1712 }
1713
1714 err = -ENOMEM;
1715 if (!matroxfb_getmemory(PMINFO memsize, &ACCESS_FBINFO(video.len)) || !ACCESS_FBINFO(video.len)) {
1716 printk(KERN_ERR "matroxfb: cannot determine memory size\n");
1717 goto failVideoIO;
1718 }
1719 ACCESS_FBINFO(devflags.ydstorg) = 0;
1720
1721 ACCESS_FBINFO(video.base) = video_base_phys;
1722 ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len);
1723 if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable)
1724 ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable;
1725#ifdef CONFIG_MTRR
1726 if (mtrr) {
1727 ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1);
1728 ACCESS_FBINFO(mtrr.vram_valid) = 1;
1729 printk(KERN_INFO "matroxfb: MTRR's turned on\n");
1730 }
1731#endif /* CONFIG_MTRR */
1732
1733 if (!ACCESS_FBINFO(devflags.novga))
1734 request_region(0x3C0, 32, "matrox");
1735 matroxfb_g450_connect(PMINFO2);
1736 ACCESS_FBINFO(hw_switch->reset(PMINFO2));
1737
1738 ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
1739 ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
1740 ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0;
1741 ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv;
1742 ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */
1743
1744 /* static settings */
1745 vesafb_defined.red = colors[depth-1].red;
1746 vesafb_defined.green = colors[depth-1].green;
1747 vesafb_defined.blue = colors[depth-1].blue;
1748 vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
1749 vesafb_defined.grayscale = grayscale;
1750 vesafb_defined.vmode = 0;
1751 if (noaccel)
1752 vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
1753
1754 ACCESS_FBINFO(fbops) = matroxfb_ops;
1755 ACCESS_FBINFO(fbcon.fbops) = &ACCESS_FBINFO(fbops);
1756 ACCESS_FBINFO(fbcon.pseudo_palette) = ACCESS_FBINFO(cmap);
1757 /* after __init time we are like module... no logo */
1758 ACCESS_FBINFO(fbcon.flags) = hotplug ? FBINFO_FLAG_MODULE : FBINFO_FLAG_DEFAULT;
1759 ACCESS_FBINFO(fbcon.flags) |= FBINFO_PARTIAL_PAN_OK | /* Prefer panning for scroll under MC viewer/edit */
1760 FBINFO_HWACCEL_COPYAREA | /* We have hw-assisted bmove */
1761 FBINFO_HWACCEL_FILLRECT | /* And fillrect */
1762 FBINFO_HWACCEL_IMAGEBLIT | /* And imageblit */
1763 FBINFO_HWACCEL_XPAN | /* And we support both horizontal */
1764 FBINFO_HWACCEL_YPAN; /* And vertical panning */
1765 ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
1766 fb_alloc_cmap(&ACCESS_FBINFO(fbcon.cmap), 256, 1);
1767
1768#ifndef MODULE
1769 /* mode database is marked __init!!! */
1770 if (!hotplug) {
1771 fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL,
1772 NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel);
1773 }
1774#endif /* !MODULE */
1775
1776 /* mode modifiers */
1777 if (hslen)
1778 vesafb_defined.hsync_len = hslen;
1779 if (vslen)
1780 vesafb_defined.vsync_len = vslen;
1781 if (left != ~0)
1782 vesafb_defined.left_margin = left;
1783 if (right != ~0)
1784 vesafb_defined.right_margin = right;
1785 if (upper != ~0)
1786 vesafb_defined.upper_margin = upper;
1787 if (lower != ~0)
1788 vesafb_defined.lower_margin = lower;
1789 if (xres)
1790 vesafb_defined.xres = xres;
1791 if (yres)
1792 vesafb_defined.yres = yres;
1793 if (sync != -1)
1794 vesafb_defined.sync = sync;
1795 else if (vesafb_defined.sync == ~0) {
1796 vesafb_defined.sync = 0;
1797 if (yres < 400)
1798 vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT;
1799 else if (yres < 480)
1800 vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT;
1801 }
1802
1803 /* fv, fh, maxclk limits was specified */
1804 {
1805 unsigned int tmp;
1806
1807 if (fv) {
1808 tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
1809 + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
1810 if ((tmp < fh) || (fh == 0)) fh = tmp;
1811 }
1812 if (fh) {
1813 tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
1814 + vesafb_defined.right_margin + vesafb_defined.hsync_len);
1815 if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
1816 }
1817 tmp = (maxclk + 499) / 500;
1818 if (tmp) {
1819 tmp = (2000000000 + tmp) / tmp;
1820 if (tmp > pixclock) pixclock = tmp;
1821 }
1822 }
1823 if (pixclock) {
1824 if (pixclock < 2000) /* > 500MHz */
1825 pixclock = 4000; /* 250MHz */
1826 if (pixclock > 1000000)
1827 pixclock = 1000000; /* 1MHz */
1828 vesafb_defined.pixclock = pixclock;
1829 }
1830
1831 /* FIXME: Where to move this?! */
1832#if defined(CONFIG_PPC_PMAC)
1833#ifndef MODULE
1834 if (_machine == _MACH_Pmac) {
1835 struct fb_var_screeninfo var;
1836 if (default_vmode <= 0 || default_vmode > VMODE_MAX)
1837 default_vmode = VMODE_640_480_60;
1838#ifdef CONFIG_NVRAM
1839 if (default_cmode == CMODE_NVRAM)
1840 default_cmode = nvram_read_byte(NV_CMODE);
1841#endif
1842 if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
1843 default_cmode = CMODE_8;
1844 if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
1845 var.accel_flags = vesafb_defined.accel_flags;
1846 var.xoffset = var.yoffset = 0;
1847 /* Note: mac_vmode_to_var() does not set all parameters */
1848 vesafb_defined = var;
1849 }
1850 }
1851#endif /* !MODULE */
1852#endif /* CONFIG_PPC_PMAC */
1853 vesafb_defined.xres_virtual = vesafb_defined.xres;
1854 if (nopan) {
1855 vesafb_defined.yres_virtual = vesafb_defined.yres;
1856 } else {
1857 vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
1858 to yres_virtual * xres_virtual < 2^32 */
1859 }
1860 matroxfb_init_fix(PMINFO2);
1861 /* Normalize values (namely yres_virtual) */
1862 matroxfb_check_var(&vesafb_defined, &ACCESS_FBINFO(fbcon));
1863 /* And put it into "current" var. Do NOT program hardware yet, or we'll not take over
1864 * vgacon correctly. fbcon_startup will call fb_set_par for us, WITHOUT check_var,
1865 * and unfortunately it will do it BEFORE vgacon contents is saved, so it won't work
1866 * anyway. But we at least tried... */
1867 ACCESS_FBINFO(fbcon.var) = vesafb_defined;
1868 err = -EINVAL;
1869
1870 printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
1871 vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
1872 vesafb_defined.xres_virtual, vesafb_defined.yres_virtual);
1873 printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n",
1874 ACCESS_FBINFO(video.base), vaddr_va(ACCESS_FBINFO(video.vbase)), ACCESS_FBINFO(video.len));
1875
1876/* We do not have to set currcon to 0... register_framebuffer do it for us on first console
1877 * and we do not want currcon == 0 for subsequent framebuffers */
1878
1879 ACCESS_FBINFO(fbcon).device = &ACCESS_FBINFO(pcidev)->dev;
1880 if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) {
1881 goto failVideoIO;
1882 }
1883 printk("fb%d: %s frame buffer device\n",
1884 ACCESS_FBINFO(fbcon.node), ACCESS_FBINFO(fbcon.fix.id));
1885
1886 /* there is no console on this fb... but we have to initialize hardware
1887 * until someone tells me what is proper thing to do */
1888 if (!ACCESS_FBINFO(initialized)) {
1889 printk(KERN_INFO "fb%d: initializing hardware\n",
1890 ACCESS_FBINFO(fbcon.node));
1891 /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
1892 * already before, so register_framebuffer works correctly. */
1893 vesafb_defined.activate |= FB_ACTIVATE_FORCE;
1894 fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
1895 }
1896
1897 return 0;
1898failVideoIO:;
1899 matroxfb_g450_shutdown(PMINFO2);
1900 mga_iounmap(ACCESS_FBINFO(video.vbase));
1901failCtrlIO:;
1902 mga_iounmap(ACCESS_FBINFO(mmio.vbase));
1903failVideoMR:;
1904 release_mem_region(video_base_phys, ACCESS_FBINFO(video.len_maximum));
1905failCtrlMR:;
1906 release_mem_region(ctrlptr_phys, 16384);
1907fail:;
1908 return err;
1909}
1910
1911static LIST_HEAD(matroxfb_list);
1912static LIST_HEAD(matroxfb_driver_list);
1913
1914#define matroxfb_l(x) list_entry(x, struct matrox_fb_info, next_fb)
1915#define matroxfb_driver_l(x) list_entry(x, struct matroxfb_driver, node)
1916int matroxfb_register_driver(struct matroxfb_driver* drv) {
1917 struct matrox_fb_info* minfo;
1918
1919 list_add(&drv->node, &matroxfb_driver_list);
1920 for (minfo = matroxfb_l(matroxfb_list.next);
1921 minfo != matroxfb_l(&matroxfb_list);
1922 minfo = matroxfb_l(minfo->next_fb.next)) {
1923 void* p;
1924
1925 if (minfo->drivers_count == MATROXFB_MAX_FB_DRIVERS)
1926 continue;
1927 p = drv->probe(minfo);
1928 if (p) {
1929 minfo->drivers_data[minfo->drivers_count] = p;
1930 minfo->drivers[minfo->drivers_count++] = drv;
1931 }
1932 }
1933 return 0;
1934}
1935
1936void matroxfb_unregister_driver(struct matroxfb_driver* drv) {
1937 struct matrox_fb_info* minfo;
1938
1939 list_del(&drv->node);
1940 for (minfo = matroxfb_l(matroxfb_list.next);
1941 minfo != matroxfb_l(&matroxfb_list);
1942 minfo = matroxfb_l(minfo->next_fb.next)) {
1943 int i;
1944
1945 for (i = 0; i < minfo->drivers_count; ) {
1946 if (minfo->drivers[i] == drv) {
1947 if (drv && drv->remove)
1948 drv->remove(minfo, minfo->drivers_data[i]);
1949 minfo->drivers[i] = minfo->drivers[--minfo->drivers_count];
1950 minfo->drivers_data[i] = minfo->drivers_data[minfo->drivers_count];
1951 } else
1952 i++;
1953 }
1954 }
1955}
1956
1957static void matroxfb_register_device(struct matrox_fb_info* minfo) {
1958 struct matroxfb_driver* drv;
1959 int i = 0;
1960 list_add(&ACCESS_FBINFO(next_fb), &matroxfb_list);
1961 for (drv = matroxfb_driver_l(matroxfb_driver_list.next);
1962 drv != matroxfb_driver_l(&matroxfb_driver_list);
1963 drv = matroxfb_driver_l(drv->node.next)) {
1964 if (drv && drv->probe) {
1965 void *p = drv->probe(minfo);
1966 if (p) {
1967 minfo->drivers_data[i] = p;
1968 minfo->drivers[i++] = drv;
1969 if (i == MATROXFB_MAX_FB_DRIVERS)
1970 break;
1971 }
1972 }
1973 }
1974 minfo->drivers_count = i;
1975}
1976
1977static void matroxfb_unregister_device(struct matrox_fb_info* minfo) {
1978 int i;
1979
1980 list_del(&ACCESS_FBINFO(next_fb));
1981 for (i = 0; i < minfo->drivers_count; i++) {
1982 struct matroxfb_driver* drv = minfo->drivers[i];
1983
1984 if (drv && drv->remove)
1985 drv->remove(minfo, minfo->drivers_data[i]);
1986 }
1987}
1988
1989static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) {
1990 struct board* b;
1991 u_int8_t rev;
1992 u_int16_t svid;
1993 u_int16_t sid;
1994 struct matrox_fb_info* minfo;
1995 int err;
1996 u_int32_t cmd;
1997#ifndef CONFIG_FB_MATROX_MULTIHEAD
1998 static int registered = 0;
1999#endif
2000 DBG(__FUNCTION__)
2001
2002 pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
2003 svid = pdev->subsystem_vendor;
2004 sid = pdev->subsystem_device;
2005 for (b = dev_list; b->vendor; b++) {
2006 if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
2007 if (b->svid)
2008 if ((b->svid != svid) || (b->sid != sid)) continue;
2009 break;
2010 }
2011 /* not match... */
2012 if (!b->vendor)
2013 return -1;
2014 if (dev > 0) {
2015 /* not requested one... */
2016 dev--;
2017 return -1;
2018 }
2019 pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
2020 if (pci_enable_device(pdev)) {
2021 return -1;
2022 }
2023
2024#ifdef CONFIG_FB_MATROX_MULTIHEAD
2025 minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL);
2026 if (!minfo)
2027 return -1;
2028#else
2029 if (registered) /* singlehead driver... */
2030 return -1;
2031 minfo = &matroxfb_global_mxinfo;
2032#endif
2033 memset(MINFO, 0, sizeof(*MINFO));
2034
2035 ACCESS_FBINFO(pcidev) = pdev;
2036 ACCESS_FBINFO(dead) = 0;
2037 ACCESS_FBINFO(usecount) = 0;
2038 ACCESS_FBINFO(userusecount) = 0;
2039
2040 pci_set_drvdata(pdev, MINFO);
2041 /* DEVFLAGS */
2042 ACCESS_FBINFO(devflags.memtype) = memtype;
2043 if (memtype != -1)
2044 noinit = 0;
2045 if (cmd & PCI_COMMAND_MEMORY) {
2046 ACCESS_FBINFO(devflags.novga) = novga;
2047 ACCESS_FBINFO(devflags.nobios) = nobios;
2048 ACCESS_FBINFO(devflags.noinit) = noinit;
2049 /* subsequent heads always needs initialization and must not enable BIOS */
2050 novga = 1;
2051 nobios = 1;
2052 noinit = 0;
2053 } else {
2054 ACCESS_FBINFO(devflags.novga) = 1;
2055 ACCESS_FBINFO(devflags.nobios) = 1;
2056 ACCESS_FBINFO(devflags.noinit) = 0;
2057 }
2058
2059 ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry;
2060 ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24;
2061 ACCESS_FBINFO(devflags.precise_width) = option_precise_width;
2062 ACCESS_FBINFO(devflags.sgram) = sgram;
2063 ACCESS_FBINFO(capable.cross4MB) = cross4MB;
2064
2065 spin_lock_init(&ACCESS_FBINFO(lock.DAC));
2066 spin_lock_init(&ACCESS_FBINFO(lock.accel));
2067 init_rwsem(&ACCESS_FBINFO(crtc2.lock));
2068 init_rwsem(&ACCESS_FBINFO(altout.lock));
2069 ACCESS_FBINFO(irq_flags) = 0;
2070 init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait));
2071 init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait));
2072 ACCESS_FBINFO(crtc1.panpos) = -1;
2073
2074 err = initMatrox2(PMINFO b);
2075 if (!err) {
2076#ifndef CONFIG_FB_MATROX_MULTIHEAD
2077 registered = 1;
2078#endif
2079 matroxfb_register_device(MINFO);
2080 return 0;
2081 }
2082#ifdef CONFIG_FB_MATROX_MULTIHEAD
2083 kfree(minfo);
2084#endif
2085 return -1;
2086}
2087
2088static void pci_remove_matrox(struct pci_dev* pdev) {
2089 struct matrox_fb_info* minfo;
2090
2091 minfo = pci_get_drvdata(pdev);
2092 matroxfb_remove(PMINFO 1);
2093}
2094
2095static struct pci_device_id matroxfb_devices[] = {
2096#ifdef CONFIG_FB_MATROX_MILLENIUM
2097 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL,
2098 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2099 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2,
2100 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2101 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP,
2102 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2103#endif
2104#ifdef CONFIG_FB_MATROX_MYSTIQUE
2105 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS,
2106 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2107#endif
2108#ifdef CONFIG_FB_MATROX_G
2109 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM,
2110 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2111 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP,
2112 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2113 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI,
2114 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2115 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP,
2116 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2117 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400,
2118 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2119 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550,
2120 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2121#endif
2122 {0, 0,
2123 0, 0, 0, 0, 0}
2124};
2125
2126MODULE_DEVICE_TABLE(pci, matroxfb_devices);
2127
2128
2129static struct pci_driver matroxfb_driver = {
2130 .name = "matroxfb",
2131 .id_table = matroxfb_devices,
2132 .probe = matroxfb_probe,
2133 .remove = pci_remove_matrox,
2134};
2135
2136/* **************************** init-time only **************************** */
2137
2138#define RSResolution(X) ((X) & 0x0F)
2139#define RS640x400 1
2140#define RS640x480 2
2141#define RS800x600 3
2142#define RS1024x768 4
2143#define RS1280x1024 5
2144#define RS1600x1200 6
2145#define RS768x576 7
2146#define RS960x720 8
2147#define RS1152x864 9
2148#define RS1408x1056 10
2149#define RS640x350 11
2150#define RS1056x344 12 /* 132 x 43 text */
2151#define RS1056x400 13 /* 132 x 50 text */
2152#define RS1056x480 14 /* 132 x 60 text */
2153#define RSNoxNo 15
2154/* 10-FF */
2155static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
2156 { 640, 400, 48, 16, 39, 8, 96, 2, 70 },
2157 { 640, 480, 48, 16, 33, 10, 96, 2, 60 },
2158 { 800, 600, 144, 24, 28, 8, 112, 6, 60 },
2159 { 1024, 768, 160, 32, 30, 4, 128, 4, 60 },
2160 { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 },
2161 { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 },
2162 { 768, 576, 144, 16, 28, 6, 112, 4, 60 },
2163 { 960, 720, 144, 24, 28, 8, 112, 4, 60 },
2164 { 1152, 864, 192, 32, 30, 4, 128, 4, 60 },
2165 { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 },
2166 { 640, 350, 48, 16, 39, 8, 96, 2, 70 },
2167 { 1056, 344, 96, 24, 59, 44, 160, 2, 70 },
2168 { 1056, 400, 96, 24, 39, 8, 160, 2, 70 },
2169 { 1056, 480, 96, 24, 36, 12, 160, 3, 60 },
2170 { 0, 0, ~0, ~0, ~0, ~0, 0, 0, 0 }
2171};
2172
2173#define RSCreate(X,Y) ((X) | ((Y) << 8))
2174static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = {
2175/* default must be first */
2176 { ~0, RSCreate(RSNoxNo, RS8bpp ) },
2177 { 0x101, RSCreate(RS640x480, RS8bpp ) },
2178 { 0x100, RSCreate(RS640x400, RS8bpp ) },
2179 { 0x180, RSCreate(RS768x576, RS8bpp ) },
2180 { 0x103, RSCreate(RS800x600, RS8bpp ) },
2181 { 0x188, RSCreate(RS960x720, RS8bpp ) },
2182 { 0x105, RSCreate(RS1024x768, RS8bpp ) },
2183 { 0x190, RSCreate(RS1152x864, RS8bpp ) },
2184 { 0x107, RSCreate(RS1280x1024, RS8bpp ) },
2185 { 0x198, RSCreate(RS1408x1056, RS8bpp ) },
2186 { 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
2187 { 0x110, RSCreate(RS640x480, RS15bpp) },
2188 { 0x181, RSCreate(RS768x576, RS15bpp) },
2189 { 0x113, RSCreate(RS800x600, RS15bpp) },
2190 { 0x189, RSCreate(RS960x720, RS15bpp) },
2191 { 0x116, RSCreate(RS1024x768, RS15bpp) },
2192 { 0x191, RSCreate(RS1152x864, RS15bpp) },
2193 { 0x119, RSCreate(RS1280x1024, RS15bpp) },
2194 { 0x199, RSCreate(RS1408x1056, RS15bpp) },
2195 { 0x11D, RSCreate(RS1600x1200, RS15bpp) },
2196 { 0x111, RSCreate(RS640x480, RS16bpp) },
2197 { 0x182, RSCreate(RS768x576, RS16bpp) },
2198 { 0x114, RSCreate(RS800x600, RS16bpp) },
2199 { 0x18A, RSCreate(RS960x720, RS16bpp) },
2200 { 0x117, RSCreate(RS1024x768, RS16bpp) },
2201 { 0x192, RSCreate(RS1152x864, RS16bpp) },
2202 { 0x11A, RSCreate(RS1280x1024, RS16bpp) },
2203 { 0x19A, RSCreate(RS1408x1056, RS16bpp) },
2204 { 0x11E, RSCreate(RS1600x1200, RS16bpp) },
2205 { 0x1B2, RSCreate(RS640x480, RS24bpp) },
2206 { 0x184, RSCreate(RS768x576, RS24bpp) },
2207 { 0x1B5, RSCreate(RS800x600, RS24bpp) },
2208 { 0x18C, RSCreate(RS960x720, RS24bpp) },
2209 { 0x1B8, RSCreate(RS1024x768, RS24bpp) },
2210 { 0x194, RSCreate(RS1152x864, RS24bpp) },
2211 { 0x1BB, RSCreate(RS1280x1024, RS24bpp) },
2212 { 0x19C, RSCreate(RS1408x1056, RS24bpp) },
2213 { 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
2214 { 0x112, RSCreate(RS640x480, RS32bpp) },
2215 { 0x183, RSCreate(RS768x576, RS32bpp) },
2216 { 0x115, RSCreate(RS800x600, RS32bpp) },
2217 { 0x18B, RSCreate(RS960x720, RS32bpp) },
2218 { 0x118, RSCreate(RS1024x768, RS32bpp) },
2219 { 0x193, RSCreate(RS1152x864, RS32bpp) },
2220 { 0x11B, RSCreate(RS1280x1024, RS32bpp) },
2221 { 0x19B, RSCreate(RS1408x1056, RS32bpp) },
2222 { 0x11F, RSCreate(RS1600x1200, RS32bpp) },
2223 { 0x010, RSCreate(RS640x350, RS4bpp ) },
2224 { 0x012, RSCreate(RS640x480, RS4bpp ) },
2225 { 0x102, RSCreate(RS800x600, RS4bpp ) },
2226 { 0x104, RSCreate(RS1024x768, RS4bpp ) },
2227 { 0x106, RSCreate(RS1280x1024, RS4bpp ) },
2228 { 0, 0 }};
2229
2230static void __init matroxfb_init_params(void) {
2231 /* fh from kHz to Hz */
2232 if (fh < 1000)
2233 fh *= 1000; /* 1kHz minimum */
2234 /* maxclk */
2235 if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */
2236 if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */
2237 /* fix VESA number */
2238 if (vesa != ~0)
2239 vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */
2240
2241 /* static settings */
2242 for (RSptr = vesamap; RSptr->vesa; RSptr++) {
2243 if (RSptr->vesa == vesa) break;
2244 }
2245 if (!RSptr->vesa) {
2246 printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa);
2247 RSptr = vesamap;
2248 }
2249 {
2250 int res = RSResolution(RSptr->info)-1;
2251 if (left == ~0)
2252 left = timmings[res].left;
2253 if (!xres)
2254 xres = timmings[res].xres;
2255 if (right == ~0)
2256 right = timmings[res].right;
2257 if (!hslen)
2258 hslen = timmings[res].hslen;
2259 if (upper == ~0)
2260 upper = timmings[res].upper;
2261 if (!yres)
2262 yres = timmings[res].yres;
2263 if (lower == ~0)
2264 lower = timmings[res].lower;
2265 if (!vslen)
2266 vslen = timmings[res].vslen;
2267 if (!(fv||fh||maxclk||pixclock))
2268 fv = timmings[res].vfreq;
2269 if (depth == -1)
2270 depth = RSDepth(RSptr->info);
2271 }
2272}
2273
2274static void __init matrox_init(void) {
2275 matroxfb_init_params();
2276 pci_register_driver(&matroxfb_driver);
2277 dev = -1; /* accept all new devices... */
2278}
2279
2280/* **************************** exit-time only **************************** */
2281
2282static void __exit matrox_done(void) {
2283 pci_unregister_driver(&matroxfb_driver);
2284}
2285
2286#ifndef MODULE
2287
2288/* ************************* init in-kernel code ************************** */
2289
2290static int __init matroxfb_setup(char *options) {
2291 char *this_opt;
2292
2293 DBG(__FUNCTION__)
2294
2295 if (!options || !*options)
2296 return 0;
2297
2298 while ((this_opt = strsep(&options, ",")) != NULL) {
2299 if (!*this_opt) continue;
2300
2301 dprintk("matroxfb_setup: option %s\n", this_opt);
2302
2303 if (!strncmp(this_opt, "dev:", 4))
2304 dev = simple_strtoul(this_opt+4, NULL, 0);
2305 else if (!strncmp(this_opt, "depth:", 6)) {
2306 switch (simple_strtoul(this_opt+6, NULL, 0)) {
2307 case 0: depth = RSText; break;
2308 case 4: depth = RS4bpp; break;
2309 case 8: depth = RS8bpp; break;
2310 case 15:depth = RS15bpp; break;
2311 case 16:depth = RS16bpp; break;
2312 case 24:depth = RS24bpp; break;
2313 case 32:depth = RS32bpp; break;
2314 default:
2315 printk(KERN_ERR "matroxfb: unsupported color depth\n");
2316 }
2317 } else if (!strncmp(this_opt, "xres:", 5))
2318 xres = simple_strtoul(this_opt+5, NULL, 0);
2319 else if (!strncmp(this_opt, "yres:", 5))
2320 yres = simple_strtoul(this_opt+5, NULL, 0);
2321 else if (!strncmp(this_opt, "vslen:", 6))
2322 vslen = simple_strtoul(this_opt+6, NULL, 0);
2323 else if (!strncmp(this_opt, "hslen:", 6))
2324 hslen = simple_strtoul(this_opt+6, NULL, 0);
2325 else if (!strncmp(this_opt, "left:", 5))
2326 left = simple_strtoul(this_opt+5, NULL, 0);
2327 else if (!strncmp(this_opt, "right:", 6))
2328 right = simple_strtoul(this_opt+6, NULL, 0);
2329 else if (!strncmp(this_opt, "upper:", 6))
2330 upper = simple_strtoul(this_opt+6, NULL, 0);
2331 else if (!strncmp(this_opt, "lower:", 6))
2332 lower = simple_strtoul(this_opt+6, NULL, 0);
2333 else if (!strncmp(this_opt, "pixclock:", 9))
2334 pixclock = simple_strtoul(this_opt+9, NULL, 0);
2335 else if (!strncmp(this_opt, "sync:", 5))
2336 sync = simple_strtoul(this_opt+5, NULL, 0);
2337 else if (!strncmp(this_opt, "vesa:", 5))
2338 vesa = simple_strtoul(this_opt+5, NULL, 0);
2339 else if (!strncmp(this_opt, "maxclk:", 7))
2340 maxclk = simple_strtoul(this_opt+7, NULL, 0);
2341 else if (!strncmp(this_opt, "fh:", 3))
2342 fh = simple_strtoul(this_opt+3, NULL, 0);
2343 else if (!strncmp(this_opt, "fv:", 3))
2344 fv = simple_strtoul(this_opt+3, NULL, 0);
2345 else if (!strncmp(this_opt, "mem:", 4))
2346 mem = simple_strtoul(this_opt+4, NULL, 0);
2347 else if (!strncmp(this_opt, "mode:", 5))
2348 strlcpy(videomode, this_opt+5, sizeof(videomode));
2349 else if (!strncmp(this_opt, "outputs:", 8))
2350 strlcpy(outputs, this_opt+8, sizeof(outputs));
2351 else if (!strncmp(this_opt, "dfp:", 4)) {
2352 dfp_type = simple_strtoul(this_opt+4, NULL, 0);
2353 dfp = 1;
2354 }
2355#ifdef CONFIG_PPC_PMAC
2356 else if (!strncmp(this_opt, "vmode:", 6)) {
2357 unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
2358 if (vmode > 0 && vmode <= VMODE_MAX)
2359 default_vmode = vmode;
2360 } else if (!strncmp(this_opt, "cmode:", 6)) {
2361 unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
2362 switch (cmode) {
2363 case 0:
2364 case 8:
2365 default_cmode = CMODE_8;
2366 break;
2367 case 15:
2368 case 16:
2369 default_cmode = CMODE_16;
2370 break;
2371 case 24:
2372 case 32:
2373 default_cmode = CMODE_32;
2374 break;
2375 }
2376 }
2377#endif
2378 else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */
2379 disabled = 1;
2380 else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */
2381 disabled = 0;
2382 else if (!strcmp(this_opt, "sgram")) /* nosgram == sdram */
2383 sgram = 1;
2384 else if (!strcmp(this_opt, "sdram"))
2385 sgram = 0;
2386 else if (!strncmp(this_opt, "memtype:", 8))
2387 memtype = simple_strtoul(this_opt+8, NULL, 0);
2388 else {
2389 int value = 1;
2390
2391 if (!strncmp(this_opt, "no", 2)) {
2392 value = 0;
2393 this_opt += 2;
2394 }
2395 if (! strcmp(this_opt, "inverse"))
2396 inverse = value;
2397 else if (!strcmp(this_opt, "accel"))
2398 noaccel = !value;
2399 else if (!strcmp(this_opt, "pan"))
2400 nopan = !value;
2401 else if (!strcmp(this_opt, "pciretry"))
2402 no_pci_retry = !value;
2403 else if (!strcmp(this_opt, "vga"))
2404 novga = !value;
2405 else if (!strcmp(this_opt, "bios"))
2406 nobios = !value;
2407 else if (!strcmp(this_opt, "init"))
2408 noinit = !value;
2409#ifdef CONFIG_MTRR
2410 else if (!strcmp(this_opt, "mtrr"))
2411 mtrr = value;
2412#endif
2413 else if (!strcmp(this_opt, "inv24"))
2414 inv24 = value;
2415 else if (!strcmp(this_opt, "cross4MB"))
2416 cross4MB = value;
2417 else if (!strcmp(this_opt, "grayscale"))
2418 grayscale = value;
2419 else if (!strcmp(this_opt, "dfp"))
2420 dfp = value;
2421 else {
2422 strlcpy(videomode, this_opt, sizeof(videomode));
2423 }
2424 }
2425 }
2426 return 0;
2427}
2428
2429static int __initdata initialized = 0;
2430
2431static int __init matroxfb_init(void)
2432{
2433 char *option = NULL;
2434
2435 DBG(__FUNCTION__)
2436
2437 if (fb_get_options("matroxfb", &option))
2438 return -ENODEV;
2439 matroxfb_setup(option);
2440
2441 if (disabled)
2442 return -ENXIO;
2443 if (!initialized) {
2444 initialized = 1;
2445 matrox_init();
2446 }
2447 hotplug = 1;
2448 /* never return failure, user can hotplug matrox later... */
2449 return 0;
2450}
2451
2452module_init(matroxfb_init);
2453
2454#else
2455
2456/* *************************** init module code **************************** */
2457
2458MODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
2459MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550");
2460MODULE_LICENSE("GPL");
2461
2462module_param(mem, int, 0);
2463MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
2464module_param(disabled, int, 0);
2465MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled) (default=0)");
2466module_param(noaccel, int, 0);
2467MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)");
2468module_param(nopan, int, 0);
2469MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)");
2470module_param(no_pci_retry, int, 0);
2471MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)");
2472module_param(novga, int, 0);
2473MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)");
2474module_param(nobios, int, 0);
2475MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)");
2476module_param(noinit, int, 0);
2477MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)");
2478module_param(memtype, int, 0);
2479MODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matroxfb.txt for explanation) (default=3 for G200, 0 for G400)");
2480#ifdef CONFIG_MTRR
2481module_param(mtrr, int, 0);
2482MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
2483#endif
2484module_param(sgram, int, 0);
2485MODULE_PARM_DESC(sgram, "Indicates that G100/G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
2486module_param(inv24, int, 0);
2487MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
2488module_param(inverse, int, 0);
2489MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)");
2490#ifdef CONFIG_FB_MATROX_MULTIHEAD
2491module_param(dev, int, 0);
2492MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)");
2493#else
2494module_param(dev, int, 0);
2495MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)");
2496#endif
2497module_param(vesa, int, 0);
2498MODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)");
2499module_param(xres, int, 0);
2500MODULE_PARM_DESC(xres, "Horizontal resolution (px), overrides xres from vesa (default=vesa)");
2501module_param(yres, int, 0);
2502MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)");
2503module_param(upper, int, 0);
2504MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)");
2505module_param(lower, int, 0);
2506MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)");
2507module_param(vslen, int, 0);
2508MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)");
2509module_param(left, int, 0);
2510MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)");
2511module_param(right, int, 0);
2512MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)");
2513module_param(hslen, int, 0);
2514MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)");
2515module_param(pixclock, int, 0);
2516MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)");
2517module_param(sync, int, 0);
2518MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)");
2519module_param(depth, int, 0);
2520MODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)");
2521module_param(maxclk, int, 0);
2522MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz");
2523module_param(fh, int, 0);
2524MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz");
2525module_param(fv, int, 0);
2526MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n"
2527"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n");
2528module_param(grayscale, int, 0);
2529MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)");
2530module_param(cross4MB, int, 0);
2531MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
2532module_param(dfp, int, 0);
2533MODULE_PARM_DESC(dfp, "Specifies whether to use digital flat panel interface of G200/G400 (0 or 1) (default=0)");
2534module_param(dfp_type, int, 0);
2535MODULE_PARM_DESC(dfp_type, "Specifies DFP interface type (0 to 255) (default=read from hardware)");
2536module_param_string(outputs, outputs, sizeof(outputs), 0);
2537MODULE_PARM_DESC(outputs, "Specifies which CRTC is mapped to which output (string of up to three letters, consisting of 0 (disabled), 1 (CRTC1), 2 (CRTC2)) (default=111 for Gx50, 101 for G200/G400 with DFP, and 100 for all other devices)");
2538#ifdef CONFIG_PPC_PMAC
2539module_param_named(vmode, default_vmode, int, 0);
2540MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
2541module_param_named(cmode, default_cmode, int, 0);
2542MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
2543#endif
2544
2545int __init init_module(void){
2546
2547 DBG(__FUNCTION__)
2548
2549 if (disabled)
2550 return -ENXIO;
2551
2552 if (depth == 0)
2553 depth = RSText;
2554 else if (depth == 4)
2555 depth = RS4bpp;
2556 else if (depth == 8)
2557 depth = RS8bpp;
2558 else if (depth == 15)
2559 depth = RS15bpp;
2560 else if (depth == 16)
2561 depth = RS16bpp;
2562 else if (depth == 24)
2563 depth = RS24bpp;
2564 else if (depth == 32)
2565 depth = RS32bpp;
2566 else if (depth != -1) {
2567 printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth);
2568 depth = -1;
2569 }
2570 matrox_init();
2571 /* never return failure; user can hotplug matrox later... */
2572 return 0;
2573}
2574#endif /* MODULE */
2575
2576module_exit(matrox_done);
2577EXPORT_SYMBOL(matroxfb_register_driver);
2578EXPORT_SYMBOL(matroxfb_unregister_driver);
2579EXPORT_SYMBOL(matroxfb_wait_for_sync);
2580EXPORT_SYMBOL(matroxfb_enable_irq);
2581
2582/*
2583 * Overrides for Emacs so that we follow Linus's tabbing style.
2584 * ---------------------------------------------------------------------------
2585 * Local variables:
2586 * c-basic-offset: 8
2587 * End:
2588 */
2589
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
new file mode 100644
index 000000000000..85a0b2558452
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -0,0 +1,781 @@
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 */
8#ifndef __MATROXFB_H__
9#define __MATROXFB_H__
10
11/* general, but fairly heavy, debugging */
12#undef MATROXFB_DEBUG
13
14/* heavy debugging: */
15/* -- logs putc[s], so everytime a char is displayed, it's logged */
16#undef MATROXFB_DEBUG_HEAVY
17
18/* This one _could_ cause infinite loops */
19/* It _does_ cause lots and lots of messages during idle loops */
20#undef MATROXFB_DEBUG_LOOP
21
22/* Debug register calls, too? */
23#undef MATROXFB_DEBUG_REG
24
25/* Guard accelerator accesses with spin_lock_irqsave... */
26#undef MATROXFB_USE_SPINLOCKS
27
28#include <linux/config.h>
29#include <linux/module.h>
30#include <linux/kernel.h>
31#include <linux/errno.h>
32#include <linux/string.h>
33#include <linux/mm.h>
34#include <linux/tty.h>
35#include <linux/slab.h>
36#include <linux/delay.h>
37#include <linux/fb.h>
38#include <linux/console.h>
39#include <linux/selection.h>
40#include <linux/ioport.h>
41#include <linux/init.h>
42#include <linux/timer.h>
43#include <linux/pci.h>
44#include <linux/spinlock.h>
45#include <linux/kd.h>
46
47#include <asm/io.h>
48#include <asm/unaligned.h>
49#ifdef CONFIG_MTRR
50#include <asm/mtrr.h>
51#endif
52
53#include "../console/fbcon.h"
54
55#if defined(CONFIG_PPC_PMAC)
56#include <asm/prom.h>
57#include <asm/pci-bridge.h>
58#include "../macmodes.h"
59#endif
60
61/* always compile support for 32MB... It cost almost nothing */
62#define CONFIG_FB_MATROX_32MB
63
64#ifdef MATROXFB_DEBUG
65
66#define DEBUG
67#define DBG(x) printk(KERN_DEBUG "matroxfb: %s\n", (x));
68
69#ifdef MATROXFB_DEBUG_HEAVY
70#define DBG_HEAVY(x) DBG(x)
71#else /* MATROXFB_DEBUG_HEAVY */
72#define DBG_HEAVY(x) /* DBG_HEAVY */
73#endif /* MATROXFB_DEBUG_HEAVY */
74
75#ifdef MATROXFB_DEBUG_LOOP
76#define DBG_LOOP(x) DBG(x)
77#else /* MATROXFB_DEBUG_LOOP */
78#define DBG_LOOP(x) /* DBG_LOOP */
79#endif /* MATROXFB_DEBUG_LOOP */
80
81#ifdef MATROXFB_DEBUG_REG
82#define DBG_REG(x) DBG(x)
83#else /* MATROXFB_DEBUG_REG */
84#define DBG_REG(x) /* DBG_REG */
85#endif /* MATROXFB_DEBUG_REG */
86
87#else /* MATROXFB_DEBUG */
88
89#define DBG(x) /* DBG */
90#define DBG_HEAVY(x) /* DBG_HEAVY */
91#define DBG_REG(x) /* DBG_REG */
92#define DBG_LOOP(x) /* DBG_LOOP */
93
94#endif /* MATROXFB_DEBUG */
95
96#ifdef DEBUG
97#define dprintk(X...) printk(X)
98#else
99#define dprintk(X...)
100#endif
101
102#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF
103#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF 0x110A
104#endif
105#ifndef PCI_SS_VENDOR_ID_MATROX
106#define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX
107#endif
108
109#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
110#define PCI_SS_ID_MATROX_GENERIC 0xFF00
111#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP 0xFF01
112#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP 0xFF02
113#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP 0xFF03
114#define PCI_SS_ID_MATROX_MARVEL_G200_AGP 0xFF04
115#define PCI_SS_ID_MATROX_MGA_G100_PCI 0xFF05
116#define PCI_SS_ID_MATROX_MGA_G100_AGP 0x1001
117#define PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP 0x2179
118#define PCI_SS_ID_SIEMENS_MGA_G100_AGP 0x001E /* 30 */
119#define PCI_SS_ID_SIEMENS_MGA_G200_AGP 0x0032 /* 50 */
120#endif
121
122#define MX_VISUAL_TRUECOLOR FB_VISUAL_DIRECTCOLOR
123#define MX_VISUAL_DIRECTCOLOR FB_VISUAL_TRUECOLOR
124#define MX_VISUAL_PSEUDOCOLOR FB_VISUAL_PSEUDOCOLOR
125
126#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
127
128/* G-series and Mystique have (almost) same DAC */
129#undef NEED_DAC1064
130#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G)
131#define NEED_DAC1064 1
132#endif
133
134typedef struct {
135 void __iomem* vaddr;
136} vaddr_t;
137
138static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) {
139 return readb(va.vaddr + offs);
140}
141
142static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) {
143 writeb(value, va.vaddr + offs);
144}
145
146static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) {
147 writew(value, va.vaddr + offs);
148}
149
150static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) {
151 return readl(va.vaddr + offs);
152}
153
154static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) {
155 writel(value, va.vaddr + offs);
156}
157
158static inline void mga_memcpy_toio(vaddr_t va, const void* src, int len) {
159#if defined(__alpha__) || defined(__i386__) || defined(__x86_64__)
160 /*
161 * memcpy_toio works for us if:
162 * (1) Copies data as 32bit quantities, not byte after byte,
163 * (2) Performs LE ordered stores, and
164 * (3) It copes with unaligned source (destination is guaranteed to be page
165 * aligned and length is guaranteed to be multiple of 4).
166 */
167 memcpy_toio(va.vaddr, src, len);
168#else
169 u_int32_t __iomem* addr = va.vaddr;
170
171 if ((unsigned long)src & 3) {
172 while (len >= 4) {
173 fb_writel(get_unaligned((u32 *)src), addr);
174 addr++;
175 len -= 4;
176 src += 4;
177 }
178 } else {
179 while (len >= 4) {
180 fb_writel(*(u32 *)src, addr);
181 addr++;
182 len -= 4;
183 src += 4;
184 }
185 }
186#endif
187}
188
189static inline void vaddr_add(vaddr_t* va, unsigned long offs) {
190 va->vaddr += offs;
191}
192
193static inline void __iomem* vaddr_va(vaddr_t va) {
194 return va.vaddr;
195}
196
197#define MGA_IOREMAP_NORMAL 0
198#define MGA_IOREMAP_NOCACHE 1
199
200#define MGA_IOREMAP_FB MGA_IOREMAP_NOCACHE
201#define MGA_IOREMAP_MMIO MGA_IOREMAP_NOCACHE
202static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags, vaddr_t* virt) {
203 if (flags & MGA_IOREMAP_NOCACHE)
204 virt->vaddr = ioremap_nocache(phys, size);
205 else
206 virt->vaddr = ioremap(phys, size);
207 return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */
208}
209
210static inline void mga_iounmap(vaddr_t va) {
211 iounmap(va.vaddr);
212}
213
214struct my_timming {
215 unsigned int pixclock;
216 int mnp;
217 unsigned int crtc;
218 unsigned int HDisplay;
219 unsigned int HSyncStart;
220 unsigned int HSyncEnd;
221 unsigned int HTotal;
222 unsigned int VDisplay;
223 unsigned int VSyncStart;
224 unsigned int VSyncEnd;
225 unsigned int VTotal;
226 unsigned int sync;
227 int dblscan;
228 int interlaced;
229 unsigned int delay; /* CRTC delay */
230};
231
232enum { M_SYSTEM_PLL, M_PIXEL_PLL_A, M_PIXEL_PLL_B, M_PIXEL_PLL_C, M_VIDEO_PLL };
233
234struct matrox_pll_cache {
235 unsigned int valid;
236 struct {
237 unsigned int mnp_key;
238 unsigned int mnp_value;
239 } data[4];
240};
241
242struct matrox_pll_limits {
243 unsigned int vcomin;
244 unsigned int vcomax;
245};
246
247struct matrox_pll_features {
248 unsigned int vco_freq_min;
249 unsigned int ref_freq;
250 unsigned int feed_div_min;
251 unsigned int feed_div_max;
252 unsigned int in_div_min;
253 unsigned int in_div_max;
254 unsigned int post_shift_max;
255};
256
257struct matroxfb_par
258{
259 unsigned int final_bppShift;
260 unsigned int cmap_len;
261 struct {
262 unsigned int bytes;
263 unsigned int pixels;
264 unsigned int chunks;
265 } ydstorg;
266};
267
268struct matrox_fb_info;
269
270struct matrox_DAC1064_features {
271 u_int8_t xvrefctrl;
272 u_int8_t xmiscctrl;
273};
274
275struct matrox_accel_features {
276 int has_cacheflush;
277};
278
279/* current hardware status */
280struct mavenregs {
281 u_int8_t regs[256];
282 int mode;
283 int vlines;
284 int xtal;
285 int fv;
286
287 u_int16_t htotal;
288 u_int16_t hcorr;
289};
290
291struct matrox_crtc2 {
292 u_int32_t ctl;
293};
294
295struct matrox_hw_state {
296 u_int32_t MXoptionReg;
297 unsigned char DACclk[6];
298 unsigned char DACreg[80];
299 unsigned char MiscOutReg;
300 unsigned char DACpal[768];
301 unsigned char CRTC[25];
302 unsigned char CRTCEXT[9];
303 unsigned char SEQ[5];
304 /* unused for MGA mode, but who knows... */
305 unsigned char GCTL[9];
306 /* unused for MGA mode, but who knows... */
307 unsigned char ATTR[21];
308
309 /* TVOut only */
310 struct mavenregs maven;
311
312 struct matrox_crtc2 crtc2;
313};
314
315struct matrox_accel_data {
316#ifdef CONFIG_FB_MATROX_MILLENIUM
317 unsigned char ramdac_rev;
318#endif
319 u_int32_t m_dwg_rect;
320 u_int32_t m_opmode;
321};
322
323struct v4l2_queryctrl;
324struct v4l2_control;
325
326struct matrox_altout {
327 const char *name;
328 int (*compute)(void* altout_dev, struct my_timming* input);
329 int (*program)(void* altout_dev);
330 int (*start)(void* altout_dev);
331 int (*verifymode)(void* altout_dev, u_int32_t mode);
332 int (*getqueryctrl)(void* altout_dev,
333 struct v4l2_queryctrl* ctrl);
334 int (*getctrl)(void* altout_dev,
335 struct v4l2_control* ctrl);
336 int (*setctrl)(void* altout_dev,
337 struct v4l2_control* ctrl);
338};
339
340#define MATROXFB_SRC_NONE 0
341#define MATROXFB_SRC_CRTC1 1
342#define MATROXFB_SRC_CRTC2 2
343
344enum mga_chip { MGA_2064, MGA_2164, MGA_1064, MGA_1164, MGA_G100, MGA_G200, MGA_G400, MGA_G450, MGA_G550 };
345
346struct matrox_bios {
347 unsigned int bios_valid : 1;
348 unsigned int pins_len;
349 unsigned char pins[128];
350 struct {
351 unsigned char vMaj, vMin, vRev;
352 } version;
353 struct {
354 unsigned char state, tvout;
355 } output;
356};
357
358extern struct display fb_display[];
359
360struct matrox_switch;
361struct matroxfb_driver;
362struct matroxfb_dh_fb_info;
363
364struct matrox_vsync {
365 wait_queue_head_t wait;
366 unsigned int cnt;
367};
368
369struct matrox_fb_info {
370 struct fb_info fbcon;
371
372 struct list_head next_fb;
373
374 int dead;
375 int initialized;
376 unsigned int usecount;
377
378 unsigned int userusecount;
379 unsigned long irq_flags;
380
381 struct matroxfb_par curr;
382 struct matrox_hw_state hw;
383
384 struct matrox_accel_data accel;
385
386 struct pci_dev* pcidev;
387
388 struct {
389 struct matrox_vsync vsync;
390 unsigned int pixclock;
391 int mnp;
392 int panpos;
393 } crtc1;
394 struct {
395 struct matrox_vsync vsync;
396 unsigned int pixclock;
397 int mnp;
398 struct matroxfb_dh_fb_info* info;
399 struct rw_semaphore lock;
400 } crtc2;
401 struct {
402 struct rw_semaphore lock;
403 struct {
404 int brightness, contrast, saturation, hue, gamma;
405 int testout, deflicker;
406 } tvo_params;
407 } altout;
408#define MATROXFB_MAX_OUTPUTS 3
409 struct {
410 unsigned int src;
411 struct matrox_altout* output;
412 void* data;
413 unsigned int mode;
414 unsigned int default_src;
415 } outputs[MATROXFB_MAX_OUTPUTS];
416
417#define MATROXFB_MAX_FB_DRIVERS 5
418 struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]);
419 void* (drivers_data[MATROXFB_MAX_FB_DRIVERS]);
420 unsigned int drivers_count;
421
422 struct {
423 unsigned long base; /* physical */
424 vaddr_t vbase; /* CPU view */
425 unsigned int len;
426 unsigned int len_usable;
427 unsigned int len_maximum;
428 } video;
429
430 struct {
431 unsigned long base; /* physical */
432 vaddr_t vbase; /* CPU view */
433 unsigned int len;
434 } mmio;
435
436 unsigned int max_pixel_clock;
437
438 struct matrox_switch* hw_switch;
439
440 struct {
441 struct matrox_pll_features pll;
442 struct matrox_DAC1064_features DAC1064;
443 struct matrox_accel_features accel;
444 } features;
445 struct {
446 spinlock_t DAC;
447 spinlock_t accel;
448 } lock;
449
450 enum mga_chip chip;
451
452 int interleave;
453 int millenium;
454 int milleniumII;
455 struct {
456 int cfb4;
457 const int* vxres;
458 int cross4MB;
459 int text;
460 int plnwt;
461 int srcorg;
462 } capable;
463#ifdef CONFIG_MTRR
464 struct {
465 int vram;
466 int vram_valid;
467 } mtrr;
468#endif
469 struct {
470 int precise_width;
471 int mga_24bpp_fix;
472 int novga;
473 int nobios;
474 int nopciretry;
475 int noinit;
476 int sgram;
477#ifdef CONFIG_FB_MATROX_32MB
478 int support32MB;
479#endif
480
481 int accelerator;
482 int text_type_aux;
483 int video64bits;
484 int crtc2;
485 int maven_capable;
486 unsigned int vgastep;
487 unsigned int textmode;
488 unsigned int textstep;
489 unsigned int textvram; /* character cells */
490 unsigned int ydstorg; /* offset in bytes from video start to usable memory */
491 /* 0 except for 6MB Millenium */
492 int memtype;
493 int g450dac;
494 int dfp_type;
495 int panellink; /* G400 DFP possible (not G450/G550) */
496 int dualhead;
497 unsigned int fbResource;
498 } devflags;
499 struct fb_ops fbops;
500 struct matrox_bios bios;
501 struct {
502 struct matrox_pll_limits pixel;
503 struct matrox_pll_limits system;
504 struct matrox_pll_limits video;
505 } limits;
506 struct {
507 struct matrox_pll_cache pixel;
508 struct matrox_pll_cache system;
509 struct matrox_pll_cache video;
510 } cache;
511 struct {
512 struct {
513 unsigned int video;
514 unsigned int system;
515 } pll;
516 struct {
517 u_int32_t opt;
518 u_int32_t opt2;
519 u_int32_t opt3;
520 u_int32_t mctlwtst;
521 u_int32_t mctlwtst_core;
522 u_int32_t memmisc;
523 u_int32_t memrdbk;
524 u_int32_t maccess;
525 } reg;
526 struct {
527 unsigned int ddr:1,
528 emrswen:1,
529 dll:1;
530 } memory;
531 } values;
532 u_int32_t cmap[17];
533};
534
535#define info2minfo(info) container_of(info, struct matrox_fb_info, fbcon)
536
537#ifdef CONFIG_FB_MATROX_MULTIHEAD
538#define ACCESS_FBINFO2(info, x) (info->x)
539#define ACCESS_FBINFO(x) ACCESS_FBINFO2(minfo,x)
540
541#define MINFO minfo
542
543#define WPMINFO2 struct matrox_fb_info* minfo
544#define WPMINFO WPMINFO2 ,
545#define CPMINFO2 const struct matrox_fb_info* minfo
546#define CPMINFO CPMINFO2 ,
547#define PMINFO2 minfo
548#define PMINFO PMINFO2 ,
549
550#define MINFO_FROM(x) struct matrox_fb_info* minfo = x
551#else
552
553extern struct matrox_fb_info matroxfb_global_mxinfo;
554
555#define ACCESS_FBINFO(x) (matroxfb_global_mxinfo.x)
556#define ACCESS_FBINFO2(info, x) (matroxfb_global_mxinfo.x)
557
558#define MINFO (&matroxfb_global_mxinfo)
559
560#define WPMINFO2 void
561#define WPMINFO
562#define CPMINFO2 void
563#define CPMINFO
564#define PMINFO2
565#define PMINFO
566
567#define MINFO_FROM(x)
568
569#endif
570
571#define MINFO_FROM_INFO(x) MINFO_FROM(info2minfo(x))
572
573struct matrox_switch {
574 int (*preinit)(WPMINFO2);
575 void (*reset)(WPMINFO2);
576 int (*init)(WPMINFO struct my_timming*);
577 void (*restore)(WPMINFO2);
578};
579
580struct matroxfb_driver {
581 struct list_head node;
582 char* name;
583 void* (*probe)(struct matrox_fb_info* info);
584 void (*remove)(struct matrox_fb_info* info, void* data);
585};
586
587int matroxfb_register_driver(struct matroxfb_driver* drv);
588void matroxfb_unregister_driver(struct matroxfb_driver* drv);
589
590#define PCI_OPTION_REG 0x40
591#define PCI_OPTION_ENABLE_ROM 0x40000000
592
593#define PCI_MGA_INDEX 0x44
594#define PCI_MGA_DATA 0x48
595#define PCI_OPTION2_REG 0x50
596#define PCI_OPTION3_REG 0x54
597#define PCI_MEMMISC_REG 0x58
598
599#define M_DWGCTL 0x1C00
600#define M_MACCESS 0x1C04
601#define M_CTLWTST 0x1C08
602
603#define M_PLNWT 0x1C1C
604
605#define M_BCOL 0x1C20
606#define M_FCOL 0x1C24
607
608#define M_SGN 0x1C58
609#define M_LEN 0x1C5C
610#define M_AR0 0x1C60
611#define M_AR1 0x1C64
612#define M_AR2 0x1C68
613#define M_AR3 0x1C6C
614#define M_AR4 0x1C70
615#define M_AR5 0x1C74
616#define M_AR6 0x1C78
617
618#define M_CXBNDRY 0x1C80
619#define M_FXBNDRY 0x1C84
620#define M_YDSTLEN 0x1C88
621#define M_PITCH 0x1C8C
622#define M_YDST 0x1C90
623#define M_YDSTORG 0x1C94
624#define M_YTOP 0x1C98
625#define M_YBOT 0x1C9C
626
627/* mystique only */
628#define M_CACHEFLUSH 0x1FFF
629
630#define M_EXEC 0x0100
631
632#define M_DWG_TRAP 0x04
633#define M_DWG_BITBLT 0x08
634#define M_DWG_ILOAD 0x09
635
636#define M_DWG_LINEAR 0x0080
637#define M_DWG_SOLID 0x0800
638#define M_DWG_ARZERO 0x1000
639#define M_DWG_SGNZERO 0x2000
640#define M_DWG_SHIFTZERO 0x4000
641
642#define M_DWG_REPLACE 0x000C0000
643#define M_DWG_REPLACE2 (M_DWG_REPLACE | 0x40)
644#define M_DWG_XOR 0x00060010
645
646#define M_DWG_BFCOL 0x04000000
647#define M_DWG_BMONOWF 0x08000000
648
649#define M_DWG_TRANSC 0x40000000
650
651#define M_FIFOSTATUS 0x1E10
652#define M_STATUS 0x1E14
653#define M_ICLEAR 0x1E18
654#define M_IEN 0x1E1C
655
656#define M_VCOUNT 0x1E20
657
658#define M_RESET 0x1E40
659#define M_MEMRDBK 0x1E44
660
661#define M_AGP2PLL 0x1E4C
662
663#define M_OPMODE 0x1E54
664#define M_OPMODE_DMA_GEN_WRITE 0x00
665#define M_OPMODE_DMA_BLIT 0x04
666#define M_OPMODE_DMA_VECTOR_WRITE 0x08
667#define M_OPMODE_DMA_LE 0x0000 /* little endian - no transformation */
668#define M_OPMODE_DMA_BE_8BPP 0x0000
669#define M_OPMODE_DMA_BE_16BPP 0x0100
670#define M_OPMODE_DMA_BE_32BPP 0x0200
671#define M_OPMODE_DIR_LE 0x000000 /* little endian - no transformation */
672#define M_OPMODE_DIR_BE_8BPP 0x000000
673#define M_OPMODE_DIR_BE_16BPP 0x010000
674#define M_OPMODE_DIR_BE_32BPP 0x020000
675
676#define M_ATTR_INDEX 0x1FC0
677#define M_ATTR_DATA 0x1FC1
678
679#define M_MISC_REG 0x1FC2
680#define M_3C2_RD 0x1FC2
681
682#define M_SEQ_INDEX 0x1FC4
683#define M_SEQ_DATA 0x1FC5
684
685#define M_MISC_REG_READ 0x1FCC
686
687#define M_GRAPHICS_INDEX 0x1FCE
688#define M_GRAPHICS_DATA 0x1FCF
689
690#define M_CRTC_INDEX 0x1FD4
691
692#define M_ATTR_RESET 0x1FDA
693#define M_3DA_WR 0x1FDA
694#define M_INSTS1 0x1FDA
695
696#define M_EXTVGA_INDEX 0x1FDE
697#define M_EXTVGA_DATA 0x1FDF
698
699/* G200 only */
700#define M_SRCORG 0x2CB4
701#define M_DSTORG 0x2CB8
702
703#define M_RAMDAC_BASE 0x3C00
704
705/* fortunately, same on TVP3026 and MGA1064 */
706#define M_DAC_REG (M_RAMDAC_BASE+0)
707#define M_DAC_VAL (M_RAMDAC_BASE+1)
708#define M_PALETTE_MASK (M_RAMDAC_BASE+2)
709
710#define M_X_INDEX 0x00
711#define M_X_DATAREG 0x0A
712
713#define DAC_XGENIOCTRL 0x2A
714#define DAC_XGENIODATA 0x2B
715
716#define M_C2CTL 0x3C10
717
718#define MX_OPTION_BSWAP 0x00000000
719
720#ifdef __LITTLE_ENDIAN
721#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
722#define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
723#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
724#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
725#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
726#else
727#ifdef __BIG_ENDIAN
728#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) /* TODO */
729#define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT)
730#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT)
731#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) /* TODO, ?32 */
732#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT)
733#else
734#error "Byte ordering have to be defined. Cannot continue."
735#endif
736#endif
737
738#define mga_inb(addr) mga_readb(ACCESS_FBINFO(mmio.vbase), (addr))
739#define mga_inl(addr) mga_readl(ACCESS_FBINFO(mmio.vbase), (addr))
740#define mga_outb(addr,val) mga_writeb(ACCESS_FBINFO(mmio.vbase), (addr), (val))
741#define mga_outw(addr,val) mga_writew(ACCESS_FBINFO(mmio.vbase), (addr), (val))
742#define mga_outl(addr,val) mga_writel(ACCESS_FBINFO(mmio.vbase), (addr), (val))
743#define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1))
744#define mga_setr(addr,port,val) mga_outw(addr, ((val)<<8) | (port))
745
746#define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
747
748#define WaitTillIdle() do {} while (mga_inl(M_STATUS) & 0x10000)
749
750/* code speedup */
751#ifdef CONFIG_FB_MATROX_MILLENIUM
752#define isInterleave(x) (x->interleave)
753#define isMillenium(x) (x->millenium)
754#define isMilleniumII(x) (x->milleniumII)
755#else
756#define isInterleave(x) (0)
757#define isMillenium(x) (0)
758#define isMilleniumII(x) (0)
759#endif
760
761#define matroxfb_DAC_lock() spin_lock(&ACCESS_FBINFO(lock.DAC))
762#define matroxfb_DAC_unlock() spin_unlock(&ACCESS_FBINFO(lock.DAC))
763#define matroxfb_DAC_lock_irqsave(flags) spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC),flags)
764#define matroxfb_DAC_unlock_irqrestore(flags) spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC),flags)
765extern void matroxfb_DAC_out(CPMINFO int reg, int val);
766extern int matroxfb_DAC_in(CPMINFO int reg);
767extern void matroxfb_var2my(struct fb_var_screeninfo* fvsi, struct my_timming* mt);
768extern int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc);
769extern int matroxfb_enable_irq(WPMINFO int reenable);
770
771#ifdef MATROXFB_USE_SPINLOCKS
772#define CRITBEGIN spin_lock_irqsave(&ACCESS_FBINFO(lock.accel), critflags);
773#define CRITEND spin_unlock_irqrestore(&ACCESS_FBINFO(lock.accel), critflags);
774#define CRITFLAGS unsigned long critflags;
775#else
776#define CRITBEGIN
777#define CRITEND
778#define CRITFLAGS
779#endif
780
781#endif /* __MATROXFB_H__ */
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
new file mode 100644
index 000000000000..429047ac615a
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -0,0 +1,741 @@
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 */
12
13#include "matroxfb_maven.h"
14#include "matroxfb_crtc2.h"
15#include "matroxfb_misc.h"
16#include "matroxfb_DAC1064.h"
17#include <linux/matroxfb.h>
18#include <asm/uaccess.h>
19
20/* **************************************************** */
21
22static int mem = 8192;
23
24module_param(mem, int, 0);
25MODULE_PARM_DESC(mem, "Memory size reserved for dualhead (default=8MB)");
26
27/* **************************************************** */
28
29static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
30 unsigned blue, unsigned transp, struct fb_info* info) {
31 u_int32_t col;
32#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
33
34 if (regno >= 16)
35 return 1;
36 if (m2info->fbcon.var.grayscale) {
37 /* gray = 0.30*R + 0.59*G + 0.11*B */
38 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
39 }
40 red = CNVT_TOHW(red, m2info->fbcon.var.red.length);
41 green = CNVT_TOHW(green, m2info->fbcon.var.green.length);
42 blue = CNVT_TOHW(blue, m2info->fbcon.var.blue.length);
43 transp = CNVT_TOHW(transp, m2info->fbcon.var.transp.length);
44
45 col = (red << m2info->fbcon.var.red.offset) |
46 (green << m2info->fbcon.var.green.offset) |
47 (blue << m2info->fbcon.var.blue.offset) |
48 (transp << m2info->fbcon.var.transp.offset);
49
50 switch (m2info->fbcon.var.bits_per_pixel) {
51 case 16:
52 m2info->cmap[regno] = col | (col << 16);
53 break;
54 case 32:
55 m2info->cmap[regno] = col;
56 break;
57 }
58 return 0;
59#undef m2info
60}
61
62static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
63 struct my_timming* mt,
64 int mode,
65 unsigned int pos) {
66 u_int32_t tmp;
67 u_int32_t datactl;
68 MINFO_FROM(m2info->primary_dev);
69
70 switch (mode) {
71 case 15:
72 tmp = 0x00200000;
73 break;
74 case 16:
75 tmp = 0x00400000;
76 break;
77/* case 32: */
78 default:
79 tmp = 0x00800000;
80 break;
81 }
82 tmp |= 0x00000001; /* enable CRTC2 */
83 datactl = 0;
84 if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
85 if (ACCESS_FBINFO(devflags.g450dac)) {
86 tmp |= 0x00000006; /* source from secondary pixel PLL */
87 /* no vidrst when in monitor mode */
88 if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
89 tmp |= 0xC0001000; /* Enable H/V vidrst */
90 }
91 } else {
92 tmp |= 0x00000002; /* source from VDOCLK */
93 tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
94 /* MGA TVO is our clock source */
95 }
96 } else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
97 tmp |= 0x00000004; /* source from pixclock */
98 /* PIXPLL is our clock source */
99 }
100 if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
101 tmp |= 0x00100000; /* connect CRTC2 to DAC */
102 }
103 if (mt->interlaced) {
104 tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */
105 mt->VDisplay >>= 1;
106 mt->VSyncStart >>= 1;
107 mt->VSyncEnd >>= 1;
108 mt->VTotal >>= 1;
109 }
110 if ((mt->HTotal & 7) == 2) {
111 datactl |= 0x00000010;
112 mt->HTotal &= ~7;
113 }
114 tmp |= 0x10000000; /* 0x10000000 is VIDRST polarity */
115 mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8));
116 mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
117 mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
118 mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
119 mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */
120 {
121 u_int32_t linelen = m2info->fbcon.var.xres_virtual * (m2info->fbcon.var.bits_per_pixel >> 3);
122 if (tmp & 0x02000000) {
123 /* field #0 is smaller, so... */
124 mga_outl(0x3C2C, pos); /* field #1 vmemory start */
125 mga_outl(0x3C28, pos + linelen); /* field #0 vmemory start */
126 linelen <<= 1;
127 m2info->interlaced = 1;
128 } else {
129 mga_outl(0x3C28, pos); /* vmemory start */
130 m2info->interlaced = 0;
131 }
132 mga_outl(0x3C40, linelen);
133 }
134 mga_outl(0x3C4C, datactl); /* data control */
135 if (tmp & 0x02000000) {
136 int i;
137
138 mga_outl(0x3C10, tmp & ~0x02000000);
139 for (i = 0; i < 2; i++) {
140 unsigned int nl;
141 unsigned int lastl = 0;
142
143 while ((nl = mga_inl(0x3C48) & 0xFFF) >= lastl) {
144 lastl = nl;
145 }
146 }
147 }
148 mga_outl(0x3C10, tmp);
149 ACCESS_FBINFO(hw).crtc2.ctl = tmp;
150
151 tmp = mt->VDisplay << 16; /* line compare */
152 if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
153 tmp |= 0x00000100;
154 if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
155 tmp |= 0x00000200;
156 mga_outl(0x3C44, tmp);
157}
158
159static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
160 MINFO_FROM(m2info->primary_dev);
161
162 mga_outl(0x3C10, 0x00000004); /* disable CRTC2, CRTC1->DAC1, PLL as clock source */
163 ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004;
164}
165
166static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) {
167 /* no acceleration for secondary head... */
168 m2info->cmap[16] = 0xFFFFFFFF;
169}
170
171static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info,
172 struct fb_var_screeninfo* var) {
173 unsigned int pos;
174 unsigned int linelen;
175 unsigned int pixelsize;
176 MINFO_FROM(m2info->primary_dev);
177
178 m2info->fbcon.var.xoffset = var->xoffset;
179 m2info->fbcon.var.yoffset = var->yoffset;
180 pixelsize = m2info->fbcon.var.bits_per_pixel >> 3;
181 linelen = m2info->fbcon.var.xres_virtual * pixelsize;
182 pos = m2info->fbcon.var.yoffset * linelen + m2info->fbcon.var.xoffset * pixelsize;
183 pos += m2info->video.offbase;
184 if (m2info->interlaced) {
185 mga_outl(0x3C2C, pos);
186 mga_outl(0x3C28, pos + linelen);
187 } else {
188 mga_outl(0x3C28, pos);
189 }
190}
191
192static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
193 struct fb_var_screeninfo* var,
194 int *visual,
195 int *video_cmap_len,
196 int *mode) {
197 unsigned int mask;
198 unsigned int memlen;
199 unsigned int vramlen;
200
201 switch (var->bits_per_pixel) {
202 case 16: mask = 0x1F;
203 break;
204 case 32: mask = 0x0F;
205 break;
206 default: return -EINVAL;
207 }
208 vramlen = m2info->video.len_usable;
209 if (var->yres_virtual < var->yres)
210 var->yres_virtual = var->yres;
211 if (var->xres_virtual < var->xres)
212 var->xres_virtual = var->xres;
213 var->xres_virtual = (var->xres_virtual + mask) & ~mask;
214 if (var->yres_virtual > 32767)
215 return -EINVAL;
216 memlen = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel >> 3);
217 if (memlen > vramlen)
218 return -EINVAL;
219 if (var->xoffset + var->xres > var->xres_virtual)
220 var->xoffset = var->xres_virtual - var->xres;
221 if (var->yoffset + var->yres > var->yres_virtual)
222 var->yoffset = var->yres_virtual - var->yres;
223
224 var->xres &= ~7;
225 var->left_margin &= ~7;
226 var->right_margin &= ~7;
227 var->hsync_len &= ~7;
228
229 *mode = var->bits_per_pixel;
230 if (var->bits_per_pixel == 16) {
231 if (var->green.length == 5) {
232 var->red.offset = 10;
233 var->red.length = 5;
234 var->green.offset = 5;
235 var->green.length = 5;
236 var->blue.offset = 0;
237 var->blue.length = 5;
238 var->transp.offset = 15;
239 var->transp.length = 1;
240 *mode = 15;
241 } else {
242 var->red.offset = 11;
243 var->red.length = 5;
244 var->green.offset = 5;
245 var->green.length = 6;
246 var->blue.offset = 0;
247 var->blue.length = 5;
248 var->transp.offset = 0;
249 var->transp.length = 0;
250 }
251 } else {
252 var->red.offset = 16;
253 var->red.length = 8;
254 var->green.offset = 8;
255 var->green.length = 8;
256 var->blue.offset = 0;
257 var->blue.length = 8;
258 var->transp.offset = 24;
259 var->transp.length = 8;
260 }
261 *visual = FB_VISUAL_TRUECOLOR;
262 *video_cmap_len = 16;
263 return 0;
264}
265
266static int matroxfb_dh_open(struct fb_info* info, int user) {
267#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
268 MINFO_FROM(m2info->primary_dev);
269
270 if (MINFO) {
271 int err;
272
273 if (ACCESS_FBINFO(dead)) {
274 return -ENXIO;
275 }
276 err = ACCESS_FBINFO(fbops).fb_open(&ACCESS_FBINFO(fbcon), user);
277 if (err) {
278 return err;
279 }
280 }
281 return 0;
282#undef m2info
283}
284
285static int matroxfb_dh_release(struct fb_info* info, int user) {
286#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
287 int err = 0;
288 MINFO_FROM(m2info->primary_dev);
289
290 if (MINFO) {
291 err = ACCESS_FBINFO(fbops).fb_release(&ACCESS_FBINFO(fbcon), user);
292 }
293 return err;
294#undef m2info
295}
296
297static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) {
298 struct fb_fix_screeninfo *fix = &m2info->fbcon.fix;
299
300 strcpy(fix->id, "MATROX DH");
301
302 fix->smem_start = m2info->video.base;
303 fix->smem_len = m2info->video.len_usable;
304 fix->ypanstep = 1;
305 fix->ywrapstep = 0;
306 fix->xpanstep = 8; /* TBD */
307 fix->mmio_start = m2info->mmio.base;
308 fix->mmio_len = m2info->mmio.len;
309 fix->accel = 0; /* no accel... */
310}
311
312static int matroxfb_dh_check_var(struct fb_var_screeninfo* var, struct fb_info* info) {
313#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
314 int visual;
315 int cmap_len;
316 int mode;
317
318 return matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode);
319#undef m2info
320}
321
322static int matroxfb_dh_set_par(struct fb_info* info) {
323#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
324 int visual;
325 int cmap_len;
326 int mode;
327 int err;
328 struct fb_var_screeninfo* var = &info->var;
329 MINFO_FROM(m2info->primary_dev);
330
331 if ((err = matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode)) != 0)
332 return err;
333 /* cmap */
334 {
335 m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
336 m2info->fbcon.fix.visual = visual;
337 m2info->fbcon.fix.type = FB_TYPE_PACKED_PIXELS;
338 m2info->fbcon.fix.type_aux = 0;
339 m2info->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
340 }
341 {
342 struct my_timming mt;
343 unsigned int pos;
344 int out;
345 int cnt;
346
347 matroxfb_var2my(&m2info->fbcon.var, &mt);
348 mt.crtc = MATROXFB_SRC_CRTC2;
349 /* CRTC2 delay */
350 mt.delay = 34;
351
352 pos = (m2info->fbcon.var.yoffset * m2info->fbcon.var.xres_virtual + m2info->fbcon.var.xoffset) * m2info->fbcon.var.bits_per_pixel >> 3;
353 pos += m2info->video.offbase;
354 cnt = 0;
355 down_read(&ACCESS_FBINFO(altout).lock);
356 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
357 if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
358 cnt++;
359 if (ACCESS_FBINFO(outputs[out]).output->compute) {
360 ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
361 }
362 }
363 }
364 ACCESS_FBINFO(crtc2).pixclock = mt.pixclock;
365 ACCESS_FBINFO(crtc2).mnp = mt.mnp;
366 up_read(&ACCESS_FBINFO(altout).lock);
367 if (cnt) {
368 matroxfb_dh_restore(m2info, &mt, mode, pos);
369 } else {
370 matroxfb_dh_disable(m2info);
371 }
372 DAC1064_global_init(PMINFO2);
373 DAC1064_global_restore(PMINFO2);
374 down_read(&ACCESS_FBINFO(altout).lock);
375 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
376 if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
377 ACCESS_FBINFO(outputs[out]).output->program) {
378 ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
379 }
380 }
381 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
382 if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
383 ACCESS_FBINFO(outputs[out]).output->start) {
384 ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
385 }
386 }
387 up_read(&ACCESS_FBINFO(altout).lock);
388 matroxfb_dh_cfbX_init(m2info);
389 }
390 m2info->initialized = 1;
391 return 0;
392#undef m2info
393}
394
395static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, struct fb_info* info) {
396#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
397 matroxfb_dh_pan_var(m2info, var);
398 return 0;
399#undef m2info
400}
401
402static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, struct fb_vblank* vblank) {
403 MINFO_FROM(m2info->primary_dev);
404
405 matroxfb_enable_irq(PMINFO 0);
406 memset(vblank, 0, sizeof(*vblank));
407 vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VBLANK;
408 /* mask out reserved bits + field number (odd/even) */
409 vblank->vcount = mga_inl(0x3C48) & 0x000007FF;
410 /* compatibility stuff */
411 if (vblank->vcount >= m2info->fbcon.var.yres)
412 vblank->flags |= FB_VBLANK_VBLANKING;
413 if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
414 vblank->flags |= FB_VBLANK_HAVE_COUNT;
415 /* Only one writer, aligned int value...
416 it should work without lock and without atomic_t */
417 vblank->count = ACCESS_FBINFO(crtc2).vsync.cnt;
418 }
419 return 0;
420}
421
422static int matroxfb_dh_ioctl(struct inode* inode,
423 struct file* file,
424 unsigned int cmd,
425 unsigned long arg,
426 struct fb_info* info) {
427#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
428 MINFO_FROM(m2info->primary_dev);
429
430 DBG(__FUNCTION__)
431
432 switch (cmd) {
433 case FBIOGET_VBLANK:
434 {
435 struct fb_vblank vblank;
436 int err;
437
438 err = matroxfb_dh_get_vblank(m2info, &vblank);
439 if (err)
440 return err;
441 if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
442 return -EFAULT;
443 return 0;
444 }
445 case FBIO_WAITFORVSYNC:
446 {
447 u_int32_t crt;
448
449 if (get_user(crt, (u_int32_t __user *)arg))
450 return -EFAULT;
451
452 if (crt != 0)
453 return -ENODEV;
454 return matroxfb_wait_for_sync(PMINFO 1);
455 }
456 case MATROXFB_SET_OUTPUT_MODE:
457 case MATROXFB_GET_OUTPUT_MODE:
458 case MATROXFB_GET_ALL_OUTPUTS:
459 {
460 return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, &ACCESS_FBINFO(fbcon));
461 }
462 case MATROXFB_SET_OUTPUT_CONNECTION:
463 {
464 u_int32_t tmp;
465 int out;
466 int changes;
467
468 if (get_user(tmp, (u_int32_t __user *)arg))
469 return -EFAULT;
470 for (out = 0; out < 32; out++) {
471 if (tmp & (1 << out)) {
472 if (out >= MATROXFB_MAX_OUTPUTS)
473 return -ENXIO;
474 if (!ACCESS_FBINFO(outputs[out]).output)
475 return -ENXIO;
476 switch (ACCESS_FBINFO(outputs[out]).src) {
477 case MATROXFB_SRC_NONE:
478 case MATROXFB_SRC_CRTC2:
479 break;
480 default:
481 return -EBUSY;
482 }
483 }
484 }
485 if (ACCESS_FBINFO(devflags.panellink)) {
486 if (tmp & MATROXFB_OUTPUT_CONN_DFP)
487 return -EINVAL;
488 if ((ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) && tmp)
489 return -EBUSY;
490 }
491 changes = 0;
492 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
493 if (tmp & (1 << out)) {
494 if (ACCESS_FBINFO(outputs[out]).src != MATROXFB_SRC_CRTC2) {
495 changes = 1;
496 ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_CRTC2;
497 }
498 } else if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
499 changes = 1;
500 ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_NONE;
501 }
502 }
503 if (!changes)
504 return 0;
505 matroxfb_dh_set_par(info);
506 return 0;
507 }
508 case MATROXFB_GET_OUTPUT_CONNECTION:
509 {
510 u_int32_t conn = 0;
511 int out;
512
513 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
514 if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
515 conn |= 1 << out;
516 }
517 }
518 if (put_user(conn, (u_int32_t __user *)arg))
519 return -EFAULT;
520 return 0;
521 }
522 case MATROXFB_GET_AVAILABLE_OUTPUTS:
523 {
524 u_int32_t tmp = 0;
525 int out;
526
527 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
528 if (ACCESS_FBINFO(outputs[out]).output) {
529 switch (ACCESS_FBINFO(outputs[out]).src) {
530 case MATROXFB_SRC_NONE:
531 case MATROXFB_SRC_CRTC2:
532 tmp |= 1 << out;
533 break;
534 }
535 }
536 }
537 if (ACCESS_FBINFO(devflags.panellink)) {
538 tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
539 if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) {
540 tmp = 0;
541 }
542 }
543 if (put_user(tmp, (u_int32_t __user *)arg))
544 return -EFAULT;
545 return 0;
546 }
547 }
548 return -ENOTTY;
549#undef m2info
550}
551
552static int matroxfb_dh_blank(int blank, struct fb_info* info) {
553#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
554 switch (blank) {
555 case 1:
556 case 2:
557 case 3:
558 case 4:
559 default:;
560 }
561 /* do something... */
562 return 0;
563#undef m2info
564}
565
566static struct fb_ops matroxfb_dh_ops = {
567 .owner = THIS_MODULE,
568 .fb_open = matroxfb_dh_open,
569 .fb_release = matroxfb_dh_release,
570 .fb_check_var = matroxfb_dh_check_var,
571 .fb_set_par = matroxfb_dh_set_par,
572 .fb_setcolreg = matroxfb_dh_setcolreg,
573 .fb_pan_display =matroxfb_dh_pan_display,
574 .fb_blank = matroxfb_dh_blank,
575 .fb_ioctl = matroxfb_dh_ioctl,
576 .fb_fillrect = cfb_fillrect,
577 .fb_copyarea = cfb_copyarea,
578 .fb_imageblit = cfb_imageblit,
579 .fb_cursor = soft_cursor,
580};
581
582static struct fb_var_screeninfo matroxfb_dh_defined = {
583 640,480,640,480,/* W,H, virtual W,H */
584 0,0, /* offset */
585 32, /* depth */
586 0, /* gray */
587 {0,0,0}, /* R */
588 {0,0,0}, /* G */
589 {0,0,0}, /* B */
590 {0,0,0}, /* alpha */
591 0, /* nonstd */
592 FB_ACTIVATE_NOW,
593 -1,-1, /* display size */
594 0, /* accel flags */
595 39721L,48L,16L,33L,10L,
596 96L,2,0, /* no sync info */
597 FB_VMODE_NONINTERLACED,
598 0, {0,0,0,0,0}
599};
600
601static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) {
602#define minfo (m2info->primary_dev)
603 void* oldcrtc2;
604
605 m2info->fbcon.fbops = &matroxfb_dh_ops;
606 m2info->fbcon.flags = FBINFO_FLAG_DEFAULT;
607 m2info->fbcon.flags |= FBINFO_HWACCEL_XPAN |
608 FBINFO_HWACCEL_YPAN;
609 m2info->fbcon.pseudo_palette = m2info->cmap;
610 fb_alloc_cmap(&m2info->fbcon.cmap, 256, 1);
611
612 if (mem < 64)
613 mem *= 1024;
614 if (mem < 64*1024)
615 mem *= 1024;
616 mem &= ~0x00000FFF; /* PAGE_MASK? */
617 if (ACCESS_FBINFO(video.len_usable) + mem <= ACCESS_FBINFO(video.len))
618 m2info->video.offbase = ACCESS_FBINFO(video.len) - mem;
619 else if (ACCESS_FBINFO(video.len) < mem) {
620 return -ENOMEM;
621 } else { /* check yres on first head... */
622 m2info->video.borrowed = mem;
623 ACCESS_FBINFO(video.len_usable) -= mem;
624 m2info->video.offbase = ACCESS_FBINFO(video.len_usable);
625 }
626 m2info->video.base = ACCESS_FBINFO(video.base) + m2info->video.offbase;
627 m2info->video.len = m2info->video.len_usable = m2info->video.len_maximum = mem;
628 m2info->video.vbase.vaddr = vaddr_va(ACCESS_FBINFO(video.vbase)) + m2info->video.offbase;
629 m2info->mmio.base = ACCESS_FBINFO(mmio.base);
630 m2info->mmio.vbase = ACCESS_FBINFO(mmio.vbase);
631 m2info->mmio.len = ACCESS_FBINFO(mmio.len);
632
633 matroxfb_dh_init_fix(m2info);
634 if (register_framebuffer(&m2info->fbcon)) {
635 return -ENXIO;
636 }
637 if (!m2info->initialized)
638 fb_set_var(&m2info->fbcon, &matroxfb_dh_defined);
639 down_write(&ACCESS_FBINFO(crtc2.lock));
640 oldcrtc2 = ACCESS_FBINFO(crtc2.info);
641 ACCESS_FBINFO(crtc2.info) = m2info;
642 up_write(&ACCESS_FBINFO(crtc2.lock));
643 if (oldcrtc2) {
644 printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n",
645 oldcrtc2);
646 }
647 return 0;
648#undef minfo
649}
650
651/* ************************** */
652
653static int matroxfb_dh_registerfb(struct matroxfb_dh_fb_info* m2info) {
654#define minfo (m2info->primary_dev)
655 if (matroxfb_dh_regit(PMINFO m2info)) {
656 printk(KERN_ERR "matroxfb_crtc2: secondary head failed to register\n");
657 return -1;
658 }
659 printk(KERN_INFO "matroxfb_crtc2: secondary head of fb%u was registered as fb%u\n",
660 ACCESS_FBINFO(fbcon.node), m2info->fbcon.node);
661 m2info->fbcon_registered = 1;
662 return 0;
663#undef minfo
664}
665
666static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info* m2info) {
667#define minfo (m2info->primary_dev)
668 if (m2info->fbcon_registered) {
669 int id;
670 struct matroxfb_dh_fb_info* crtc2;
671
672 down_write(&ACCESS_FBINFO(crtc2.lock));
673 crtc2 = ACCESS_FBINFO(crtc2.info);
674 if (crtc2 == m2info)
675 ACCESS_FBINFO(crtc2.info) = NULL;
676 up_write(&ACCESS_FBINFO(crtc2.lock));
677 if (crtc2 != m2info) {
678 printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n",
679 crtc2, m2info);
680 printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n");
681 return;
682 }
683 id = m2info->fbcon.node;
684 unregister_framebuffer(&m2info->fbcon);
685 /* return memory back to primary head */
686 ACCESS_FBINFO(video.len_usable) += m2info->video.borrowed;
687 printk(KERN_INFO "matroxfb_crtc2: fb%u unregistered\n", id);
688 m2info->fbcon_registered = 0;
689 }
690#undef minfo
691}
692
693static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) {
694 struct matroxfb_dh_fb_info* m2info;
695
696 /* hardware is CRTC2 incapable... */
697 if (!ACCESS_FBINFO(devflags.crtc2))
698 return NULL;
699 m2info = (struct matroxfb_dh_fb_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
700 if (!m2info) {
701 printk(KERN_ERR "matroxfb_crtc2: Not enough memory for CRTC2 control structs\n");
702 return NULL;
703 }
704 memset(m2info, 0, sizeof(*m2info));
705 m2info->primary_dev = MINFO;
706 if (matroxfb_dh_registerfb(m2info)) {
707 kfree(m2info);
708 printk(KERN_ERR "matroxfb_crtc2: CRTC2 framebuffer failed to register\n");
709 return NULL;
710 }
711 return m2info;
712}
713
714static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) {
715 matroxfb_dh_deregisterfb(crtc2);
716 kfree(crtc2);
717}
718
719static struct matroxfb_driver crtc2 = {
720 .name = "Matrox G400 CRTC2",
721 .probe = matroxfb_crtc2_probe,
722 .remove = matroxfb_crtc2_remove };
723
724static int matroxfb_crtc2_init(void) {
725 if (fb_get_options("matrox_crtc2fb", NULL))
726 return -ENODEV;
727
728 matroxfb_register_driver(&crtc2);
729 return 0;
730}
731
732static void matroxfb_crtc2_exit(void) {
733 matroxfb_unregister_driver(&crtc2);
734}
735
736MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
737MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
738MODULE_LICENSE("GPL");
739module_init(matroxfb_crtc2_init);
740module_exit(matroxfb_crtc2_exit);
741/* we do not have __setup() yet */
diff --git a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h
new file mode 100644
index 000000000000..608e40bb20e9
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_crtc2.h
@@ -0,0 +1,36 @@
1#ifndef __MATROXFB_CRTC2_H__
2#define __MATROXFB_CRTC2_H__
3
4#include <linux/ioctl.h>
5#include <linux/i2c.h>
6#include <linux/i2c-algo-bit.h>
7#include "matroxfb_base.h"
8
9struct matroxfb_dh_fb_info {
10 struct fb_info fbcon;
11 int fbcon_registered;
12 int initialized;
13
14 struct matrox_fb_info* primary_dev;
15
16 struct {
17 unsigned long base; /* physical */
18 vaddr_t vbase; /* virtual */
19 unsigned int len;
20 unsigned int len_usable;
21 unsigned int len_maximum;
22 unsigned int offbase;
23 unsigned int borrowed;
24 } video;
25 struct {
26 unsigned long base;
27 vaddr_t vbase;
28 unsigned int len;
29 } mmio;
30
31 unsigned int interlaced:1;
32
33 u_int32_t cmap[17];
34};
35
36#endif /* __MATROXFB_CRTC2_H__ */
diff --git a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c
new file mode 100644
index 000000000000..35008af7db75
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_g450.c
@@ -0,0 +1,626 @@
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
15#include "matroxfb_base.h"
16#include "matroxfb_misc.h"
17#include "matroxfb_DAC1064.h"
18#include "g450_pll.h"
19#include <linux/matroxfb.h>
20#include <asm/uaccess.h>
21#include <asm/div64.h>
22
23/* Definition of the various controls */
24struct mctl {
25 struct v4l2_queryctrl desc;
26 size_t control;
27};
28
29#define BLMIN 0xF3
30#define WLMAX 0x3FF
31
32static const struct mctl g450_controls[] =
33{ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
34 "brightness",
35 0, WLMAX-BLMIN, 1, 370-BLMIN,
36 0,
37 }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
38 { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
39 "contrast",
40 0, 1023, 1, 127,
41 0,
42 }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
43 { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
44 "saturation",
45 0, 255, 1, 165,
46 0,
47 }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
48 { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
49 "hue",
50 0, 255, 1, 0,
51 0,
52 }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
53 { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
54 "test output",
55 0, 1, 1, 0,
56 0,
57 }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
58};
59
60#define G450CTRLS (sizeof(g450_controls)/sizeof(g450_controls[0]))
61
62/* Return: positive number: id found
63 -EINVAL: id not found, return failure
64 -ENOENT: id not found, create fake disabled control */
65static int get_ctrl_id(__u32 v4l2_id) {
66 int i;
67
68 for (i = 0; i < G450CTRLS; i++) {
69 if (v4l2_id < g450_controls[i].desc.id) {
70 if (g450_controls[i].desc.id == 0x08000000) {
71 return -EINVAL;
72 }
73 return -ENOENT;
74 }
75 if (v4l2_id == g450_controls[i].desc.id) {
76 return i;
77 }
78 }
79 return -EINVAL;
80}
81
82static inline int* get_ctrl_ptr(WPMINFO unsigned int idx) {
83 return (int*)((char*)MINFO + g450_controls[idx].control);
84}
85
86static void tvo_fill_defaults(WPMINFO2) {
87 unsigned int i;
88
89 for (i = 0; i < G450CTRLS; i++) {
90 *get_ctrl_ptr(PMINFO i) = g450_controls[i].desc.default_value;
91 }
92}
93
94static int cve2_get_reg(WPMINFO int reg) {
95 unsigned long flags;
96 int val;
97
98 matroxfb_DAC_lock_irqsave(flags);
99 matroxfb_DAC_out(PMINFO 0x87, reg);
100 val = matroxfb_DAC_in(PMINFO 0x88);
101 matroxfb_DAC_unlock_irqrestore(flags);
102 return val;
103}
104
105static void cve2_set_reg(WPMINFO int reg, int val) {
106 unsigned long flags;
107
108 matroxfb_DAC_lock_irqsave(flags);
109 matroxfb_DAC_out(PMINFO 0x87, reg);
110 matroxfb_DAC_out(PMINFO 0x88, val);
111 matroxfb_DAC_unlock_irqrestore(flags);
112}
113
114static void cve2_set_reg10(WPMINFO int reg, int val) {
115 unsigned long flags;
116
117 matroxfb_DAC_lock_irqsave(flags);
118 matroxfb_DAC_out(PMINFO 0x87, reg);
119 matroxfb_DAC_out(PMINFO 0x88, val >> 2);
120 matroxfb_DAC_out(PMINFO 0x87, reg + 1);
121 matroxfb_DAC_out(PMINFO 0x88, val & 3);
122 matroxfb_DAC_unlock_irqrestore(flags);
123}
124
125static void g450_compute_bwlevel(CPMINFO int *bl, int *wl) {
126 const int b = ACCESS_FBINFO(altout.tvo_params.brightness) + BLMIN;
127 const int c = ACCESS_FBINFO(altout.tvo_params.contrast);
128
129 *bl = max(b - c, BLMIN);
130 *wl = min(b + c, WLMAX);
131}
132
133static int g450_query_ctrl(void* md, struct v4l2_queryctrl *p) {
134 int i;
135
136 i = get_ctrl_id(p->id);
137 if (i >= 0) {
138 *p = g450_controls[i].desc;
139 return 0;
140 }
141 if (i == -ENOENT) {
142 static const struct v4l2_queryctrl disctrl =
143 { .flags = V4L2_CTRL_FLAG_DISABLED };
144
145 i = p->id;
146 *p = disctrl;
147 p->id = i;
148 sprintf(p->name, "Ctrl #%08X", i);
149 return 0;
150 }
151 return -EINVAL;
152}
153
154static int g450_set_ctrl(void* md, struct v4l2_control *p) {
155 int i;
156 MINFO_FROM(md);
157
158 i = get_ctrl_id(p->id);
159 if (i < 0) return -EINVAL;
160
161 /*
162 * Check if changed.
163 */
164 if (p->value == *get_ctrl_ptr(PMINFO i)) return 0;
165
166 /*
167 * Check limits.
168 */
169 if (p->value > g450_controls[i].desc.maximum) return -EINVAL;
170 if (p->value < g450_controls[i].desc.minimum) return -EINVAL;
171
172 /*
173 * Store new value.
174 */
175 *get_ctrl_ptr(PMINFO i) = p->value;
176
177 switch (p->id) {
178 case V4L2_CID_BRIGHTNESS:
179 case V4L2_CID_CONTRAST:
180 {
181 int blacklevel, whitelevel;
182 g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel);
183 cve2_set_reg10(PMINFO 0x0e, blacklevel);
184 cve2_set_reg10(PMINFO 0x1e, whitelevel);
185 }
186 break;
187 case V4L2_CID_SATURATION:
188 cve2_set_reg(PMINFO 0x20, p->value);
189 cve2_set_reg(PMINFO 0x22, p->value);
190 break;
191 case V4L2_CID_HUE:
192 cve2_set_reg(PMINFO 0x25, p->value);
193 break;
194 case MATROXFB_CID_TESTOUT:
195 {
196 unsigned char val = cve2_get_reg (PMINFO 0x05);
197 if (p->value) val |= 0x02;
198 else val &= ~0x02;
199 cve2_set_reg(PMINFO 0x05, val);
200 }
201 break;
202 }
203
204
205 return 0;
206}
207
208static int g450_get_ctrl(void* md, struct v4l2_control *p) {
209 int i;
210 MINFO_FROM(md);
211
212 i = get_ctrl_id(p->id);
213 if (i < 0) return -EINVAL;
214 p->value = *get_ctrl_ptr(PMINFO i);
215 return 0;
216}
217
218struct output_desc {
219 unsigned int h_vis;
220 unsigned int h_f_porch;
221 unsigned int h_sync;
222 unsigned int h_b_porch;
223 unsigned long long int chromasc;
224 unsigned int burst;
225 unsigned int v_total;
226};
227
228static void computeRegs(WPMINFO struct mavenregs* r, struct my_timming* mt, const struct output_desc* outd) {
229 u_int32_t chromasc;
230 u_int32_t hlen;
231 u_int32_t hsl;
232 u_int32_t hbp;
233 u_int32_t hfp;
234 u_int32_t hvis;
235 unsigned int pixclock;
236 unsigned long long piic;
237 int mnp;
238 int over;
239
240 r->regs[0x80] = 0x03; /* | 0x40 for SCART */
241
242 hvis = ((mt->HDisplay << 1) + 3) & ~3;
243
244 if (hvis >= 2048) {
245 hvis = 2044;
246 }
247
248 piic = 1000000000ULL * hvis;
249 do_div(piic, outd->h_vis);
250
251 dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic);
252
253 mnp = matroxfb_g450_setclk(PMINFO piic, M_VIDEO_PLL);
254
255 mt->mnp = mnp;
256 mt->pixclock = g450_mnp2f(PMINFO mnp);
257
258 dprintk(KERN_DEBUG "MNP=%08X\n", mnp);
259
260 pixclock = 1000000000U / mt->pixclock;
261
262 dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock);
263
264 piic = outd->chromasc;
265 do_div(piic, mt->pixclock);
266 chromasc = piic;
267
268 dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc);
269
270 r->regs[0] = piic >> 24;
271 r->regs[1] = piic >> 16;
272 r->regs[2] = piic >> 8;
273 r->regs[3] = piic >> 0;
274 hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1;
275 hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1;
276 hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1;
277 hlen = hvis + hfp + hsl + hbp;
278 over = hlen & 0x0F;
279
280 dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen);
281
282 if (over) {
283 hfp -= over;
284 hlen -= over;
285 if (over <= 2) {
286 } else if (over < 10) {
287 hfp += 4;
288 hlen += 4;
289 } else {
290 hfp += 16;
291 hlen += 16;
292 }
293 }
294
295 /* maybe cve2 has requirement 800 < hlen < 1184 */
296 r->regs[0x08] = hsl;
297 r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock; /* burst length */
298 r->regs[0x0A] = hbp;
299 r->regs[0x2C] = hfp;
300 r->regs[0x31] = hvis / 8;
301 r->regs[0x32] = hvis & 7;
302
303 dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen);
304
305 r->regs[0x84] = 1; /* x sync point */
306 r->regs[0x85] = 0;
307 hvis = hvis >> 1;
308 hlen = hlen >> 1;
309
310 dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis);
311
312 mt->interlaced = 1;
313
314 mt->HDisplay = hvis & ~7;
315 mt->HSyncStart = mt->HDisplay + 8;
316 mt->HSyncEnd = (hlen & ~7) - 8;
317 mt->HTotal = hlen;
318
319 {
320 int upper;
321 unsigned int vtotal;
322 unsigned int vsyncend;
323 unsigned int vdisplay;
324
325 vtotal = mt->VTotal;
326 vsyncend = mt->VSyncEnd;
327 vdisplay = mt->VDisplay;
328 if (vtotal < outd->v_total) {
329 unsigned int yovr = outd->v_total - vtotal;
330
331 vsyncend += yovr >> 1;
332 } else if (vtotal > outd->v_total) {
333 vdisplay = outd->v_total - 4;
334 vsyncend = outd->v_total;
335 }
336 upper = (outd->v_total - vsyncend) >> 1; /* in field lines */
337 r->regs[0x17] = outd->v_total / 4;
338 r->regs[0x18] = outd->v_total & 3;
339 r->regs[0x33] = upper - 1; /* upper blanking */
340 r->regs[0x82] = upper; /* y sync point */
341 r->regs[0x83] = upper >> 8;
342
343 mt->VDisplay = vdisplay;
344 mt->VSyncStart = outd->v_total - 2;
345 mt->VSyncEnd = outd->v_total;
346 mt->VTotal = outd->v_total;
347 }
348}
349
350static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
351 static const struct output_desc paloutd = {
352 .h_vis = 52148148, // ps
353 .h_f_porch = 1407407, // ps
354 .h_sync = 4666667, // ps
355 .h_b_porch = 5777778, // ps
356 .chromasc = 19042247534182ULL, // 4433618.750 Hz
357 .burst = 2518518, // ps
358 .v_total = 625,
359 };
360 static const struct output_desc ntscoutd = {
361 .h_vis = 52888889, // ps
362 .h_f_porch = 1333333, // ps
363 .h_sync = 4666667, // ps
364 .h_b_porch = 4666667, // ps
365 .chromasc = 15374030659475ULL, // 3579545.454 Hz
366 .burst = 2418418, // ps
367 .v_total = 525, // lines
368 };
369
370 static const struct mavenregs palregs = { {
371 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
372 0x00,
373 0x00, /* test */
374 0xF9, /* modified by code (F9 written...) */
375 0x00, /* ? not written */
376 0x7E, /* 08 */
377 0x44, /* 09 */
378 0x9C, /* 0A */
379 0x2E, /* 0B */
380 0x21, /* 0C */
381 0x00, /* ? not written */
382// 0x3F, 0x03, /* 0E-0F */
383 0x3C, 0x03,
384 0x3C, 0x03, /* 10-11 */
385 0x1A, /* 12 */
386 0x2A, /* 13 */
387 0x1C, 0x3D, 0x14, /* 14-16 */
388 0x9C, 0x01, /* 17-18 */
389 0x00, /* 19 */
390 0xFE, /* 1A */
391 0x7E, /* 1B */
392 0x60, /* 1C */
393 0x05, /* 1D */
394// 0x89, 0x03, /* 1E-1F */
395 0xAD, 0x03,
396// 0x72, /* 20 */
397 0xA5,
398 0x07, /* 21 */
399// 0x72, /* 22 */
400 0xA5,
401 0x00, /* 23 */
402 0x00, /* 24 */
403 0x00, /* 25 */
404 0x08, /* 26 */
405 0x04, /* 27 */
406 0x00, /* 28 */
407 0x1A, /* 29 */
408 0x55, 0x01, /* 2A-2B */
409 0x26, /* 2C */
410 0x07, 0x7E, /* 2D-2E */
411 0x02, 0x54, /* 2F-30 */
412 0xB0, 0x00, /* 31-32 */
413 0x14, /* 33 */
414 0x49, /* 34 */
415 0x00, /* 35 written multiple times */
416 0x00, /* 36 not written */
417 0xA3, /* 37 */
418 0xC8, /* 38 */
419 0x22, /* 39 */
420 0x02, /* 3A */
421 0x22, /* 3B */
422 0x3F, 0x03, /* 3C-3D */
423 0x00, /* 3E written multiple times */
424 0x00, /* 3F not written */
425 } };
426 static struct mavenregs ntscregs = { {
427 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
428 0x00,
429 0x00, /* test */
430 0xF9, /* modified by code (F9 written...) */
431 0x00, /* ? not written */
432 0x7E, /* 08 */
433 0x43, /* 09 */
434 0x7E, /* 0A */
435 0x3D, /* 0B */
436 0x00, /* 0C */
437 0x00, /* ? not written */
438 0x41, 0x00, /* 0E-0F */
439 0x3C, 0x00, /* 10-11 */
440 0x17, /* 12 */
441 0x21, /* 13 */
442 0x1B, 0x1B, 0x24, /* 14-16 */
443 0x83, 0x01, /* 17-18 */
444 0x00, /* 19 */
445 0x0F, /* 1A */
446 0x0F, /* 1B */
447 0x60, /* 1C */
448 0x05, /* 1D */
449 //0x89, 0x02, /* 1E-1F */
450 0xC0, 0x02, /* 1E-1F */
451 //0x5F, /* 20 */
452 0x9C, /* 20 */
453 0x04, /* 21 */
454 //0x5F, /* 22 */
455 0x9C, /* 22 */
456 0x01, /* 23 */
457 0x02, /* 24 */
458 0x00, /* 25 */
459 0x0A, /* 26 */
460 0x05, /* 27 */
461 0x00, /* 28 */
462 0x10, /* 29 */
463 0xFF, 0x03, /* 2A-2B */
464 0x24, /* 2C */
465 0x0F, 0x78, /* 2D-2E */
466 0x00, 0x00, /* 2F-30 */
467 0xB2, 0x04, /* 31-32 */
468 0x14, /* 33 */
469 0x02, /* 34 */
470 0x00, /* 35 written multiple times */
471 0x00, /* 36 not written */
472 0xA3, /* 37 */
473 0xC8, /* 38 */
474 0x15, /* 39 */
475 0x05, /* 3A */
476 0x3B, /* 3B */
477 0x3C, 0x00, /* 3C-3D */
478 0x00, /* 3E written multiple times */
479 0x00, /* never written */
480 } };
481
482 if (norm == MATROXFB_OUTPUT_MODE_PAL) {
483 *data = palregs;
484 *outd = &paloutd;
485 } else {
486 *data = ntscregs;
487 *outd = &ntscoutd;
488 }
489 return;
490}
491
492#define LR(x) cve2_set_reg(PMINFO (x), m->regs[(x)])
493static void cve2_init_TV(WPMINFO const struct mavenregs* m) {
494 int i;
495
496 LR(0x80);
497 LR(0x82); LR(0x83);
498 LR(0x84); LR(0x85);
499
500 cve2_set_reg(PMINFO 0x3E, 0x01);
501
502 for (i = 0; i < 0x3E; i++) {
503 LR(i);
504 }
505 cve2_set_reg(PMINFO 0x3E, 0x00);
506}
507
508static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
509 MINFO_FROM(md);
510
511 dprintk(KERN_DEBUG "Computing, mode=%u\n", ACCESS_FBINFO(outputs[1]).mode);
512
513 if (mt->crtc == MATROXFB_SRC_CRTC2 &&
514 ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
515 const struct output_desc* outd;
516
517 cve2_init_TVdata(ACCESS_FBINFO(outputs[1]).mode, &ACCESS_FBINFO(hw).maven, &outd);
518 {
519 int blacklevel, whitelevel;
520 g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel);
521 ACCESS_FBINFO(hw).maven.regs[0x0E] = blacklevel >> 2;
522 ACCESS_FBINFO(hw).maven.regs[0x0F] = blacklevel & 3;
523 ACCESS_FBINFO(hw).maven.regs[0x1E] = whitelevel >> 2;
524 ACCESS_FBINFO(hw).maven.regs[0x1F] = whitelevel & 3;
525
526 ACCESS_FBINFO(hw).maven.regs[0x20] =
527 ACCESS_FBINFO(hw).maven.regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
528
529 ACCESS_FBINFO(hw).maven.regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
530
531 if (ACCESS_FBINFO(altout.tvo_params.testout)) {
532 ACCESS_FBINFO(hw).maven.regs[0x05] |= 0x02;
533 }
534 }
535 computeRegs(PMINFO &ACCESS_FBINFO(hw).maven, mt, outd);
536 } else if (mt->mnp < 0) {
537 /* We must program clocks before CRTC2, otherwise interlaced mode
538 startup may fail */
539 mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
540 mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
541 }
542 dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
543 return 0;
544}
545
546static int matroxfb_g450_program(void* md) {
547 MINFO_FROM(md);
548
549 if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
550 cve2_init_TV(PMINFO &ACCESS_FBINFO(hw).maven);
551 }
552 return 0;
553}
554
555static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
556 switch (arg) {
557 case MATROXFB_OUTPUT_MODE_PAL:
558 case MATROXFB_OUTPUT_MODE_NTSC:
559 case MATROXFB_OUTPUT_MODE_MONITOR:
560 return 0;
561 }
562 return -EINVAL;
563}
564
565static int g450_dvi_compute(void* md, struct my_timming* mt) {
566 MINFO_FROM(md);
567
568 if (mt->mnp < 0) {
569 mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
570 mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
571 }
572 return 0;
573}
574
575static struct matrox_altout matroxfb_g450_altout = {
576 .name = "Secondary output",
577 .compute = matroxfb_g450_compute,
578 .program = matroxfb_g450_program,
579 .verifymode = matroxfb_g450_verify_mode,
580 .getqueryctrl = g450_query_ctrl,
581 .getctrl = g450_get_ctrl,
582 .setctrl = g450_set_ctrl,
583};
584
585static struct matrox_altout matroxfb_g450_dvi = {
586 .name = "DVI output",
587 .compute = g450_dvi_compute,
588};
589
590void matroxfb_g450_connect(WPMINFO2) {
591 if (ACCESS_FBINFO(devflags.g450dac)) {
592 down_write(&ACCESS_FBINFO(altout.lock));
593 tvo_fill_defaults(PMINFO2);
594 ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
595 ACCESS_FBINFO(outputs[1]).data = MINFO;
596 ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout;
597 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
598 ACCESS_FBINFO(outputs[2]).src = ACCESS_FBINFO(outputs[2]).default_src;
599 ACCESS_FBINFO(outputs[2]).data = MINFO;
600 ACCESS_FBINFO(outputs[2]).output = &matroxfb_g450_dvi;
601 ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
602 up_write(&ACCESS_FBINFO(altout.lock));
603 }
604}
605
606void matroxfb_g450_shutdown(WPMINFO2) {
607 if (ACCESS_FBINFO(devflags.g450dac)) {
608 down_write(&ACCESS_FBINFO(altout.lock));
609 ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
610 ACCESS_FBINFO(outputs[1]).output = NULL;
611 ACCESS_FBINFO(outputs[1]).data = NULL;
612 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
613 ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
614 ACCESS_FBINFO(outputs[2]).output = NULL;
615 ACCESS_FBINFO(outputs[2]).data = NULL;
616 ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
617 up_write(&ACCESS_FBINFO(altout.lock));
618 }
619}
620
621EXPORT_SYMBOL(matroxfb_g450_connect);
622EXPORT_SYMBOL(matroxfb_g450_shutdown);
623
624MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
625MODULE_DESCRIPTION("Matrox G450/G550 output driver");
626MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_g450.h b/drivers/video/matrox/matroxfb_g450.h
new file mode 100644
index 000000000000..a0822a6033e5
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_g450.h
@@ -0,0 +1,14 @@
1#ifndef __MATROXFB_G450_H__
2#define __MATROXFB_G450_H__
3
4#include "matroxfb_base.h"
5
6#ifdef CONFIG_FB_MATROX_G
7void matroxfb_g450_connect(WPMINFO2);
8void matroxfb_g450_shutdown(WPMINFO2);
9#else
10static inline void matroxfb_g450_connect(WPMINFO2) { };
11static inline void matroxfb_g450_shutdown(WPMINFO2) { };
12#endif
13
14#endif /* __MATROXFB_G450_H__ */
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
new file mode 100644
index 000000000000..e529841cd83d
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -0,0 +1,1328 @@
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
15#include "matroxfb_maven.h"
16#include "matroxfb_misc.h"
17#include "matroxfb_DAC1064.h"
18#include <linux/i2c.h>
19#include <linux/matroxfb.h>
20#include <asm/div64.h>
21#include <asm/uaccess.h>
22
23#define MAVEN_I2CID (0x1B)
24
25#define MGATVO_B 1
26#define MGATVO_C 2
27
28static const struct maven_gamma {
29 unsigned char reg83;
30 unsigned char reg84;
31 unsigned char reg85;
32 unsigned char reg86;
33 unsigned char reg87;
34 unsigned char reg88;
35 unsigned char reg89;
36 unsigned char reg8a;
37 unsigned char reg8b;
38} maven_gamma[] = {
39 { 131, 57, 223, 15, 117, 212, 251, 91, 156},
40 { 133, 61, 128, 63, 180, 147, 195, 100, 180},
41 { 131, 19, 63, 31, 50, 66, 171, 64, 176},
42 { 0, 0, 0, 31, 16, 16, 16, 100, 200},
43 { 8, 23, 47, 73, 147, 244, 220, 80, 195},
44 { 22, 43, 64, 80, 147, 115, 58, 85, 168},
45 { 34, 60, 80, 214, 147, 212, 188, 85, 167},
46 { 45, 77, 96, 216, 147, 99, 91, 85, 159},
47 { 56, 76, 112, 107, 147, 212, 148, 64, 144},
48 { 65, 91, 128, 137, 147, 196, 17, 69, 148},
49 { 72, 104, 136, 138, 147, 180, 245, 73, 147},
50 { 87, 116, 143, 126, 16, 83, 229, 77, 144},
51 { 95, 119, 152, 254, 244, 83, 221, 77, 151},
52 { 100, 129, 159, 156, 244, 148, 197, 77, 160},
53 { 105, 141, 167, 247, 244, 132, 181, 84, 166},
54 { 105, 147, 168, 247, 244, 245, 181, 90, 170},
55 { 120, 153, 175, 248, 212, 229, 165, 90, 180},
56 { 119, 156, 176, 248, 244, 229, 84, 74, 160},
57 { 119, 158, 183, 248, 244, 229, 149, 78, 165}
58};
59
60/* Definition of the various controls */
61struct mctl {
62 struct v4l2_queryctrl desc;
63 size_t control;
64};
65
66#define BLMIN 0x0FF
67#define WLMAX 0x3FF
68
69static const struct mctl maven_controls[] =
70{ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
71 "brightness",
72 0, WLMAX - BLMIN, 1, 379 - BLMIN,
73 0,
74 }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
75 { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
76 "contrast",
77 0, 1023, 1, 127,
78 0,
79 }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
80 { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
81 "saturation",
82 0, 255, 1, 155,
83 0,
84 }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
85 { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
86 "hue",
87 0, 255, 1, 0,
88 0,
89 }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
90 { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER,
91 "gamma",
92 0, sizeof(maven_gamma)/sizeof(maven_gamma[0])-1, 1, 3,
93 0,
94 }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
95 { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
96 "test output",
97 0, 1, 1, 0,
98 0,
99 }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
100 { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER,
101 "deflicker mode",
102 0, 2, 1, 0,
103 0,
104 }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
105
106};
107
108#define MAVCTRLS (sizeof(maven_controls)/sizeof(maven_controls[0]))
109
110/* Return: positive number: id found
111 -EINVAL: id not found, return failure
112 -ENOENT: id not found, create fake disabled control */
113static int get_ctrl_id(__u32 v4l2_id) {
114 int i;
115
116 for (i = 0; i < MAVCTRLS; i++) {
117 if (v4l2_id < maven_controls[i].desc.id) {
118 if (maven_controls[i].desc.id == 0x08000000) {
119 return -EINVAL;
120 }
121 return -ENOENT;
122 }
123 if (v4l2_id == maven_controls[i].desc.id) {
124 return i;
125 }
126 }
127 return -EINVAL;
128}
129
130struct maven_data {
131 struct matrox_fb_info* primary_head;
132 struct i2c_client* client;
133 int version;
134};
135
136static int* get_ctrl_ptr(struct maven_data* md, int idx) {
137 return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
138}
139
140static int maven_get_reg(struct i2c_client* c, char reg) {
141 char dst;
142 struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), &reg },
143 { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }};
144 s32 err;
145
146 err = i2c_transfer(c->adapter, msgs, 2);
147 if (err < 0)
148 printk(KERN_INFO "ReadReg(%d) failed\n", reg);
149 return dst & 0xFF;
150}
151
152static int maven_set_reg(struct i2c_client* c, int reg, int val) {
153 s32 err;
154
155 err = i2c_smbus_write_byte_data(c, reg, val);
156 if (err)
157 printk(KERN_INFO "WriteReg(%d) failed\n", reg);
158 return err;
159}
160
161static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
162 s32 err;
163
164 err = i2c_smbus_write_word_data(c, reg, val);
165 if (err)
166 printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
167 return err;
168}
169
170static const struct matrox_pll_features maven_pll = {
171 50000,
172 27000,
173 4, 127,
174 2, 31,
175 3
176};
177
178struct matrox_pll_features2 {
179 unsigned int vco_freq_min;
180 unsigned int vco_freq_max;
181 unsigned int feed_div_min;
182 unsigned int feed_div_max;
183 unsigned int in_div_min;
184 unsigned int in_div_max;
185 unsigned int post_shift_max;
186};
187
188struct matrox_pll_ctl {
189 unsigned int ref_freq;
190 unsigned int den;
191};
192
193static const struct matrox_pll_features2 maven1000_pll = {
194 50000000,
195 300000000,
196 5, 128,
197 3, 32,
198 3
199};
200
201static const struct matrox_pll_ctl maven_PAL = {
202 540000,
203 50
204};
205
206static const struct matrox_pll_ctl maven_NTSC = {
207 450450, /* 27027000/60 == 27000000/59.94005994 */
208 60
209};
210
211static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
212 const struct matrox_pll_ctl* ctl,
213 unsigned int htotal, unsigned int vtotal,
214 unsigned int* in, unsigned int* feed, unsigned int* post,
215 unsigned int* h2) {
216 unsigned int besth2 = 0;
217 unsigned int fxtal = ctl->ref_freq;
218 unsigned int fmin = pll->vco_freq_min / ctl->den;
219 unsigned int fwant;
220 unsigned int p;
221 unsigned int scrlen;
222 unsigned int fmax;
223
224 DBG(__FUNCTION__)
225
226 scrlen = htotal * (vtotal - 1);
227 fwant = htotal * vtotal;
228 fmax = pll->vco_freq_max / ctl->den;
229
230 dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
231 fwant, fxtal, htotal, vtotal, fmax);
232 for (p = 1; p <= pll->post_shift_max; p++) {
233 if (fwant * 2 > fmax)
234 break;
235 fwant *= 2;
236 }
237 if (fwant > fmax)
238 return 0;
239 for (; p-- > 0; fwant >>= 1) {
240 unsigned int m;
241
242 if (fwant < fmin) break;
243 for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
244 unsigned int n;
245 unsigned int dvd;
246 unsigned int ln;
247
248 n = (fwant * m) / fxtal;
249 if (n < pll->feed_div_min)
250 continue;
251 if (n > pll->feed_div_max)
252 break;
253
254 ln = fxtal * n;
255 dvd = m << p;
256
257 if (ln % dvd)
258 continue;
259 ln = ln / dvd;
260
261 if (ln < scrlen + 2)
262 continue;
263 ln = ln - scrlen;
264 if (ln > htotal)
265 continue;
266 dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
267 if (ln > besth2) {
268 dprintk(KERN_DEBUG "Better...\n");
269 *h2 = besth2 = ln;
270 *post = p;
271 *in = m;
272 *feed = n;
273 }
274 }
275 }
276 if (besth2 < 2)
277 return 0;
278 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
279 return fxtal * (*feed) / (*in) * ctl->den;
280}
281
282static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
283 unsigned int htotal, unsigned int vtotal,
284 unsigned int* in, unsigned int* feed, unsigned int* post,
285 unsigned int* htotal2) {
286 unsigned int fvco;
287 unsigned int p;
288
289 fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
290 if (!fvco)
291 return -EINVAL;
292 p = (1 << p) - 1;
293 if (fvco <= 100000000)
294 ;
295 else if (fvco <= 140000000)
296 p |= 0x08;
297 else if (fvco <= 180000000)
298 p |= 0x10;
299 else
300 p |= 0x18;
301 *post = p;
302 return 0;
303}
304
305static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
306 unsigned int* in, unsigned int* feed, unsigned int* post) {
307 unsigned int fvco;
308 unsigned int p;
309
310 fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
311 p = (1 << p) - 1;
312 if (fvco <= 100000)
313 ;
314 else if (fvco <= 140000)
315 p |= 0x08;
316 else if (fvco <= 180000)
317 p |= 0x10;
318 else
319 p |= 0x18;
320 *post = p;
321 return;
322}
323
324static unsigned char maven_compute_deflicker (const struct maven_data* md) {
325 unsigned char df;
326
327 df = (md->version == MGATVO_B?0x40:0x00);
328 switch (md->primary_head->altout.tvo_params.deflicker) {
329 case 0:
330/* df |= 0x00; */
331 break;
332 case 1:
333 df |= 0xB1;
334 break;
335 case 2:
336 df |= 0xA2;
337 break;
338 }
339 return df;
340}
341
342static void maven_compute_bwlevel (const struct maven_data* md,
343 int *bl, int *wl) {
344 const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
345 const int c = md->primary_head->altout.tvo_params.contrast;
346
347 *bl = max(b - c, BLMIN);
348 *wl = min(b + c, WLMAX);
349}
350
351static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
352 return maven_gamma + md->primary_head->altout.tvo_params.gamma;
353}
354
355
356static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
357 static struct mavenregs palregs = { {
358 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
359 0x00,
360 0x00, /* ? not written */
361 0x00, /* modified by code (F9 written...) */
362 0x00, /* ? not written */
363 0x7E, /* 08 */
364 0x44, /* 09 */
365 0x9C, /* 0A */
366 0x2E, /* 0B */
367 0x21, /* 0C */
368 0x00, /* ? not written */
369 0x3F, 0x03, /* 0E-0F */
370 0x3F, 0x03, /* 10-11 */
371 0x1A, /* 12 */
372 0x2A, /* 13 */
373 0x1C, 0x3D, 0x14, /* 14-16 */
374 0x9C, 0x01, /* 17-18 */
375 0x00, /* 19 */
376 0xFE, /* 1A */
377 0x7E, /* 1B */
378 0x60, /* 1C */
379 0x05, /* 1D */
380 0x89, 0x03, /* 1E-1F */
381 0x72, /* 20 */
382 0x07, /* 21 */
383 0x72, /* 22 */
384 0x00, /* 23 */
385 0x00, /* 24 */
386 0x00, /* 25 */
387 0x08, /* 26 */
388 0x04, /* 27 */
389 0x00, /* 28 */
390 0x1A, /* 29 */
391 0x55, 0x01, /* 2A-2B */
392 0x26, /* 2C */
393 0x07, 0x7E, /* 2D-2E */
394 0x02, 0x54, /* 2F-30 */
395 0xB0, 0x00, /* 31-32 */
396 0x14, /* 33 */
397 0x49, /* 34 */
398 0x00, /* 35 written multiple times */
399 0x00, /* 36 not written */
400 0xA3, /* 37 */
401 0xC8, /* 38 */
402 0x22, /* 39 */
403 0x02, /* 3A */
404 0x22, /* 3B */
405 0x3F, 0x03, /* 3C-3D */
406 0x00, /* 3E written multiple times */
407 0x00, /* 3F not written */
408 }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
409 static struct mavenregs ntscregs = { {
410 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
411 0x00,
412 0x00, /* ? not written */
413 0x00, /* modified by code (F9 written...) */
414 0x00, /* ? not written */
415 0x7E, /* 08 */
416 0x43, /* 09 */
417 0x7E, /* 0A */
418 0x3D, /* 0B */
419 0x00, /* 0C */
420 0x00, /* ? not written */
421 0x41, 0x00, /* 0E-0F */
422 0x3C, 0x00, /* 10-11 */
423 0x17, /* 12 */
424 0x21, /* 13 */
425 0x1B, 0x1B, 0x24, /* 14-16 */
426 0x83, 0x01, /* 17-18 */
427 0x00, /* 19 */
428 0x0F, /* 1A */
429 0x0F, /* 1B */
430 0x60, /* 1C */
431 0x05, /* 1D */
432 0x89, 0x02, /* 1E-1F */
433 0x5F, /* 20 */
434 0x04, /* 21 */
435 0x5F, /* 22 */
436 0x01, /* 23 */
437 0x02, /* 24 */
438 0x00, /* 25 */
439 0x0A, /* 26 */
440 0x05, /* 27 */
441 0x00, /* 28 */
442 0x10, /* 29 */
443 0xFF, 0x03, /* 2A-2B */
444 0x24, /* 2C */
445 0x0F, 0x78, /* 2D-2E */
446 0x00, 0x00, /* 2F-30 */
447 0xB2, 0x04, /* 31-32 */
448 0x14, /* 33 */
449 0x02, /* 34 */
450 0x00, /* 35 written multiple times */
451 0x00, /* 36 not written */
452 0xA3, /* 37 */
453 0xC8, /* 38 */
454 0x15, /* 39 */
455 0x05, /* 3A */
456 0x3B, /* 3B */
457 0x3C, 0x00, /* 3C-3D */
458 0x00, /* 3E written multiple times */
459 0x00, /* never written */
460 }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
461 MINFO_FROM(md->primary_head);
462
463 if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_PAL)
464 *data = palregs;
465 else
466 *data = ntscregs;
467
468 /* Set deflicker */
469 data->regs[0x93] = maven_compute_deflicker(md);
470
471 /* set gamma */
472 {
473 const struct maven_gamma* g;
474 g = maven_compute_gamma(md);
475 data->regs[0x83] = g->reg83;
476 data->regs[0x84] = g->reg84;
477 data->regs[0x85] = g->reg85;
478 data->regs[0x86] = g->reg86;
479 data->regs[0x87] = g->reg87;
480 data->regs[0x88] = g->reg88;
481 data->regs[0x89] = g->reg89;
482 data->regs[0x8A] = g->reg8a;
483 data->regs[0x8B] = g->reg8b;
484 }
485
486 /* Set contrast / brightness */
487 {
488 int bl, wl;
489 maven_compute_bwlevel (md, &bl, &wl);
490 data->regs[0x0e] = bl >> 2;
491 data->regs[0x0f] = bl & 3;
492 data->regs[0x1e] = wl >> 2;
493 data->regs[0x1f] = wl & 3;
494 }
495
496 /* Set saturation */
497 {
498 data->regs[0x20] =
499 data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
500 }
501
502 /* Set HUE */
503 data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
504 return;
505}
506
507#define LR(x) maven_set_reg(c, (x), m->regs[(x)])
508#define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
509static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
510 int val;
511
512
513 maven_set_reg(c, 0x3E, 0x01);
514 maven_get_reg(c, 0x82); /* fetch oscillator state? */
515 maven_set_reg(c, 0x8C, 0x00);
516 maven_get_reg(c, 0x94); /* get 0x82 */
517 maven_set_reg(c, 0x94, 0xA2);
518 /* xmiscctrl */
519
520 maven_set_reg_pair(c, 0x8E, 0x1EFF);
521 maven_set_reg(c, 0xC6, 0x01);
522
523 /* removed code... */
524
525 maven_get_reg(c, 0x06);
526 maven_set_reg(c, 0x06, 0xF9); /* or read |= 0xF0 ? */
527
528 /* removed code here... */
529
530 /* real code begins here? */
531 /* chroma subcarrier */
532 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
533
534 LR(0x04);
535
536 LR(0x2C);
537 LR(0x08);
538 LR(0x0A);
539 LR(0x09);
540 LR(0x29);
541 LRP(0x31);
542 LRP(0x17);
543 LR(0x0B);
544 LR(0x0C);
545 if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
546 maven_set_reg(c, 0x35, 0x10); /* ... */
547 } else {
548 maven_set_reg(c, 0x35, 0x0F); /* ... */
549 }
550
551 LRP(0x10);
552
553 LRP(0x0E);
554 LRP(0x1E);
555
556 LR(0x20); /* saturation #1 */
557 LR(0x22); /* saturation #2 */
558 LR(0x25); /* hue */
559 LR(0x34);
560 LR(0x33);
561 LR(0x19);
562 LR(0x12);
563 LR(0x3B);
564 LR(0x13);
565 LR(0x39);
566 LR(0x1D);
567 LR(0x3A);
568 LR(0x24);
569 LR(0x14);
570 LR(0x15);
571 LR(0x16);
572 LRP(0x2D);
573 LRP(0x2F);
574 LR(0x1A);
575 LR(0x1B);
576 LR(0x1C);
577 LR(0x23);
578 LR(0x26);
579 LR(0x28);
580 LR(0x27);
581 LR(0x21);
582 LRP(0x2A);
583 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
584 maven_set_reg(c, 0x35, 0x1D); /* ... */
585 else
586 maven_set_reg(c, 0x35, 0x1C);
587
588 LRP(0x3C);
589 LR(0x37);
590 LR(0x38);
591 maven_set_reg(c, 0xB3, 0x01);
592
593 maven_get_reg(c, 0xB0); /* read 0x80 */
594 maven_set_reg(c, 0xB0, 0x08); /* ugh... */
595 maven_get_reg(c, 0xB9); /* read 0x7C */
596 maven_set_reg(c, 0xB9, 0x78);
597 maven_get_reg(c, 0xBF); /* read 0x00 */
598 maven_set_reg(c, 0xBF, 0x02);
599 maven_get_reg(c, 0x94); /* read 0x82 */
600 maven_set_reg(c, 0x94, 0xB3);
601
602 LR(0x80); /* 04 1A 91 or 05 21 91 */
603 LR(0x81);
604 LR(0x82);
605
606 maven_set_reg(c, 0x8C, 0x20);
607 maven_get_reg(c, 0x8D);
608 maven_set_reg(c, 0x8D, 0x10);
609
610 LR(0x90); /* 4D 50 52 or 4E 05 45 */
611 LR(0x91);
612 LR(0x92);
613
614 LRP(0x9A); /* 0049 or 004F */
615 LRP(0x9C); /* 0004 or 0004 */
616 LRP(0x9E); /* 0458 or 045E */
617 LRP(0xA0); /* 05DA or 051B */
618 LRP(0xA2); /* 00CC or 00CF */
619 LRP(0xA4); /* 007D or 007F */
620 LRP(0xA6); /* 007C or 007E */
621 LRP(0xA8); /* 03CB or 03CE */
622 LRP(0x98); /* 0000 or 0000 */
623 LRP(0xAE); /* 0044 or 003A */
624 LRP(0x96); /* 05DA or 051B */
625 LRP(0xAA); /* 04BC or 046A */
626 LRP(0xAC); /* 004D or 004E */
627
628 LR(0xBE);
629 LR(0xC2);
630
631 maven_get_reg(c, 0x8D);
632 maven_set_reg(c, 0x8D, 0x04);
633
634 LR(0x20); /* saturation #1 */
635 LR(0x22); /* saturation #2 */
636 LR(0x93); /* whoops */
637 LR(0x20); /* oh, saturation #1 again */
638 LR(0x22); /* oh, saturation #2 again */
639 LR(0x25); /* hue */
640 LRP(0x0E);
641 LRP(0x1E);
642 LRP(0x0E); /* problems with memory? */
643 LRP(0x1E); /* yes, matrox must have problems in memory area... */
644
645 /* load gamma correction stuff */
646 LR(0x83);
647 LR(0x84);
648 LR(0x85);
649 LR(0x86);
650 LR(0x87);
651 LR(0x88);
652 LR(0x89);
653 LR(0x8A);
654 LR(0x8B);
655
656 val = maven_get_reg(c, 0x8D);
657 val &= 0x14; /* 0x10 or anything ored with it */
658 maven_set_reg(c, 0x8D, val);
659
660 LR(0x33);
661 LR(0x19);
662 LR(0x12);
663 LR(0x3B);
664 LR(0x13);
665 LR(0x39);
666 LR(0x1D);
667 LR(0x3A);
668 LR(0x24);
669 LR(0x14);
670 LR(0x15);
671 LR(0x16);
672 LRP(0x2D);
673 LRP(0x2F);
674 LR(0x1A);
675 LR(0x1B);
676 LR(0x1C);
677 LR(0x23);
678 LR(0x26);
679 LR(0x28);
680 LR(0x27);
681 LR(0x21);
682 LRP(0x2A);
683 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
684 maven_set_reg(c, 0x35, 0x1D);
685 else
686 maven_set_reg(c, 0x35, 0x1C);
687 LRP(0x3C);
688 LR(0x37);
689 LR(0x38);
690
691 maven_get_reg(c, 0xB0);
692 LR(0xB0); /* output mode */
693 LR(0x90);
694 LR(0xBE);
695 LR(0xC2);
696
697 LRP(0x9A);
698 LRP(0xA2);
699 LRP(0x9E);
700 LRP(0xA6);
701 LRP(0xAA);
702 LRP(0xAC);
703 maven_set_reg(c, 0x3E, 0x00);
704 maven_set_reg(c, 0x95, 0x20);
705}
706
707static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
708 struct mavenregs* m) {
709 unsigned int x;
710 unsigned int err = ~0;
711
712 /* 1:1 */
713 m->regs[0x80] = 0x0F;
714 m->regs[0x81] = 0x07;
715 m->regs[0x82] = 0x81;
716
717 for (x = 0; x < 8; x++) {
718 unsigned int a, b, c, h2;
719 unsigned int h = ht + 2 + x;
720
721 if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
722 unsigned int diff = h - h2;
723
724 if (diff < err) {
725 err = diff;
726 m->regs[0x80] = a - 1;
727 m->regs[0x81] = b - 1;
728 m->regs[0x82] = c | 0x80;
729 m->hcorr = h2 - 2;
730 m->htotal = h - 2;
731 }
732 }
733 }
734 return err != ~0U;
735}
736
737static inline int maven_compute_timming(struct maven_data* md,
738 struct my_timming* mt,
739 struct mavenregs* m) {
740 unsigned int tmpi;
741 unsigned int a, bv, c;
742 MINFO_FROM(md->primary_head);
743
744 m->mode = ACCESS_FBINFO(outputs[1]).mode;
745 if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
746 unsigned int lmargin;
747 unsigned int umargin;
748 unsigned int vslen;
749 unsigned int hcrt;
750 unsigned int slen;
751
752 maven_init_TVdata(md, m);
753
754 if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
755 return -EINVAL;
756
757 lmargin = mt->HTotal - mt->HSyncEnd;
758 slen = mt->HSyncEnd - mt->HSyncStart;
759 hcrt = mt->HTotal - slen - mt->delay;
760 umargin = mt->VTotal - mt->VSyncEnd;
761 vslen = mt->VSyncEnd - mt->VSyncStart;
762
763 if (m->hcorr < mt->HTotal)
764 hcrt += m->hcorr;
765 if (hcrt > mt->HTotal)
766 hcrt -= mt->HTotal;
767 if (hcrt + 2 > mt->HTotal)
768 hcrt = 0; /* or issue warning? */
769
770 /* last (first? middle?) line in picture can have different length */
771 /* hlen - 2 */
772 m->regs[0x96] = m->hcorr;
773 m->regs[0x97] = m->hcorr >> 8;
774 /* ... */
775 m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
776 /* hblanking end */
777 m->regs[0x9A] = lmargin; /* 100% */
778 m->regs[0x9B] = lmargin >> 8; /* 100% */
779 /* who knows */
780 m->regs[0x9C] = 0x04;
781 m->regs[0x9D] = 0x00;
782 /* htotal - 2 */
783 m->regs[0xA0] = m->htotal;
784 m->regs[0xA1] = m->htotal >> 8;
785 /* vblanking end */
786 m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */
787 m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
788 /* something end... [A6]+1..[A8] */
789 if (md->version == MGATVO_B) {
790 m->regs[0xA4] = 0x04;
791 m->regs[0xA5] = 0x00;
792 } else {
793 m->regs[0xA4] = 0x01;
794 m->regs[0xA5] = 0x00;
795 }
796 /* something start... 0..[A4]-1 */
797 m->regs[0xA6] = 0x00;
798 m->regs[0xA7] = 0x00;
799 /* vertical line count - 1 */
800 m->regs[0xA8] = mt->VTotal - 1;
801 m->regs[0xA9] = (mt->VTotal - 1) >> 8;
802 /* horizontal vidrst pos */
803 m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */
804 m->regs[0xAB] = hcrt >> 8;
805 /* vertical vidrst pos */
806 m->regs[0xAC] = mt->VTotal - 2;
807 m->regs[0xAD] = (mt->VTotal - 2) >> 8;
808 /* moves picture up/down and so on... */
809 m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
810 m->regs[0xAF] = 0x00;
811 {
812 int hdec;
813 int hlen;
814 unsigned int ibmin = 4 + lmargin + mt->HDisplay;
815 unsigned int ib;
816 int i;
817
818 /* Verify! */
819 /* Where 94208 came from? */
820 if (mt->HTotal)
821 hdec = 94208 / (mt->HTotal);
822 else
823 hdec = 0x81;
824 if (hdec > 0x81)
825 hdec = 0x81;
826 if (hdec < 0x41)
827 hdec = 0x41;
828 hdec--;
829 hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
830 if (hlen < 0)
831 hlen = 0;
832 hlen = hlen >> 8;
833 if (hlen > 0xFF)
834 hlen = 0xFF;
835 /* Now we have to compute input buffer length.
836 If you want any picture, it must be between
837 4 + lmargin + xres
838 and
839 94208 / hdec
840 If you want perfect picture even on the top
841 of screen, it must be also
842 0x3C0000 * i / hdec + Q - R / hdec
843 where
844 R Qmin Qmax
845 0x07000 0x5AE 0x5BF
846 0x08000 0x5CF 0x5FF
847 0x0C000 0x653 0x67F
848 0x10000 0x6F8 0x6FF
849 */
850 i = 1;
851 do {
852 ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
853 i++;
854 } while (ib < ibmin);
855 if (ib >= m->htotal + 2) {
856 ib = ibmin;
857 }
858
859 m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
860 m->regs[0xC2] = hlen;
861 /* 'valid' input line length */
862 m->regs[0x9E] = ib;
863 m->regs[0x9F] = ib >> 8;
864 }
865 {
866 int vdec;
867 int vlen;
868
869#define MATROX_USE64BIT_DIVIDE
870 if (mt->VTotal) {
871#ifdef MATROX_USE64BIT_DIVIDE
872 u64 f1;
873 u32 a;
874 u32 b;
875
876 a = m->vlines * (m->htotal + 2);
877 b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
878
879 f1 = ((u64)a) << 15; /* *32768 */
880 do_div(f1, b);
881 vdec = f1;
882#else
883 vdec = m->vlines * 32768 / mt->VTotal;
884#endif
885 } else
886 vdec = 0x8000;
887 if (vdec > 0x8000)
888 vdec = 0x8000;
889 vlen = (vslen + umargin + mt->VDisplay) * vdec;
890 vlen = (vlen >> 16) - 146; /* FIXME: 146?! */
891 if (vlen < 0)
892 vlen = 0;
893 if (vlen > 0xFF)
894 vlen = 0xFF;
895 vdec--;
896 m->regs[0x91] = vdec;
897 m->regs[0x92] = vdec >> 8;
898 m->regs[0xBE] = vlen;
899 }
900 m->regs[0xB0] = 0x08; /* output: SVideo/Composite */
901 return 0;
902 }
903
904 DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
905 m->regs[0x80] = a;
906 m->regs[0x81] = bv;
907 m->regs[0x82] = c | 0x80;
908
909 m->regs[0xB3] = 0x01;
910 m->regs[0x94] = 0xB2;
911
912 /* htotal... */
913 m->regs[0x96] = mt->HTotal;
914 m->regs[0x97] = mt->HTotal >> 8;
915 /* ?? */
916 m->regs[0x98] = 0x00;
917 m->regs[0x99] = 0x00;
918 /* hsync len */
919 tmpi = mt->HSyncEnd - mt->HSyncStart;
920 m->regs[0x9A] = tmpi;
921 m->regs[0x9B] = tmpi >> 8;
922 /* hblank end */
923 tmpi = mt->HTotal - mt->HSyncStart;
924 m->regs[0x9C] = tmpi;
925 m->regs[0x9D] = tmpi >> 8;
926 /* hblank start */
927 tmpi += mt->HDisplay;
928 m->regs[0x9E] = tmpi;
929 m->regs[0x9F] = tmpi >> 8;
930 /* htotal + 1 */
931 tmpi = mt->HTotal + 1;
932 m->regs[0xA0] = tmpi;
933 m->regs[0xA1] = tmpi >> 8;
934 /* vsync?! */
935 tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
936 m->regs[0xA2] = tmpi;
937 m->regs[0xA3] = tmpi >> 8;
938 /* ignored? */
939 tmpi = mt->VTotal - mt->VSyncStart;
940 m->regs[0xA4] = tmpi;
941 m->regs[0xA5] = tmpi >> 8;
942 /* ignored? */
943 tmpi = mt->VTotal - 1;
944 m->regs[0xA6] = tmpi;
945 m->regs[0xA7] = tmpi >> 8;
946 /* vtotal - 1 */
947 m->regs[0xA8] = tmpi;
948 m->regs[0xA9] = tmpi >> 8;
949 /* hor vidrst */
950 tmpi = mt->HTotal - mt->delay;
951 m->regs[0xAA] = tmpi;
952 m->regs[0xAB] = tmpi >> 8;
953 /* vert vidrst */
954 tmpi = mt->VTotal - 2;
955 m->regs[0xAC] = tmpi;
956 m->regs[0xAD] = tmpi >> 8;
957 /* ignored? */
958 m->regs[0xAE] = 0x00;
959 m->regs[0xAF] = 0x00;
960
961 m->regs[0xB0] = 0x03; /* output: monitor */
962 m->regs[0xB1] = 0xA0; /* ??? */
963 m->regs[0x8C] = 0x20; /* must be set... */
964 m->regs[0x8D] = 0x04; /* defaults to 0x10: test signal */
965 m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
966 m->regs[0xBF] = 0x22; /* makes picture stable */
967
968 return 0;
969}
970
971static inline int maven_program_timming(struct maven_data* md,
972 const struct mavenregs* m) {
973 struct i2c_client* c = md->client;
974
975 if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
976 LR(0x80);
977 LR(0x81);
978 LR(0x82);
979
980 LR(0xB3);
981 LR(0x94);
982
983 LRP(0x96);
984 LRP(0x98);
985 LRP(0x9A);
986 LRP(0x9C);
987 LRP(0x9E);
988 LRP(0xA0);
989 LRP(0xA2);
990 LRP(0xA4);
991 LRP(0xA6);
992 LRP(0xA8);
993 LRP(0xAA);
994 LRP(0xAC);
995 LRP(0xAE);
996
997 LR(0xB0); /* output: monitor */
998 LR(0xB1); /* ??? */
999 LR(0x8C); /* must be set... */
1000 LR(0x8D); /* defaults to 0x10: test signal */
1001 LR(0xB9); /* defaults to 0x2C: too bright */
1002 LR(0xBF); /* makes picture stable */
1003 } else {
1004 maven_init_TV(c, m);
1005 }
1006 return 0;
1007}
1008
1009static inline int maven_resync(struct maven_data* md) {
1010 struct i2c_client* c = md->client;
1011 maven_set_reg(c, 0x95, 0x20); /* start whole thing */
1012 return 0;
1013}
1014
1015static int maven_get_queryctrl (struct maven_data* md,
1016 struct v4l2_queryctrl *p) {
1017 int i;
1018
1019 i = get_ctrl_id(p->id);
1020 if (i >= 0) {
1021 *p = maven_controls[i].desc;
1022 return 0;
1023 }
1024 if (i == -ENOENT) {
1025 static const struct v4l2_queryctrl disctrl =
1026 { .flags = V4L2_CTRL_FLAG_DISABLED };
1027
1028 i = p->id;
1029 *p = disctrl;
1030 p->id = i;
1031 sprintf(p->name, "Ctrl #%08X", i);
1032 return 0;
1033 }
1034 return -EINVAL;
1035}
1036
1037static int maven_set_control (struct maven_data* md,
1038 struct v4l2_control *p) {
1039 int i;
1040
1041 i = get_ctrl_id(p->id);
1042 if (i < 0) return -EINVAL;
1043
1044 /*
1045 * Check if changed.
1046 */
1047 if (p->value == *get_ctrl_ptr(md, i)) return 0;
1048
1049 /*
1050 * Check limits.
1051 */
1052 if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
1053 if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
1054
1055 /*
1056 * Store new value.
1057 */
1058 *get_ctrl_ptr(md, i) = p->value;
1059
1060 switch (p->id) {
1061 case V4L2_CID_BRIGHTNESS:
1062 case V4L2_CID_CONTRAST:
1063 {
1064 int blacklevel, whitelevel;
1065 maven_compute_bwlevel(md, &blacklevel, &whitelevel);
1066 blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
1067 whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
1068 maven_set_reg_pair(md->client, 0x0e, blacklevel);
1069 maven_set_reg_pair(md->client, 0x1e, whitelevel);
1070 }
1071 break;
1072 case V4L2_CID_SATURATION:
1073 {
1074 maven_set_reg(md->client, 0x20, p->value);
1075 maven_set_reg(md->client, 0x22, p->value);
1076 }
1077 break;
1078 case V4L2_CID_HUE:
1079 {
1080 maven_set_reg(md->client, 0x25, p->value);
1081 }
1082 break;
1083 case V4L2_CID_GAMMA:
1084 {
1085 const struct maven_gamma* g;
1086 g = maven_compute_gamma(md);
1087 maven_set_reg(md->client, 0x83, g->reg83);
1088 maven_set_reg(md->client, 0x84, g->reg84);
1089 maven_set_reg(md->client, 0x85, g->reg85);
1090 maven_set_reg(md->client, 0x86, g->reg86);
1091 maven_set_reg(md->client, 0x87, g->reg87);
1092 maven_set_reg(md->client, 0x88, g->reg88);
1093 maven_set_reg(md->client, 0x89, g->reg89);
1094 maven_set_reg(md->client, 0x8a, g->reg8a);
1095 maven_set_reg(md->client, 0x8b, g->reg8b);
1096 }
1097 break;
1098 case MATROXFB_CID_TESTOUT:
1099 {
1100 unsigned char val
1101 = maven_get_reg (md->client,0x8d);
1102 if (p->value) val |= 0x10;
1103 else val &= ~0x10;
1104 maven_set_reg (md->client, 0x8d, val);
1105 }
1106 break;
1107 case MATROXFB_CID_DEFLICKER:
1108 {
1109 maven_set_reg(md->client, 0x93, maven_compute_deflicker(md));
1110 }
1111 break;
1112 }
1113
1114
1115 return 0;
1116}
1117
1118static int maven_get_control (struct maven_data* md,
1119 struct v4l2_control *p) {
1120 int i;
1121
1122 i = get_ctrl_id(p->id);
1123 if (i < 0) return -EINVAL;
1124 p->value = *get_ctrl_ptr(md, i);
1125 return 0;
1126}
1127
1128/******************************************************/
1129
1130static int maven_out_compute(void* md, struct my_timming* mt) {
1131#define mdinfo ((struct maven_data*)md)
1132#define minfo (mdinfo->primary_head)
1133 return maven_compute_timming(md, mt, &ACCESS_FBINFO(hw).maven);
1134#undef minfo
1135#undef mdinfo
1136}
1137
1138static int maven_out_program(void* md) {
1139#define mdinfo ((struct maven_data*)md)
1140#define minfo (mdinfo->primary_head)
1141 return maven_program_timming(md, &ACCESS_FBINFO(hw).maven);
1142#undef minfo
1143#undef mdinfo
1144}
1145
1146static int maven_out_start(void* md) {
1147 return maven_resync(md);
1148}
1149
1150static int maven_out_verify_mode(void* md, u_int32_t arg) {
1151 switch (arg) {
1152 case MATROXFB_OUTPUT_MODE_PAL:
1153 case MATROXFB_OUTPUT_MODE_NTSC:
1154 case MATROXFB_OUTPUT_MODE_MONITOR:
1155 return 0;
1156 }
1157 return -EINVAL;
1158}
1159
1160static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) {
1161 return maven_get_queryctrl(md, p);
1162}
1163
1164static int maven_out_get_ctrl(void* md, struct v4l2_control* p) {
1165 return maven_get_control(md, p);
1166}
1167
1168static int maven_out_set_ctrl(void* md, struct v4l2_control* p) {
1169 return maven_set_control(md, p);
1170}
1171
1172static struct matrox_altout maven_altout = {
1173 .name = "Secondary output",
1174 .compute = maven_out_compute,
1175 .program = maven_out_program,
1176 .start = maven_out_start,
1177 .verifymode = maven_out_verify_mode,
1178 .getqueryctrl = maven_out_get_queryctrl,
1179 .getctrl = maven_out_get_ctrl,
1180 .setctrl = maven_out_set_ctrl,
1181};
1182
1183static int maven_init_client(struct i2c_client* clnt) {
1184 struct maven_data* md = i2c_get_clientdata(clnt);
1185 MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo);
1186
1187 md->primary_head = MINFO;
1188 md->client = clnt;
1189 down_write(&ACCESS_FBINFO(altout.lock));
1190 ACCESS_FBINFO(outputs[1]).output = &maven_altout;
1191 ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
1192 ACCESS_FBINFO(outputs[1]).data = md;
1193 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1194 up_write(&ACCESS_FBINFO(altout.lock));
1195 if (maven_get_reg(clnt, 0xB2) < 0x14) {
1196 md->version = MGATVO_B;
1197 /* Tweak some things for this old chip */
1198 } else {
1199 md->version = MGATVO_C;
1200 }
1201 /*
1202 * Set all parameters to its initial values.
1203 */
1204 {
1205 unsigned int i;
1206
1207 for (i = 0; i < MAVCTRLS; ++i) {
1208 *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
1209 }
1210 }
1211
1212 return 0;
1213}
1214
1215static int maven_shutdown_client(struct i2c_client* clnt) {
1216 struct maven_data* md = i2c_get_clientdata(clnt);
1217
1218 if (md->primary_head) {
1219 MINFO_FROM(md->primary_head);
1220
1221 down_write(&ACCESS_FBINFO(altout.lock));
1222 ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
1223 ACCESS_FBINFO(outputs[1]).output = NULL;
1224 ACCESS_FBINFO(outputs[1]).data = NULL;
1225 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1226 up_write(&ACCESS_FBINFO(altout.lock));
1227 md->primary_head = NULL;
1228 }
1229 return 0;
1230}
1231
1232static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
1233static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END };
1234I2C_CLIENT_INSMOD;
1235
1236static struct i2c_driver maven_driver;
1237
1238static int maven_detect_client(struct i2c_adapter* adapter, int address, int kind) {
1239 int err = 0;
1240 struct i2c_client* new_client;
1241 struct maven_data* data;
1242
1243 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
1244 I2C_FUNC_SMBUS_BYTE_DATA |
1245 I2C_FUNC_PROTOCOL_MANGLING))
1246 goto ERROR0;
1247 if (!(new_client = (struct i2c_client*)kmalloc(sizeof(*new_client) + sizeof(*data),
1248 GFP_KERNEL))) {
1249 err = -ENOMEM;
1250 goto ERROR0;
1251 }
1252 memset(new_client, 0, sizeof(*new_client) + sizeof(*data));
1253 data = (struct maven_data*)(new_client + 1);
1254 i2c_set_clientdata(new_client, data);
1255 new_client->addr = address;
1256 new_client->adapter = adapter;
1257 new_client->driver = &maven_driver;
1258 new_client->flags = 0;
1259 strcpy(new_client->name, "maven client");
1260 if ((err = i2c_attach_client(new_client)))
1261 goto ERROR3;
1262 err = maven_init_client(new_client);
1263 if (err)
1264 goto ERROR4;
1265 return 0;
1266ERROR4:;
1267 i2c_detach_client(new_client);
1268ERROR3:;
1269 kfree(new_client);
1270ERROR0:;
1271 return err;
1272}
1273
1274static int maven_attach_adapter(struct i2c_adapter* adapter) {
1275 if (adapter->id == (I2C_ALGO_BIT | I2C_HW_B_G400))
1276 return i2c_probe(adapter, &addr_data, &maven_detect_client);
1277 return 0;
1278}
1279
1280static int maven_detach_client(struct i2c_client* client) {
1281 int err;
1282
1283 if ((err = i2c_detach_client(client))) {
1284 printk(KERN_ERR "maven: Cannot deregister client\n");
1285 return err;
1286 }
1287 maven_shutdown_client(client);
1288 kfree(client);
1289 return 0;
1290}
1291
1292static int maven_command(struct i2c_client* client, unsigned int cmd, void* arg) {
1293 return -ENOIOCTLCMD; /* or -EINVAL, depends on who will call this */
1294}
1295
1296static struct i2c_driver maven_driver={
1297 .owner = THIS_MODULE,
1298 .name = "maven",
1299 .id = I2C_DRIVERID_MGATVO,
1300 .flags = I2C_DF_NOTIFY,
1301 .attach_adapter = maven_attach_adapter,
1302 .detach_client = maven_detach_client,
1303 .command = maven_command,
1304};
1305
1306/* ************************** */
1307
1308static int matroxfb_maven_init(void) {
1309 int err;
1310
1311 err = i2c_add_driver(&maven_driver);
1312 if (err) {
1313 printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err);
1314 return err;
1315 }
1316 return 0;
1317}
1318
1319static void matroxfb_maven_exit(void) {
1320 i2c_del_driver(&maven_driver);
1321}
1322
1323MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1324MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1325MODULE_LICENSE("GPL");
1326module_init(matroxfb_maven_init);
1327module_exit(matroxfb_maven_exit);
1328/* we do not have __setup() yet */
diff --git a/drivers/video/matrox/matroxfb_maven.h b/drivers/video/matrox/matroxfb_maven.h
new file mode 100644
index 000000000000..99eddec9f30c
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_maven.h
@@ -0,0 +1,20 @@
1#ifndef __MATROXFB_MAVEN_H__
2#define __MATROXFB_MAVEN_H__
3
4#include <linux/ioctl.h>
5#include <linux/i2c.h>
6#include <linux/i2c-algo-bit.h>
7#include "matroxfb_base.h"
8
9struct i2c_bit_adapter {
10 struct i2c_adapter adapter;
11 int initialized;
12 struct i2c_algo_bit_data bac;
13 struct matrox_fb_info* minfo;
14 struct {
15 unsigned int data;
16 unsigned int clock;
17 } mask;
18};
19
20#endif /* __MATROXFB_MAVEN_H__ */
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
new file mode 100644
index 000000000000..76fd3a519b8a
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -0,0 +1,777 @@
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#include <linux/config.h>
86
87#include "matroxfb_misc.h"
88#include <linux/interrupt.h>
89#include <linux/matroxfb.h>
90
91void matroxfb_DAC_out(CPMINFO int reg, int val) {
92 DBG_REG(__FUNCTION__)
93 mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
94 mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val);
95}
96
97int matroxfb_DAC_in(CPMINFO int reg) {
98 DBG_REG(__FUNCTION__)
99 mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
100 return mga_inb(M_RAMDAC_BASE+M_X_DATAREG);
101}
102
103void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
104 unsigned int pixclock = var->pixclock;
105
106 DBG(__FUNCTION__)
107
108 if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
109 mt->pixclock = 1000000000 / pixclock;
110 if (mt->pixclock < 1) mt->pixclock = 1;
111 mt->mnp = -1;
112 mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
113 mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
114 mt->HDisplay = var->xres;
115 mt->HSyncStart = mt->HDisplay + var->right_margin;
116 mt->HSyncEnd = mt->HSyncStart + var->hsync_len;
117 mt->HTotal = mt->HSyncEnd + var->left_margin;
118 mt->VDisplay = var->yres;
119 mt->VSyncStart = mt->VDisplay + var->lower_margin;
120 mt->VSyncEnd = mt->VSyncStart + var->vsync_len;
121 mt->VTotal = mt->VSyncEnd + var->upper_margin;
122 mt->sync = var->sync;
123}
124
125int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax,
126 unsigned int* in, unsigned int* feed, unsigned int* post) {
127 unsigned int bestdiff = ~0;
128 unsigned int bestvco = 0;
129 unsigned int fxtal = pll->ref_freq;
130 unsigned int fwant;
131 unsigned int p;
132
133 DBG(__FUNCTION__)
134
135 fwant = freq;
136
137#ifdef DEBUG
138 printk(KERN_ERR "post_shift_max: %d\n", pll->post_shift_max);
139 printk(KERN_ERR "ref_freq: %d\n", pll->ref_freq);
140 printk(KERN_ERR "freq: %d\n", freq);
141 printk(KERN_ERR "vco_freq_min: %d\n", pll->vco_freq_min);
142 printk(KERN_ERR "in_div_min: %d\n", pll->in_div_min);
143 printk(KERN_ERR "in_div_max: %d\n", pll->in_div_max);
144 printk(KERN_ERR "feed_div_min: %d\n", pll->feed_div_min);
145 printk(KERN_ERR "feed_div_max: %d\n", pll->feed_div_max);
146 printk(KERN_ERR "fmax: %d\n", fmax);
147#endif
148 for (p = 1; p <= pll->post_shift_max; p++) {
149 if (fwant * 2 > fmax)
150 break;
151 fwant *= 2;
152 }
153 if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min;
154 if (fwant > fmax) fwant = fmax;
155 for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) {
156 unsigned int m;
157
158 if (fwant < pll->vco_freq_min) break;
159 for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
160 unsigned int diff, fvco;
161 unsigned int n;
162
163 n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1;
164 if (n > pll->feed_div_max)
165 break;
166 if (n < pll->feed_div_min)
167 n = pll->feed_div_min;
168 fvco = (fxtal * (n + 1)) / (m + 1);
169 if (fvco < fwant)
170 diff = fwant - fvco;
171 else
172 diff = fvco - fwant;
173 if (diff < bestdiff) {
174 bestdiff = diff;
175 *post = p;
176 *in = m;
177 *feed = n;
178 bestvco = fvco;
179 }
180 }
181 }
182 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant);
183 return bestvco;
184}
185
186int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) {
187 unsigned int hd, hs, he, hbe, ht;
188 unsigned int vd, vs, ve, vt, lc;
189 unsigned int wd;
190 unsigned int divider;
191 int i;
192 int fwidth;
193 struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw);
194
195 fwidth = 8;
196
197 DBG(__FUNCTION__)
198
199 hw->SEQ[0] = 0x00;
200 if (fwidth == 9)
201 hw->SEQ[1] = 0x00;
202 else
203 hw->SEQ[1] = 0x01; /* or 0x09 */
204 hw->SEQ[2] = 0x0F; /* bitplanes */
205 hw->SEQ[3] = 0x00;
206 hw->SEQ[4] = 0x0E;
207 /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millennium code... Hope that by MGA1064 too */
208 if (m->dblscan) {
209 m->VTotal <<= 1;
210 m->VDisplay <<= 1;
211 m->VSyncStart <<= 1;
212 m->VSyncEnd <<= 1;
213 }
214 if (m->interlaced) {
215 m->VTotal >>= 1;
216 m->VDisplay >>= 1;
217 m->VSyncStart >>= 1;
218 m->VSyncEnd >>= 1;
219 }
220
221 /* GCTL is ignored when not using 0xA0000 aperture */
222 hw->GCTL[0] = 0x00;
223 hw->GCTL[1] = 0x00;
224 hw->GCTL[2] = 0x00;
225 hw->GCTL[3] = 0x00;
226 hw->GCTL[4] = 0x00;
227 hw->GCTL[5] = 0x40;
228 hw->GCTL[6] = 0x05;
229 hw->GCTL[7] = 0x0F;
230 hw->GCTL[8] = 0xFF;
231
232 /* Whole ATTR is ignored in PowerGraphics mode */
233 for (i = 0; i < 16; i++)
234 hw->ATTR[i] = i;
235 hw->ATTR[16] = 0x41;
236 hw->ATTR[17] = 0xFF;
237 hw->ATTR[18] = 0x0F;
238 if (fwidth == 9)
239 hw->ATTR[19] = 0x08;
240 else
241 hw->ATTR[19] = 0x00;
242 hw->ATTR[20] = 0x00;
243
244 hd = m->HDisplay >> 3;
245 hs = m->HSyncStart >> 3;
246 he = m->HSyncEnd >> 3;
247 ht = m->HTotal >> 3;
248 /* standard timmings are in 8pixels, but for interleaved we cannot */
249 /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */
250 /* using 16 or more pixels per unit can save us */
251 divider = ACCESS_FBINFO(curr.final_bppShift);
252 while (divider & 3) {
253 hd >>= 1;
254 hs >>= 1;
255 he >>= 1;
256 ht >>= 1;
257 divider <<= 1;
258 }
259 divider = divider / 4;
260 /* divider can be from 1 to 8 */
261 while (divider > 8) {
262 hd <<= 1;
263 hs <<= 1;
264 he <<= 1;
265 ht <<= 1;
266 divider >>= 1;
267 }
268 hd = hd - 1;
269 hs = hs - 1;
270 he = he - 1;
271 ht = ht - 1;
272 vd = m->VDisplay - 1;
273 vs = m->VSyncStart - 1;
274 ve = m->VSyncEnd - 1;
275 vt = m->VTotal - 2;
276 lc = vd;
277 /* G200 cannot work with (ht & 7) == 6 */
278 if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04))
279 ht++;
280 hbe = ht;
281 wd = ACCESS_FBINFO(fbcon).var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64;
282
283 hw->CRTCEXT[0] = 0;
284 hw->CRTCEXT[5] = 0;
285 if (m->interlaced) {
286 hw->CRTCEXT[0] = 0x80;
287 hw->CRTCEXT[5] = (hs + he - ht) >> 1;
288 if (!m->dblscan)
289 wd <<= 1;
290 vt &= ~1;
291 }
292 hw->CRTCEXT[0] |= (wd & 0x300) >> 4;
293 hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) |
294 ((hd & 0x100) >> 7) | /* blanking */
295 ((hs & 0x100) >> 6) | /* sync start */
296 (hbe & 0x040); /* end hor. blanking */
297 /* FIXME: Enable vidrst only on G400, and only if TV-out is used */
298 if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1)
299 hw->CRTCEXT[1] |= 0x88; /* enable horizontal and vertical vidrst */
300 hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) |
301 ((vd & 0x400) >> 8) | /* disp end */
302 ((vd & 0xC00) >> 7) | /* vblanking start */
303 ((vs & 0xC00) >> 5) |
304 ((lc & 0x400) >> 3);
305 hw->CRTCEXT[3] = (divider - 1) | 0x80;
306 hw->CRTCEXT[4] = 0;
307
308 hw->CRTC[0] = ht-4;
309 hw->CRTC[1] = hd;
310 hw->CRTC[2] = hd;
311 hw->CRTC[3] = (hbe & 0x1F) | 0x80;
312 hw->CRTC[4] = hs;
313 hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F);
314 hw->CRTC[6] = vt & 0xFF;
315 hw->CRTC[7] = ((vt & 0x100) >> 8) |
316 ((vd & 0x100) >> 7) |
317 ((vs & 0x100) >> 6) |
318 ((vd & 0x100) >> 5) |
319 ((lc & 0x100) >> 4) |
320 ((vt & 0x200) >> 4) |
321 ((vd & 0x200) >> 3) |
322 ((vs & 0x200) >> 2);
323 hw->CRTC[8] = 0x00;
324 hw->CRTC[9] = ((vd & 0x200) >> 4) |
325 ((lc & 0x200) >> 3);
326 if (m->dblscan && !m->interlaced)
327 hw->CRTC[9] |= 0x80;
328 for (i = 10; i < 16; i++)
329 hw->CRTC[i] = 0x00;
330 hw->CRTC[16] = vs /* & 0xFF */;
331 hw->CRTC[17] = (ve & 0x0F) | 0x20;
332 hw->CRTC[18] = vd /* & 0xFF */;
333 hw->CRTC[19] = wd /* & 0xFF */;
334 hw->CRTC[20] = 0x00;
335 hw->CRTC[21] = vd /* & 0xFF */;
336 hw->CRTC[22] = (vt + 1) /* & 0xFF */;
337 hw->CRTC[23] = 0xC3;
338 hw->CRTC[24] = lc;
339 return 0;
340};
341
342void matroxfb_vgaHWrestore(WPMINFO2) {
343 int i;
344 struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw);
345 CRITFLAGS
346
347 DBG(__FUNCTION__)
348
349 dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg);
350 dprintk(KERN_INFO "SEQ regs: ");
351 for (i = 0; i < 5; i++)
352 dprintk("%02X:", hw->SEQ[i]);
353 dprintk("\n");
354 dprintk(KERN_INFO "GDC regs: ");
355 for (i = 0; i < 9; i++)
356 dprintk("%02X:", hw->GCTL[i]);
357 dprintk("\n");
358 dprintk(KERN_INFO "CRTC regs: ");
359 for (i = 0; i < 25; i++)
360 dprintk("%02X:", hw->CRTC[i]);
361 dprintk("\n");
362 dprintk(KERN_INFO "ATTR regs: ");
363 for (i = 0; i < 21; i++)
364 dprintk("%02X:", hw->ATTR[i]);
365 dprintk("\n");
366
367 CRITBEGIN
368
369 mga_inb(M_ATTR_RESET);
370 mga_outb(M_ATTR_INDEX, 0);
371 mga_outb(M_MISC_REG, hw->MiscOutReg);
372 for (i = 1; i < 5; i++)
373 mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]);
374 mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F);
375 for (i = 0; i < 25; i++)
376 mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]);
377 for (i = 0; i < 9; i++)
378 mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]);
379 for (i = 0; i < 21; i++) {
380 mga_inb(M_ATTR_RESET);
381 mga_outb(M_ATTR_INDEX, i);
382 mga_outb(M_ATTR_INDEX, hw->ATTR[i]);
383 }
384 mga_outb(M_PALETTE_MASK, 0xFF);
385 mga_outb(M_DAC_REG, 0x00);
386 for (i = 0; i < 768; i++)
387 mga_outb(M_DAC_VAL, hw->DACpal[i]);
388 mga_inb(M_ATTR_RESET);
389 mga_outb(M_ATTR_INDEX, 0x20);
390
391 CRITEND
392}
393
394static void get_pins(unsigned char __iomem* pins, struct matrox_bios* bd) {
395 unsigned int b0 = readb(pins);
396
397 if (b0 == 0x2E && readb(pins+1) == 0x41) {
398 unsigned int pins_len = readb(pins+2);
399 unsigned int i;
400 unsigned char cksum;
401 unsigned char* dst = bd->pins;
402
403 if (pins_len < 3 || pins_len > 128) {
404 return;
405 }
406 *dst++ = 0x2E;
407 *dst++ = 0x41;
408 *dst++ = pins_len;
409 cksum = 0x2E + 0x41 + pins_len;
410 for (i = 3; i < pins_len; i++) {
411 cksum += *dst++ = readb(pins+i);
412 }
413 if (cksum) {
414 return;
415 }
416 bd->pins_len = pins_len;
417 } else if (b0 == 0x40 && readb(pins+1) == 0x00) {
418 unsigned int i;
419 unsigned char* dst = bd->pins;
420
421 *dst++ = 0x40;
422 *dst++ = 0;
423 for (i = 2; i < 0x40; i++) {
424 *dst++ = readb(pins+i);
425 }
426 bd->pins_len = 0x40;
427 }
428}
429
430static void get_bios_version(unsigned char __iomem * vbios, struct matrox_bios* bd) {
431 unsigned int pcir_offset;
432
433 pcir_offset = readb(vbios + 24) | (readb(vbios + 25) << 8);
434 if (pcir_offset >= 26 && pcir_offset < 0xFFE0 &&
435 readb(vbios + pcir_offset ) == 'P' &&
436 readb(vbios + pcir_offset + 1) == 'C' &&
437 readb(vbios + pcir_offset + 2) == 'I' &&
438 readb(vbios + pcir_offset + 3) == 'R') {
439 unsigned char h;
440
441 h = readb(vbios + pcir_offset + 0x12);
442 bd->version.vMaj = (h >> 4) & 0xF;
443 bd->version.vMin = h & 0xF;
444 bd->version.vRev = readb(vbios + pcir_offset + 0x13);
445 } else {
446 unsigned char h;
447
448 h = readb(vbios + 5);
449 bd->version.vMaj = (h >> 4) & 0xF;
450 bd->version.vMin = h & 0xF;
451 bd->version.vRev = 0;
452 }
453}
454
455static void get_bios_output(unsigned char __iomem* vbios, struct matrox_bios* bd) {
456 unsigned char b;
457
458 b = readb(vbios + 0x7FF1);
459 if (b == 0xFF) {
460 b = 0;
461 }
462 bd->output.state = b;
463}
464
465static void get_bios_tvout(unsigned char __iomem* vbios, struct matrox_bios* bd) {
466 unsigned int i;
467
468 /* Check for 'IBM .*(V....TVO' string - it means TVO BIOS */
469 bd->output.tvout = 0;
470 if (readb(vbios + 0x1D) != 'I' ||
471 readb(vbios + 0x1E) != 'B' ||
472 readb(vbios + 0x1F) != 'M' ||
473 readb(vbios + 0x20) != ' ') {
474 return;
475 }
476 for (i = 0x2D; i < 0x2D + 128; i++) {
477 unsigned char b = readb(vbios + i);
478
479 if (b == '(' && readb(vbios + i + 1) == 'V') {
480 if (readb(vbios + i + 6) == 'T' &&
481 readb(vbios + i + 7) == 'V' &&
482 readb(vbios + i + 8) == 'O') {
483 bd->output.tvout = 1;
484 }
485 return;
486 }
487 if (b == 0)
488 break;
489 }
490}
491
492static void parse_bios(unsigned char __iomem* vbios, struct matrox_bios* bd) {
493 unsigned int pins_offset;
494
495 if (readb(vbios) != 0x55 || readb(vbios + 1) != 0xAA) {
496 return;
497 }
498 bd->bios_valid = 1;
499 get_bios_version(vbios, bd);
500 get_bios_output(vbios, bd);
501 get_bios_tvout(vbios, bd);
502 pins_offset = readb(vbios + 0x7FFC) | (readb(vbios + 0x7FFD) << 8);
503 if (pins_offset <= 0xFF80) {
504 get_pins(vbios + pins_offset, bd);
505 }
506}
507
508#define get_u16(x) (le16_to_cpu(get_unaligned((__u16*)(x))))
509#define get_u32(x) (le32_to_cpu(get_unaligned((__u32*)(x))))
510static int parse_pins1(WPMINFO const struct matrox_bios* bd) {
511 unsigned int maxdac;
512
513 switch (bd->pins[22]) {
514 case 0: maxdac = 175000; break;
515 case 1: maxdac = 220000; break;
516 default: maxdac = 240000; break;
517 }
518 if (get_u16(bd->pins + 24)) {
519 maxdac = get_u16(bd->pins + 24) * 10;
520 }
521 MINFO->limits.pixel.vcomax = maxdac;
522 MINFO->values.pll.system = get_u16(bd->pins + 28) ? get_u16(bd->pins + 28) * 10 : 50000;
523 /* ignore 4MB, 8MB, module clocks */
524 MINFO->features.pll.ref_freq = 14318;
525 MINFO->values.reg.mctlwtst = 0x00030101;
526 return 0;
527}
528
529static void default_pins1(WPMINFO2) {
530 /* Millennium */
531 MINFO->limits.pixel.vcomax = 220000;
532 MINFO->values.pll.system = 50000;
533 MINFO->features.pll.ref_freq = 14318;
534 MINFO->values.reg.mctlwtst = 0x00030101;
535}
536
537static int parse_pins2(WPMINFO const struct matrox_bios* bd) {
538 MINFO->limits.pixel.vcomax =
539 MINFO->limits.system.vcomax = (bd->pins[41] == 0xFF) ? 230000 : ((bd->pins[41] + 100) * 1000);
540 MINFO->values.reg.mctlwtst = ((bd->pins[51] & 0x01) ? 0x00000001 : 0) |
541 ((bd->pins[51] & 0x02) ? 0x00000100 : 0) |
542 ((bd->pins[51] & 0x04) ? 0x00010000 : 0) |
543 ((bd->pins[51] & 0x08) ? 0x00020000 : 0);
544 MINFO->values.pll.system = (bd->pins[43] == 0xFF) ? 50000 : ((bd->pins[43] + 100) * 1000);
545 MINFO->features.pll.ref_freq = 14318;
546 return 0;
547}
548
549static void default_pins2(WPMINFO2) {
550 /* Millennium II, Mystique */
551 MINFO->limits.pixel.vcomax =
552 MINFO->limits.system.vcomax = 230000;
553 MINFO->values.reg.mctlwtst = 0x00030101;
554 MINFO->values.pll.system = 50000;
555 MINFO->features.pll.ref_freq = 14318;
556}
557
558static int parse_pins3(WPMINFO const struct matrox_bios* bd) {
559 MINFO->limits.pixel.vcomax =
560 MINFO->limits.system.vcomax = (bd->pins[36] == 0xFF) ? 230000 : ((bd->pins[36] + 100) * 1000);
561 MINFO->values.reg.mctlwtst = get_u32(bd->pins + 48) == 0xFFFFFFFF ? 0x01250A21 : get_u32(bd->pins + 48);
562 /* memory config */
563 MINFO->values.reg.memrdbk = ((bd->pins[57] << 21) & 0x1E000000) |
564 ((bd->pins[57] << 22) & 0x00C00000) |
565 ((bd->pins[56] << 1) & 0x000001E0) |
566 ( bd->pins[56] & 0x0000000F);
567 MINFO->values.reg.opt = (bd->pins[54] & 7) << 10;
568 MINFO->values.reg.opt2 = bd->pins[58] << 12;
569 MINFO->features.pll.ref_freq = (bd->pins[52] & 0x20) ? 14318 : 27000;
570 return 0;
571}
572
573static void default_pins3(WPMINFO2) {
574 /* G100, G200 */
575 MINFO->limits.pixel.vcomax =
576 MINFO->limits.system.vcomax = 230000;
577 MINFO->values.reg.mctlwtst = 0x01250A21;
578 MINFO->values.reg.memrdbk = 0x00000000;
579 MINFO->values.reg.opt = 0x00000C00;
580 MINFO->values.reg.opt2 = 0x00000000;
581 MINFO->features.pll.ref_freq = 27000;
582}
583
584static int parse_pins4(WPMINFO const struct matrox_bios* bd) {
585 MINFO->limits.pixel.vcomax = (bd->pins[ 39] == 0xFF) ? 230000 : bd->pins[ 39] * 4000;
586 MINFO->limits.system.vcomax = (bd->pins[ 38] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 38] * 4000;
587 MINFO->values.reg.mctlwtst = get_u32(bd->pins + 71);
588 MINFO->values.reg.memrdbk = ((bd->pins[87] << 21) & 0x1E000000) |
589 ((bd->pins[87] << 22) & 0x00C00000) |
590 ((bd->pins[86] << 1) & 0x000001E0) |
591 ( bd->pins[86] & 0x0000000F);
592 MINFO->values.reg.opt = ((bd->pins[53] << 15) & 0x00400000) |
593 ((bd->pins[53] << 22) & 0x10000000) |
594 ((bd->pins[53] << 7) & 0x00001C00);
595 MINFO->values.reg.opt3 = get_u32(bd->pins + 67);
596 MINFO->values.pll.system = (bd->pins[ 65] == 0xFF) ? 200000 : bd->pins[ 65] * 4000;
597 MINFO->features.pll.ref_freq = (bd->pins[ 92] & 0x01) ? 14318 : 27000;
598 return 0;
599}
600
601static void default_pins4(WPMINFO2) {
602 /* G400 */
603 MINFO->limits.pixel.vcomax =
604 MINFO->limits.system.vcomax = 252000;
605 MINFO->values.reg.mctlwtst = 0x04A450A1;
606 MINFO->values.reg.memrdbk = 0x000000E7;
607 MINFO->values.reg.opt = 0x10000400;
608 MINFO->values.reg.opt3 = 0x0190A419;
609 MINFO->values.pll.system = 200000;
610 MINFO->features.pll.ref_freq = 27000;
611}
612
613static int parse_pins5(WPMINFO const struct matrox_bios* bd) {
614 unsigned int mult;
615
616 mult = bd->pins[4]?8000:6000;
617
618 MINFO->limits.pixel.vcomax = (bd->pins[ 38] == 0xFF) ? 600000 : bd->pins[ 38] * mult;
619 MINFO->limits.system.vcomax = (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 36] * mult;
620 MINFO->limits.video.vcomax = (bd->pins[ 37] == 0xFF) ? MINFO->limits.system.vcomax : bd->pins[ 37] * mult;
621 MINFO->limits.pixel.vcomin = (bd->pins[123] == 0xFF) ? 256000 : bd->pins[123] * mult;
622 MINFO->limits.system.vcomin = (bd->pins[121] == 0xFF) ? MINFO->limits.pixel.vcomin : bd->pins[121] * mult;
623 MINFO->limits.video.vcomin = (bd->pins[122] == 0xFF) ? MINFO->limits.system.vcomin : bd->pins[122] * mult;
624 MINFO->values.pll.system =
625 MINFO->values.pll.video = (bd->pins[ 92] == 0xFF) ? 284000 : bd->pins[ 92] * 4000;
626 MINFO->values.reg.opt = get_u32(bd->pins+ 48);
627 MINFO->values.reg.opt2 = get_u32(bd->pins+ 52);
628 MINFO->values.reg.opt3 = get_u32(bd->pins+ 94);
629 MINFO->values.reg.mctlwtst = get_u32(bd->pins+ 98);
630 MINFO->values.reg.memmisc = get_u32(bd->pins+102);
631 MINFO->values.reg.memrdbk = get_u32(bd->pins+106);
632 MINFO->features.pll.ref_freq = (bd->pins[110] & 0x01) ? 14318 : 27000;
633 MINFO->values.memory.ddr = (bd->pins[114] & 0x60) == 0x20;
634 MINFO->values.memory.dll = (bd->pins[115] & 0x02) != 0;
635 MINFO->values.memory.emrswen = (bd->pins[115] & 0x01) != 0;
636 MINFO->values.reg.maccess = MINFO->values.memory.emrswen ? 0x00004000 : 0x00000000;
637 if (bd->pins[115] & 4) {
638 MINFO->values.reg.mctlwtst_core = MINFO->values.reg.mctlwtst;
639 } else {
640 u_int32_t wtst_xlat[] = { 0, 1, 5, 6, 7, 5, 2, 3 };
641 MINFO->values.reg.mctlwtst_core = (MINFO->values.reg.mctlwtst & ~7) |
642 wtst_xlat[MINFO->values.reg.mctlwtst & 7];
643 }
644 return 0;
645}
646
647static void default_pins5(WPMINFO2) {
648 /* Mine 16MB G450 with SDRAM DDR */
649 MINFO->limits.pixel.vcomax =
650 MINFO->limits.system.vcomax =
651 MINFO->limits.video.vcomax = 600000;
652 MINFO->limits.pixel.vcomin =
653 MINFO->limits.system.vcomin =
654 MINFO->limits.video.vcomin = 256000;
655 MINFO->values.pll.system =
656 MINFO->values.pll.video = 284000;
657 MINFO->values.reg.opt = 0x404A1160;
658 MINFO->values.reg.opt2 = 0x0000AC00;
659 MINFO->values.reg.opt3 = 0x0090A409;
660 MINFO->values.reg.mctlwtst_core =
661 MINFO->values.reg.mctlwtst = 0x0C81462B;
662 MINFO->values.reg.memmisc = 0x80000004;
663 MINFO->values.reg.memrdbk = 0x01001103;
664 MINFO->features.pll.ref_freq = 27000;
665 MINFO->values.memory.ddr = 1;
666 MINFO->values.memory.dll = 1;
667 MINFO->values.memory.emrswen = 1;
668 MINFO->values.reg.maccess = 0x00004000;
669}
670
671static int matroxfb_set_limits(WPMINFO const struct matrox_bios* bd) {
672 unsigned int pins_version;
673 static const unsigned int pinslen[] = { 64, 64, 64, 128, 128 };
674
675 switch (ACCESS_FBINFO(chip)) {
676 case MGA_2064: default_pins1(PMINFO2); break;
677 case MGA_2164:
678 case MGA_1064:
679 case MGA_1164: default_pins2(PMINFO2); break;
680 case MGA_G100:
681 case MGA_G200: default_pins3(PMINFO2); break;
682 case MGA_G400: default_pins4(PMINFO2); break;
683 case MGA_G450:
684 case MGA_G550: default_pins5(PMINFO2); break;
685 }
686 if (!bd->bios_valid) {
687 printk(KERN_INFO "matroxfb: Your Matrox device does not have BIOS\n");
688 return -1;
689 }
690 if (bd->pins_len < 64) {
691 printk(KERN_INFO "matroxfb: BIOS on your Matrox device does not contain powerup info\n");
692 return -1;
693 }
694 if (bd->pins[0] == 0x2E && bd->pins[1] == 0x41) {
695 pins_version = bd->pins[5];
696 if (pins_version < 2 || pins_version > 5) {
697 printk(KERN_INFO "matroxfb: Unknown version (%u) of powerup info\n", pins_version);
698 return -1;
699 }
700 } else {
701 pins_version = 1;
702 }
703 if (bd->pins_len != pinslen[pins_version - 1]) {
704 printk(KERN_INFO "matroxfb: Invalid powerup info\n");
705 return -1;
706 }
707 switch (pins_version) {
708 case 1:
709 return parse_pins1(PMINFO bd);
710 case 2:
711 return parse_pins2(PMINFO bd);
712 case 3:
713 return parse_pins3(PMINFO bd);
714 case 4:
715 return parse_pins4(PMINFO bd);
716 case 5:
717 return parse_pins5(PMINFO bd);
718 default:
719 printk(KERN_DEBUG "matroxfb: Powerup info version %u is not yet supported\n", pins_version);
720 return -1;
721 }
722}
723
724void matroxfb_read_pins(WPMINFO2) {
725 u32 opt;
726 u32 biosbase;
727 u32 fbbase;
728 struct pci_dev* pdev = ACCESS_FBINFO(pcidev);
729
730 memset(&ACCESS_FBINFO(bios), 0, sizeof(ACCESS_FBINFO(bios)));
731 pci_read_config_dword(pdev, PCI_OPTION_REG, &opt);
732 pci_write_config_dword(pdev, PCI_OPTION_REG, opt | PCI_OPTION_ENABLE_ROM);
733 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &biosbase);
734 pci_read_config_dword(pdev, ACCESS_FBINFO(devflags.fbResource), &fbbase);
735 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, (fbbase & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
736 parse_bios(vaddr_va(ACCESS_FBINFO(video).vbase), &ACCESS_FBINFO(bios));
737 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, biosbase);
738 pci_write_config_dword(pdev, PCI_OPTION_REG, opt);
739#ifdef CONFIG_X86
740 if (!ACCESS_FBINFO(bios).bios_valid) {
741 unsigned char __iomem* b;
742
743 b = ioremap(0x000C0000, 65536);
744 if (!b) {
745 printk(KERN_INFO "matroxfb: Unable to map legacy BIOS\n");
746 } else {
747 unsigned int ven = readb(b+0x64+0) | (readb(b+0x64+1) << 8);
748 unsigned int dev = readb(b+0x64+2) | (readb(b+0x64+3) << 8);
749
750 if (ven != pdev->vendor || dev != pdev->device) {
751 printk(KERN_INFO "matroxfb: Legacy BIOS is for %04X:%04X, while this device is %04X:%04X\n",
752 ven, dev, pdev->vendor, pdev->device);
753 } else {
754 parse_bios(b, &ACCESS_FBINFO(bios));
755 }
756 iounmap(b);
757 }
758 }
759#endif
760 matroxfb_set_limits(PMINFO &ACCESS_FBINFO(bios));
761}
762
763EXPORT_SYMBOL(matroxfb_DAC_in);
764EXPORT_SYMBOL(matroxfb_DAC_out);
765EXPORT_SYMBOL(matroxfb_var2my);
766EXPORT_SYMBOL(matroxfb_PLL_calcclock);
767#ifndef CONFIG_FB_MATROX_MULTIHEAD
768struct matrox_fb_info matroxfb_global_mxinfo;
769EXPORT_SYMBOL(matroxfb_global_mxinfo);
770#endif
771EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */
772EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */
773EXPORT_SYMBOL(matroxfb_read_pins);
774
775MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
776MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards");
777MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_misc.h b/drivers/video/matrox/matroxfb_misc.h
new file mode 100644
index 000000000000..cb62cc0ead96
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_misc.h
@@ -0,0 +1,18 @@
1#ifndef __MATROXFB_MISC_H__
2#define __MATROXFB_MISC_H__
3
4#include "matroxfb_base.h"
5
6/* also for modules */
7int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax,
8 unsigned int* in, unsigned int* feed, unsigned int* post);
9static inline int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax,
10 unsigned int* in, unsigned int* feed, unsigned int* post) {
11 return matroxfb_PLL_calcclock(&ACCESS_FBINFO(features.pll), freq, fmax, in, feed, post);
12}
13
14int matroxfb_vgaHWinit(WPMINFO struct my_timming* m);
15void matroxfb_vgaHWrestore(WPMINFO2);
16void matroxfb_read_pins(WPMINFO2);
17
18#endif /* __MATROXFB_MISC_H__ */