Import 2.3.18pre1
[davej-history.git] / drivers / video / matroxfb.c
blob4b0ffb0ade3a52f09fd6ac5adb4afdad0c659816
1 /*
3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
5 * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>
7 * Version: 1.19 1999/08/05
9 * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
11 * Contributors: "menion?" <menion@mindless.com>
12 * Betatesting, fixes, ideas
14 * "Kurt Garloff" <garloff@kg1.ping.de>
15 * Betatesting, fixes, ideas, videomodes, videomodes timmings
17 * "Tom Rini" <trini@disparity.net>
18 * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
20 * "Bibek Sahu" <scorpio@dodds.net>
21 * Access device through readb|w|l and write b|w|l
22 * Extensive debugging stuff
24 * "Daniel Haun" <haund@usa.net>
25 * Testing, hardware cursor fixes
27 * "Scott Wood" <sawst46+@pitt.edu>
28 * Fixes
30 * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
31 * Betatesting
33 * "Kelly French" <targon@hazmat.com>
34 * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
35 * Betatesting, bug reporting
37 * "Pablo Bianucci" <pbian@pccp.com.ar>
38 * Fixes, ideas, betatesting
40 * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
41 * Fixes, enhandcements, ideas, betatesting
43 * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
44 * PPC betatesting, PPC support, backward compatibility
46 * "Paul Womar" <Paul@pwomar.demon.co.uk>
47 * "Owen Waller" <O.Waller@ee.qub.ac.uk>
48 * PPC betatesting
50 * "Thomas Pornin" <pornin@bolet.ens.fr>
51 * Alpha betatesting
53 * "Pieter van Leuven" <pvl@iae.nl>
54 * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
55 * G100 testing
57 * "H. Peter Arvin" <hpa@transmeta.com>
58 * Ideas
60 * "Cort Dougan" <cort@cs.nmt.edu>
61 * CHRP fixes and PReP cleanup
63 * "Mark Vojkovich" <mvojkovi@ucsd.edu>
64 * G400 support
66 * (following author is not in any relation with this code, but his code
67 * is included in this driver)
69 * Based on framebuffer driver for VBE 2.0 compliant graphic boards
70 * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
72 * (following author is not in any relation with this code, but his ideas
73 * were used when writting this driver)
75 * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
77 */
79 /* general, but fairly heavy, debugging */
80 #undef MATROXFB_DEBUG
82 /* heavy debugging: */
83 /* -- logs putc[s], so everytime a char is displayed, it's logged */
84 #undef MATROXFB_DEBUG_HEAVY
86 /* This one _could_ cause infinite loops */
87 /* It _does_ cause lots and lots of messages during idle loops */
88 #undef MATROXFB_DEBUG_LOOP
90 /* Debug register calls, too? */
91 #undef MATROXFB_DEBUG_REG
93 /* Log reentrancy attempts - you must have printstate() patch applied */
94 #undef MATROXFB_DEBUG_REENTER
95 /* you must define DEBUG_REENTER to get debugged CONSOLEBH... */
96 #undef MATROXFB_DEBUG_CONSOLEBH
98 #include <linux/config.h>
99 #include <linux/module.h>
100 #include <linux/kernel.h>
101 #include <linux/errno.h>
102 #include <linux/string.h>
103 #include <linux/mm.h>
104 #include <linux/tty.h>
105 #include <linux/malloc.h>
106 #include <linux/delay.h>
107 #include <linux/fb.h>
108 #include <linux/console.h>
109 #include <linux/selection.h>
110 #include <linux/ioport.h>
111 #include <linux/init.h>
112 #include <linux/timer.h>
113 #include <linux/pci.h>
114 #include <linux/spinlock.h>
116 #include <asm/io.h>
117 #include <asm/unaligned.h>
118 #ifdef CONFIG_MTRR
119 #include <asm/mtrr.h>
120 #endif
122 #include <video/fbcon.h>
123 #include <video/fbcon-cfb4.h>
124 #include <video/fbcon-cfb8.h>
125 #include <video/fbcon-cfb16.h>
126 #include <video/fbcon-cfb24.h>
127 #include <video/fbcon-cfb32.h>
129 #if defined(CONFIG_FB_OF)
130 #if defined(CONFIG_FB_COMPAT_XPMAC)
131 #include <asm/vc_ioctl.h>
132 #endif
133 #include <asm/prom.h>
134 #include <asm/pci-bridge.h>
135 #include <video/macmodes.h>
136 #endif
138 /* always compile support for 32MB... It cost almost nothing */
139 #define CONFIG_FB_MATROX_32MB
141 #define FBCON_HAS_VGATEXT
143 #ifdef MATROXFB_DEBUG
145 #define DEBUG
146 #define DBG(x) printk(KERN_DEBUG "matroxfb: %s\n", (x));
148 #ifdef MATROXFB_DEBUG_HEAVY
149 #define DBG_HEAVY(x) DBG(x)
150 #else /* MATROXFB_DEBUG_HEAVY */
151 #define DBG_HEAVY(x) /* DBG_HEAVY */
152 #endif /* MATROXFB_DEBUG_HEAVY */
154 #ifdef MATROXFB_DEBUG_LOOP
155 #define DBG_LOOP(x) DBG(x)
156 #else /* MATROXFB_DEBUG_LOOP */
157 #define DBG_LOOP(x) /* DBG_LOOP */
158 #endif /* MATROXFB_DEBUG_LOOP */
160 #ifdef MATROXFB_DEBUG_REG
161 #define DBG_REG(x) DBG(x)
162 #else /* MATROXFB_DEBUG_REG */
163 #define DBG_REG(x) /* DBG_REG */
164 #endif /* MATROXFB_DEBUG_REG */
166 #else /* MATROXFB_DEBUG */
168 #define DBG(x) /* DBG */
169 #define DBG_HEAVY(x) /* DBG_HEAVY */
170 #define DBG_REG(x) /* DBG_REG */
171 #define DBG_LOOP(x) /* DBG_LOOP */
173 #endif /* MATROXFB_DEBUG */
175 #ifndef __i386__
176 #ifndef ioremap_nocache
177 #define ioremap_nocache(X,Y) ioremap(X,Y)
178 #endif
179 #endif
181 #if defined(__alpha__) || defined(__m68k__)
182 #define READx_WORKS
183 #define MEMCPYTOIO_WORKS
184 #else
185 #define READx_FAILS
186 /* recheck __ppc__, maybe that __ppc__ needs MEMCPYTOIO_WRITEL */
187 /* I benchmarked PII/350MHz with G200... MEMCPY, MEMCPYTOIO and WRITEL are on same speed ( <2% diff) */
188 /* so that means that G200 speed (or AGP speed?) is our limit... I do not have benchmark to test, how */
189 /* much of PCI bandwidth is used during transfers... */
190 #if defined(__i386__)
191 #define MEMCPYTOIO_MEMCPY
192 #else
193 #define MEMCPYTOIO_WRITEL
194 #endif
195 #endif
197 #ifdef __sparc__
198 #error "Sorry, I have no idea how to do this on sparc... There is mapioaddr... With bus_type parameter..."
199 #endif
201 #if defined(__m68k__)
202 #define MAP_BUSTOVIRT
203 #else
204 #define MAP_IOREMAP
205 #endif
207 #ifdef DEBUG
208 #define dprintk(X...) printk(X)
209 #else
210 #define dprintk(X...)
211 #endif
213 #ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF
214 #define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF 0x110A
215 #endif
216 #ifndef PCI_SS_VENDOR_ID_MATROX
217 #define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX
218 #endif
219 #ifndef PCI_DEVICE_ID_MATROX_G200_PCI
220 #define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520
221 #endif
222 #ifndef PCI_DEVICE_ID_MATROX_G200_AGP
223 #define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521
224 #endif
225 #ifndef PCI_DEVICE_ID_MATROX_G100
226 #define PCI_DEVICE_ID_MATROX_G100 0x1000
227 #endif
228 #ifndef PCI_DEVICE_ID_MATROX_G100_AGP
229 #define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001
230 #endif
231 #ifndef PCI_DEVICE_ID_MATROX_G400_AGP
232 #define PCI_DEVICE_ID_MATROX_G400_AGP 0x0525
233 #endif
235 #ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
236 #define PCI_SS_ID_MATROX_GENERIC 0xFF00
237 #define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP 0xFF01
238 #define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP 0xFF02
239 #define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP 0xFF03
240 #define PCI_SS_ID_MATROX_MARVEL_G200_AGP 0xFF04
241 #define PCI_SS_ID_MATROX_MGA_G100_PCI 0xFF05
242 #define PCI_SS_ID_MATROX_MGA_G100_AGP 0x1001
243 #define PCI_SS_ID_SIEMENS_MGA_G100_AGP 0x001E /* 30 */
244 #define PCI_SS_ID_SIEMENS_MGA_G200_AGP 0x0032 /* 50 */
245 #endif
247 #define MX_VISUAL_TRUECOLOR FB_VISUAL_DIRECTCOLOR
248 #define MX_VISUAL_DIRECTCOLOR FB_VISUAL_TRUECOLOR
249 #define MX_VISUAL_PSEUDOCOLOR FB_VISUAL_PSEUDOCOLOR
251 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
253 /* G100, G200 and Mystique have (almost) same DAC */
254 #undef NEED_DAC1064
255 #if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G100)
256 #define NEED_DAC1064 1
257 #endif
259 typedef struct {
260 u_int8_t* vaddr;
261 } vaddr_t;
263 #ifdef READx_WORKS
264 static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) {
265 return readb(va.vaddr + offs);
268 static inline unsigned int mga_readw(vaddr_t va, unsigned int offs) {
269 return readw(va.vaddr + offs);
272 static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) {
273 return readl(va.vaddr + offs);
276 static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) {
277 writeb(value, va.vaddr + offs);
280 static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) {
281 writew(value, va.vaddr + offs);
284 static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) {
285 writel(value, va.vaddr + offs);
287 #else
288 static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) {
289 return *(volatile u_int8_t*)(va.vaddr + offs);
292 static inline unsigned int mga_readw(vaddr_t va, unsigned int offs) {
293 return *(volatile u_int16_t*)(va.vaddr + offs);
296 static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) {
297 return *(volatile u_int32_t*)(va.vaddr + offs);
300 static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) {
301 *(volatile u_int8_t*)(va.vaddr + offs) = value;
304 static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) {
305 *(volatile u_int16_t*)(va.vaddr + offs) = value;
308 static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) {
309 *(volatile u_int32_t*)(va.vaddr + offs) = value;
311 #endif
313 static inline void mga_memcpy_toio(vaddr_t va, unsigned int offs, const void* src, int len) {
314 #ifdef MEMCPYTOIO_WORKS
315 memcpy_toio(va.vaddr + offs, src, len);
316 #elif defined(MEMCPYTOIO_WRITEL)
317 #define srcd ((const u_int32_t*)src)
318 if (offs & 3) {
319 while (len >= 4) {
320 mga_writel(va, offs, get_unaligned(srcd++));
321 offs += 4;
322 len -= 4;
324 } else {
325 while (len >= 4) {
326 mga_writel(va, offs, *srcd++);
327 offs += 4;
328 len -= 4;
331 #undef srcd
332 if (len) {
333 u_int32_t tmp;
335 memcpy(&tmp, src, len);
336 mga_writel(va, offs, tmp);
338 #elif defined(MEMCPYTOIO_MEMCPY)
339 memcpy(va.vaddr + offs, src, len);
340 #else
341 #error "Sorry, do not know how to write block of data to device"
342 #endif
345 static inline void vaddr_add(vaddr_t* va, unsigned long offs) {
346 va->vaddr += offs;
349 static inline void* vaddr_va(vaddr_t va) {
350 return va.vaddr;
353 #define MGA_IOREMAP_NORMAL 0
354 #define MGA_IOREMAP_NOCACHE 1
356 #define MGA_IOREMAP_FB MGA_IOREMAP_NOCACHE
357 #define MGA_IOREMAP_MMIO MGA_IOREMAP_NOCACHE
358 static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags, vaddr_t* virt) {
359 #ifdef MAP_IOREMAP
360 if (flags & MGA_IOREMAP_NOCACHE)
361 virt->vaddr = ioremap_nocache(phys, size);
362 else
363 virt->vaddr = ioremap(phys, size);
364 #else
365 #ifdef MAP_BUSTOVIRT
366 virt->vaddr = bus_to_virt(phys);
367 #else
368 #error "Your architecture does not have neither ioremap nor bus_to_virt... Giving up"
369 #endif
370 #endif
371 return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */
374 static inline void mga_iounmap(vaddr_t va) {
375 #ifdef MAP_IOREMAP
376 iounmap(va.vaddr);
377 #endif
380 struct matroxfb_par
382 unsigned int final_bppShift;
383 unsigned int cmap_len;
384 struct {
385 unsigned int bytes;
386 unsigned int pixels;
387 unsigned int chunks;
388 } ydstorg;
389 void (*putc)(u_int32_t, u_int32_t, struct display*, int, int, int);
390 void (*putcs)(u_int32_t, u_int32_t, struct display*, const unsigned short*, int, int, int);
393 struct my_timming {
394 unsigned int pixclock;
395 unsigned int HDisplay;
396 unsigned int HSyncStart;
397 unsigned int HSyncEnd;
398 unsigned int HTotal;
399 unsigned int VDisplay;
400 unsigned int VSyncStart;
401 unsigned int VSyncEnd;
402 unsigned int VTotal;
403 unsigned int sync;
404 int dblscan;
405 int interlaced;
408 struct matrox_fb_info;
410 #define MATROX_2MB_WITH_4MB_ADDON
412 struct matrox_pll_features {
413 unsigned int vco_freq_min;
414 unsigned int ref_freq;
415 unsigned int feed_div_min;
416 unsigned int feed_div_max;
417 unsigned int in_div_min;
418 unsigned int in_div_max;
419 unsigned int post_shift_max;
422 struct matrox_DAC1064_features {
423 u_int8_t xvrefctrl;
424 unsigned int cursorimage;
427 struct matrox_accel_features {
428 int has_cacheflush;
431 /* current hardware status */
432 struct matrox_hw_state {
433 u_int32_t MXoptionReg;
434 unsigned char DACclk[6];
435 unsigned char DACreg[64];
436 unsigned char MiscOutReg;
437 unsigned char DACpal[768];
438 unsigned char CRTC[25];
439 unsigned char CRTCEXT[9];
440 unsigned char SEQ[5];
441 /* unused for MGA mode, but who knows... */
442 unsigned char GCTL[9];
443 /* unused for MGA mode, but who knows... */
444 unsigned char ATTR[21];
447 struct matrox_accel_data {
448 #ifdef CONFIG_FB_MATROX_MILLENIUM
449 unsigned char ramdac_rev;
450 #endif
451 u_int32_t m_dwg_rect;
452 u_int32_t m_opmode;
455 #ifdef CONFIG_FB_MATROX_MULTIHEAD
456 #define ACCESS_FBINFO2(info, x) (info->x)
457 #define ACCESS_FBINFO(x) ACCESS_FBINFO2(minfo,x)
459 #define MINFO minfo
461 #define WPMINFO struct matrox_fb_info* minfo,
462 #define CPMINFO const struct matrox_fb_info* minfo,
463 #define PMINFO minfo,
465 static inline struct matrox_fb_info* mxinfo(const struct display* p) {
466 return (struct matrox_fb_info*)p->fb_info;
469 #define PMXINFO(p) mxinfo(p),
470 #define MINFO_FROM(x) struct matrox_fb_info* minfo = x
471 #define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x))
473 #else
475 struct matrox_fb_info global_mxinfo;
476 struct display global_disp;
478 #define ACCESS_FBINFO(x) (global_mxinfo.x)
479 #define ACCESS_FBINFO2(info, x) (global_mxinfo.x)
481 #define MINFO (&global_mxinfo)
483 #define WPMINFO
484 #define CPMINFO
485 #define PMINFO
487 #if 0
488 static inline struct matrox_fb_info* mxinfo(const struct display* p) {
489 return &global_mxinfo;
491 #endif
493 #define PMXINFO(p)
494 #define MINFO_FROM(x)
495 #define MINFO_FROM_DISP(x)
497 #endif
499 struct matrox_switch {
500 int (*preinit)(WPMINFO struct matrox_hw_state*);
501 void (*reset)(WPMINFO struct matrox_hw_state*);
502 int (*init)(CPMINFO struct matrox_hw_state*, struct my_timming*, struct display*);
503 void (*restore)(WPMINFO struct matrox_hw_state*, struct matrox_hw_state*, struct display*);
506 struct matrox_fb_info {
507 /* fb_info must be first */
508 struct fb_info fbcon;
510 struct matrox_fb_info* next_fb;
512 struct matroxfb_par curr;
513 struct matrox_hw_state hw1;
514 struct matrox_hw_state hw2;
515 struct matrox_hw_state* newhw;
516 struct matrox_hw_state* currenthw;
518 struct matrox_accel_data accel;
520 struct pci_dev* pcidev;
522 struct {
523 unsigned long base; /* physical */
524 vaddr_t vbase; /* CPU view */
525 unsigned int len;
526 unsigned int len_usable;
527 } video;
529 struct {
530 unsigned long base; /* physical */
531 vaddr_t vbase; /* CPU view */
532 unsigned int len;
533 } mmio;
535 unsigned int max_pixel_clock;
537 struct matrox_switch* hw_switch;
538 int currcon;
539 struct display* currcon_display;
541 struct {
542 struct matrox_pll_features pll;
543 struct matrox_DAC1064_features DAC1064;
544 struct matrox_accel_features accel;
545 } features;
546 struct {
547 spinlock_t DAC;
548 } lock;
550 int interleave;
551 int millenium;
552 int milleniumII;
553 struct {
554 int cfb4;
555 const int* vxres;
556 int cross4MB;
557 int text;
558 int plnwt;
559 } capable;
560 struct {
561 unsigned int size;
562 unsigned int mgabase;
563 vaddr_t vbase;
564 } fastfont;
565 #ifdef CONFIG_MTRR
566 struct {
567 int vram;
568 int vram_valid;
569 } mtrr;
570 #endif
571 struct {
572 int precise_width;
573 int mga_24bpp_fix;
574 int novga;
575 int nobios;
576 int nopciretry;
577 int noinit;
578 int inverse;
579 int hwcursor;
580 int blink;
581 int sgram;
582 #ifdef CONFIG_FB_MATROX_32MB
583 int support32MB;
584 #endif
586 int accelerator;
587 int text_type_aux;
588 int video64bits;
589 unsigned int vgastep;
590 unsigned int vgastepdisp;
591 unsigned int textmode;
592 unsigned int textstep;
593 unsigned int textvram; /* character cells */
594 unsigned int ydstorg; /* offset in bytes from video start to usable memory */
595 /* 0 except for 6MB Millenium */
596 } devflags;
597 struct display_switch dispsw;
598 struct {
599 int x;
600 int y;
601 unsigned int w;
602 unsigned int u;
603 unsigned int d;
604 unsigned int type;
605 int state;
606 int redraw;
607 struct timer_list timer;
608 } cursor;
609 #if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
610 union {
611 #ifdef FBCON_HAS_CFB16
612 u_int16_t cfb16[16];
613 #endif
614 #ifdef FBCON_HAS_CFB24
615 u_int32_t cfb24[16];
616 #endif
617 #ifdef FBCON_HAS_CFB32
618 u_int32_t cfb32[16];
619 #endif
620 } cmap;
621 #endif
622 struct { unsigned red, green, blue, transp; } palette[256];
623 #if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC)
624 char matrox_name[32];
625 #endif
628 #if defined(CONFIG_FB_OF)
629 unsigned char nvram_read_byte(int);
630 int matrox_of_init(struct device_node *dp);
631 static int default_vmode = VMODE_NVRAM;
632 static int default_cmode = CMODE_NVRAM;
633 #endif
635 #define curr_ydstorg(x) ACCESS_FBINFO2(x, curr.ydstorg.pixels)
637 #define PCI_OPTION_REG 0x40
638 #define PCI_MGA_INDEX 0x44
639 #define PCI_MGA_DATA 0x48
641 #define M_DWGCTL 0x1C00
642 #define M_MACCESS 0x1C04
643 #define M_CTLWTST 0x1C08
645 #define M_PLNWT 0x1C1C
647 #define M_BCOL 0x1C20
648 #define M_FCOL 0x1C24
650 #define M_SGN 0x1C58
651 #define M_LEN 0x1C5C
652 #define M_AR0 0x1C60
653 #define M_AR1 0x1C64
654 #define M_AR2 0x1C68
655 #define M_AR3 0x1C6C
656 #define M_AR4 0x1C70
657 #define M_AR5 0x1C74
658 #define M_AR6 0x1C78
660 #define M_CXBNDRY 0x1C80
661 #define M_FXBNDRY 0x1C84
662 #define M_YDSTLEN 0x1C88
663 #define M_PITCH 0x1C8C
664 #define M_YDST 0x1C90
665 #define M_YDSTORG 0x1C94
666 #define M_YTOP 0x1C98
667 #define M_YBOT 0x1C9C
669 /* mystique only */
670 #define M_CACHEFLUSH 0x1FFF
672 #define M_EXEC 0x0100
674 #define M_DWG_TRAP 0x04
675 #define M_DWG_BITBLT 0x08
676 #define M_DWG_ILOAD 0x09
678 #define M_DWG_LINEAR 0x0080
679 #define M_DWG_SOLID 0x0800
680 #define M_DWG_ARZERO 0x1000
681 #define M_DWG_SGNZERO 0x2000
682 #define M_DWG_SHIFTZERO 0x4000
684 #define M_DWG_REPLACE 0x000C0000
685 #define M_DWG_REPLACE2 (M_DWG_REPLACE | 0x40)
686 #define M_DWG_XOR 0x00060010
688 #define M_DWG_BFCOL 0x04000000
689 #define M_DWG_BMONOWF 0x08000000
691 #define M_DWG_TRANSC 0x40000000
693 #define M_FIFOSTATUS 0x1E10
694 #define M_STATUS 0x1E14
696 #define M_IEN 0x1E1C
698 #define M_VCOUNT 0x1E20
700 #define M_RESET 0x1E40
702 #define M_AGP2PLL 0x1E4C
704 #define M_OPMODE 0x1E54
705 #define M_OPMODE_DMA_GEN_WRITE 0x00
706 #define M_OPMODE_DMA_BLIT 0x04
707 #define M_OPMODE_DMA_VECTOR_WRITE 0x08
708 #define M_OPMODE_DMA_LE 0x0000 /* little endian - no transformation */
709 #define M_OPMODE_DMA_BE_8BPP 0x0000
710 #define M_OPMODE_DMA_BE_16BPP 0x0100
711 #define M_OPMODE_DMA_BE_32BPP 0x0200
712 #define M_OPMODE_DIR_LE 0x000000 /* little endian - no transformation */
713 #define M_OPMODE_DIR_BE_8BPP 0x000000
714 #define M_OPMODE_DIR_BE_16BPP 0x010000
715 #define M_OPMODE_DIR_BE_32BPP 0x020000
717 #define M_ATTR_INDEX 0x1FC0
718 #define M_ATTR_DATA 0x1FC1
720 #define M_MISC_REG 0x1FC2
721 #define M_3C2_RD 0x1FC2
723 #define M_SEQ_INDEX 0x1FC4
724 #define M_SEQ_DATA 0x1FC5
726 #define M_MISC_REG_READ 0x1FCC
728 #define M_GRAPHICS_INDEX 0x1FCE
729 #define M_GRAPHICS_DATA 0x1FCF
731 #define M_CRTC_INDEX 0x1FD4
733 #define M_ATTR_RESET 0x1FDA
734 #define M_3DA_WR 0x1FDA
736 #define M_EXTVGA_INDEX 0x1FDE
737 #define M_EXTVGA_DATA 0x1FDF
739 /* G200 only */
740 #define M_SRCORG 0x2CB4
742 #define M_RAMDAC_BASE 0x3C00
744 /* fortunately, same on TVP3026 and MGA1064 */
745 #define M_DAC_REG (M_RAMDAC_BASE+0)
746 #define M_DAC_VAL (M_RAMDAC_BASE+1)
747 #define M_PALETTE_MASK (M_RAMDAC_BASE+2)
749 #define M_X_INDEX 0x00
750 #define M_X_DATAREG 0x0A
752 #define DAC_XGENIOCTRL 0x2A
753 #define DAC_XGENIODATA 0x2B
755 #ifdef CONFIG_FB_MATROX_MILLENIUM
756 #define TVP3026_INDEX 0x00
757 #define TVP3026_PALWRADD 0x00
758 #define TVP3026_PALDATA 0x01
759 #define TVP3026_PIXRDMSK 0x02
760 #define TVP3026_PALRDADD 0x03
761 #define TVP3026_CURCOLWRADD 0x04
762 #define TVP3026_CLOVERSCAN 0x00
763 #define TVP3026_CLCOLOR0 0x01
764 #define TVP3026_CLCOLOR1 0x02
765 #define TVP3026_CLCOLOR2 0x03
766 #define TVP3026_CURCOLDATA 0x05
767 #define TVP3026_CURCOLRDADD 0x07
768 #define TVP3026_CURCTRL 0x09
769 #define TVP3026_X_DATAREG 0x0A
770 #define TVP3026_CURRAMDATA 0x0B
771 #define TVP3026_CURPOSXL 0x0C
772 #define TVP3026_CURPOSXH 0x0D
773 #define TVP3026_CURPOSYL 0x0E
774 #define TVP3026_CURPOSYH 0x0F
776 #define TVP3026_XSILICONREV 0x01
777 #define TVP3026_XCURCTRL 0x06
778 #define TVP3026_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */
779 #define TVP3026_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
780 #define TVP3026_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
781 #define TVP3026_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
782 #define TVP3026_XCURCTRL_BLANK2048 0x00
783 #define TVP3026_XCURCTRL_BLANK4096 0x10
784 #define TVP3026_XCURCTRL_INTERLACED 0x20
785 #define TVP3026_XCURCTRL_ODD 0x00 /* ext.signal ODD/\EVEN */
786 #define TVP3026_XCURCTRL_EVEN 0x40 /* ext.signal EVEN/\ODD */
787 #define TVP3026_XCURCTRL_INDIRECT 0x00
788 #define TVP3026_XCURCTRL_DIRECT 0x80
789 #define TVP3026_XLATCHCTRL 0x0F
790 #define TVP3026_XLATCHCTRL_1_1 0x06
791 #define TVP3026_XLATCHCTRL_2_1 0x07
792 #define TVP3026_XLATCHCTRL_4_1 0x06
793 #define TVP3026_XLATCHCTRL_8_1 0x06
794 #define TVP3026_XLATCHCTRL_16_1 0x06
795 #define TVP3026A_XLATCHCTRL_4_3 0x06 /* ??? do not understand... but it works... !!! */
796 #define TVP3026A_XLATCHCTRL_8_3 0x07
797 #define TVP3026B_XLATCHCTRL_4_3 0x08
798 #define TVP3026B_XLATCHCTRL_8_3 0x06 /* ??? do not understand... but it works... !!! */
799 #define TVP3026_XTRUECOLORCTRL 0x18
800 #define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL 0x00
801 #define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP 0x20
802 #define TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR 0x80
803 #define TVP3026_XTRUECOLORCTRL_TRUECOLOR 0x40 /* paletized */
804 #define TVP3026_XTRUECOLORCTRL_DIRECTCOLOR 0x00
805 #define TVP3026_XTRUECOLORCTRL_24_ALTERNATE 0x08 /* 5:4/5:2 instead of 4:3/8:3 */
806 #define TVP3026_XTRUECOLORCTRL_RGB_888 0x16 /* 4:3/8:3 (or 5:4/5:2) */
807 #define TVP3026_XTRUECOLORCTRL_BGR_888 0x17
808 #define TVP3026_XTRUECOLORCTRL_ORGB_8888 0x06
809 #define TVP3026_XTRUECOLORCTRL_BGRO_8888 0x07
810 #define TVP3026_XTRUECOLORCTRL_RGB_565 0x05
811 #define TVP3026_XTRUECOLORCTRL_ORGB_1555 0x04
812 #define TVP3026_XTRUECOLORCTRL_RGB_664 0x03
813 #define TVP3026_XTRUECOLORCTRL_RGBO_4444 0x01
814 #define TVP3026_XMUXCTRL 0x19
815 #define TVP3026_XMUXCTRL_MEMORY_8BIT 0x01 /* - */
816 #define TVP3026_XMUXCTRL_MEMORY_16BIT 0x02 /* - */
817 #define TVP3026_XMUXCTRL_MEMORY_32BIT 0x03 /* 2MB RAM, 512K * 4 */
818 #define TVP3026_XMUXCTRL_MEMORY_64BIT 0x04 /* >2MB RAM, 512K * 8 & more */
819 #define TVP3026_XMUXCTRL_PIXEL_4BIT 0x40 /* L0,H0,L1,H1... */
820 #define TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED 0x60 /* H0,L0,H1,L1... */
821 #define TVP3026_XMUXCTRL_PIXEL_8BIT 0x48
822 #define TVP3026_XMUXCTRL_PIXEL_16BIT 0x50
823 #define TVP3026_XMUXCTRL_PIXEL_32BIT 0x58
824 #define TVP3026_XMUXCTRL_VGA 0x98 /* VGA MEMORY, 8BIT PIXEL */
825 #define TVP3026_XCLKCTRL 0x1A
826 #define TVP3026_XCLKCTRL_DIV1 0x00
827 #define TVP3026_XCLKCTRL_DIV2 0x10
828 #define TVP3026_XCLKCTRL_DIV4 0x20
829 #define TVP3026_XCLKCTRL_DIV8 0x30
830 #define TVP3026_XCLKCTRL_DIV16 0x40
831 #define TVP3026_XCLKCTRL_DIV32 0x50
832 #define TVP3026_XCLKCTRL_DIV64 0x60
833 #define TVP3026_XCLKCTRL_CLKSTOPPED 0x70
834 #define TVP3026_XCLKCTRL_SRC_CLK0 0x00
835 #define TVP3026_XCLKCTRL_SRC_CLK1 0x01
836 #define TVP3026_XCLKCTRL_SRC_CLK2 0x02 /* CLK2 is TTL source*/
837 #define TVP3026_XCLKCTRL_SRC_NCLK2 0x03 /* not CLK2 is TTL source */
838 #define TVP3026_XCLKCTRL_SRC_ECLK2 0x04 /* CLK2 and not CLK2 is ECL source */
839 #define TVP3026_XCLKCTRL_SRC_PLL 0x05
840 #define TVP3026_XCLKCTRL_SRC_DIS 0x06 /* disable & poweroff internal clock */
841 #define TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
842 #define TVP3026_XPALETTEPAGE 0x1C
843 #define TVP3026_XGENCTRL 0x1D
844 #define TVP3026_XGENCTRL_HSYNC_POS 0x00
845 #define TVP3026_XGENCTRL_HSYNC_NEG 0x01
846 #define TVP3026_XGENCTRL_VSYNC_POS 0x00
847 #define TVP3026_XGENCTRL_VSYNC_NEG 0x02
848 #define TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
849 #define TVP3026_XGENCTRL_BIG_ENDIAN 0x08
850 #define TVP3026_XGENCTRL_BLACK_0IRE 0x00
851 #define TVP3026_XGENCTRL_BLACK_75IRE 0x10
852 #define TVP3026_XGENCTRL_NO_SYNC_ON_GREEN 0x00
853 #define TVP3026_XGENCTRL_SYNC_ON_GREEN 0x20
854 #define TVP3026_XGENCTRL_OVERSCAN_DIS 0x00
855 #define TVP3026_XGENCTRL_OVERSCAN_EN 0x40
856 #define TVP3026_XMISCCTRL 0x1E
857 #define TVP3026_XMISCCTRL_DAC_PUP 0x00
858 #define TVP3026_XMISCCTRL_DAC_PDOWN 0x01
859 #define TVP3026_XMISCCTRL_DAC_EXT 0x00 /* or 8, bit 3 is ignored */
860 #define TVP3026_XMISCCTRL_DAC_6BIT 0x04
861 #define TVP3026_XMISCCTRL_DAC_8BIT 0x0C
862 #define TVP3026_XMISCCTRL_PSEL_DIS 0x00
863 #define TVP3026_XMISCCTRL_PSEL_EN 0x10
864 #define TVP3026_XMISCCTRL_PSEL_LOW 0x00 /* PSEL high selects directcolor */
865 #define TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
866 #define TVP3026_XGENIOCTRL 0x2A
867 #define TVP3026_XGENIODATA 0x2B
868 #define TVP3026_XPLLADDR 0x2C
869 #define TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
870 #define TVP3026_XPLLDATA_N 0x00
871 #define TVP3026_XPLLDATA_M 0x01
872 #define TVP3026_XPLLDATA_P 0x02
873 #define TVP3026_XPLLDATA_STAT 0x03
874 #define TVP3026_XPIXPLLDATA 0x2D
875 #define TVP3026_XMEMPLLDATA 0x2E
876 #define TVP3026_XLOOPPLLDATA 0x2F
877 #define TVP3026_XCOLKEYOVRMIN 0x30
878 #define TVP3026_XCOLKEYOVRMAX 0x31
879 #define TVP3026_XCOLKEYREDMIN 0x32
880 #define TVP3026_XCOLKEYREDMAX 0x33
881 #define TVP3026_XCOLKEYGREENMIN 0x34
882 #define TVP3026_XCOLKEYGREENMAX 0x35
883 #define TVP3026_XCOLKEYBLUEMIN 0x36
884 #define TVP3026_XCOLKEYBLUEMAX 0x37
885 #define TVP3026_XCOLKEYCTRL 0x38
886 #define TVP3026_XCOLKEYCTRL_OVR_EN 0x01
887 #define TVP3026_XCOLKEYCTRL_RED_EN 0x02
888 #define TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
889 #define TVP3026_XCOLKEYCTRL_BLUE_EN 0x08
890 #define TVP3026_XCOLKEYCTRL_NEGATE 0x10
891 #define TVP3026_XCOLKEYCTRL_ZOOM1 0x00
892 #define TVP3026_XCOLKEYCTRL_ZOOM2 0x20
893 #define TVP3026_XCOLKEYCTRL_ZOOM4 0x40
894 #define TVP3026_XCOLKEYCTRL_ZOOM8 0x60
895 #define TVP3026_XCOLKEYCTRL_ZOOM16 0x80
896 #define TVP3026_XCOLKEYCTRL_ZOOM32 0xA0
897 #define TVP3026_XMEMPLLCTRL 0x39
898 #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 */
899 #define TVP3026_XMEMPLLCTRL_STROBEMKC4 0x08
900 #define TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK 0x00 /* MKC4 */
901 #define TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL 0x10 /* MKC4 */
902 #define TVP3026_XMEMPLLCTRL_RCLK_PIXPLL 0x00
903 #define TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL 0x20
904 #define TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN 0x40 /* dot clock divided by loop pclk N prescaler */
905 #define TVP3026_XSENSETEST 0x3A
906 #define TVP3026_XTESTMODEDATA 0x3B
907 #define TVP3026_XCRCREML 0x3C
908 #define TVP3026_XCRCREMH 0x3D
909 #define TVP3026_XCRCBITSEL 0x3E
910 #define TVP3026_XID 0x3F
912 #endif
914 #ifdef NEED_DAC1064
916 #define DAC1064_OPT_SCLK_PCI 0x00
917 #define DAC1064_OPT_SCLK_PLL 0x01
918 #define DAC1064_OPT_SCLK_EXT 0x02
919 #define DAC1064_OPT_SCLK_MASK 0x03
920 #define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */
921 #define DAC1064_OPT_GDIV3 0x00
922 #define DAC1064_OPT_MDIV1 0x08
923 #define DAC1064_OPT_MDIV2 0x00
924 #define DAC1064_OPT_RESERVED 0x10
926 #define M1064_INDEX 0x00
927 #define M1064_PALWRADD 0x00
928 #define M1064_PALDATA 0x01
929 #define M1064_PIXRDMSK 0x02
930 #define M1064_PALRDADD 0x03
931 #define M1064_X_DATAREG 0x0A
932 #define M1064_CURPOSXL 0x0C /* can be accessed as DWORD */
933 #define M1064_CURPOSXH 0x0D
934 #define M1064_CURPOSYL 0x0E
935 #define M1064_CURPOSYH 0x0F
937 #define M1064_XCURADDL 0x04
938 #define M1064_XCURADDH 0x05
939 #define M1064_XCURCTRL 0x06
940 #define M1064_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */
941 #define M1064_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
942 #define M1064_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
943 #define M1064_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
944 #define M1064_XCURCOL0RED 0x08
945 #define M1064_XCURCOL0GREEN 0x09
946 #define M1064_XCURCOL0BLUE 0x0A
947 #define M1064_XCURCOL1RED 0x0C
948 #define M1064_XCURCOL1GREEN 0x0D
949 #define M1064_XCURCOL1BLUE 0x0E
950 #define M1064_XCURCOL2RED 0x10
951 #define M1064_XCURCOL2GREEN 0x11
952 #define M1064_XCURCOL2BLUE 0x12
953 #define DAC1064_XVREFCTRL 0x18
954 #define DAC1064_XVREFCTRL_INTERNAL 0x3F
955 #define DAC1064_XVREFCTRL_EXTERNAL 0x00
956 #define DAC1064_XVREFCTRL_G100_DEFAULT 0x03
957 #define M1064_XMULCTRL 0x19
958 #define M1064_XMULCTRL_DEPTH_8BPP 0x00 /* 8 bpp paletized */
959 #define M1064_XMULCTRL_DEPTH_15BPP_1BPP 0x01 /* 15 bpp paletized + 1 bpp overlay */
960 #define M1064_XMULCTRL_DEPTH_16BPP 0x02 /* 16 bpp paletized */
961 #define M1064_XMULCTRL_DEPTH_24BPP 0x03 /* 24 bpp paletized */
962 #define M1064_XMULCTRL_DEPTH_24BPP_8BPP 0x04 /* 24 bpp direct + 8 bpp overlay paletized */
963 #define M1064_XMULCTRL_2G8V16 0x05 /* 15 bpp video direct, half xres, 8bpp paletized */
964 #define M1064_XMULCTRL_G16V16 0x06 /* 15 bpp video, 15bpp graphics, one of them paletized */
965 #define M1064_XMULCTRL_DEPTH_32BPP 0x07 /* 24 bpp paletized + 8 bpp unused */
966 #define M1064_XMULCTRL_GRAPHICS_PALETIZED 0x00
967 #define M1064_XMULCTRL_VIDEO_PALETIZED 0x08
968 #define M1064_XPIXCLKCTRL 0x1A
969 #define M1064_XPIXCLKCTRL_SRC_PCI 0x00
970 #define M1064_XPIXCLKCTRL_SRC_PLL 0x01
971 #define M1064_XPIXCLKCTRL_SRC_EXT 0x02
972 #define M1064_XPIXCLKCTRL_SRC_MASK 0x03
973 #define M1064_XPIXCLKCTRL_EN 0x00
974 #define M1064_XPIXCLKCTRL_DIS 0x04
975 #define M1064_XPIXCLKCTRL_PLL_DOWN 0x00
976 #define M1064_XPIXCLKCTRL_PLL_UP 0x08
977 #define M1064_XGENCTRL 0x1D
978 #define M1064_XGENCTRL_VS_0 0x00
979 #define M1064_XGENCTRL_VS_1 0x01
980 #define M1064_XGENCTRL_ALPHA_DIS 0x00
981 #define M1064_XGENCTRL_ALPHA_EN 0x02
982 #define M1064_XGENCTRL_BLACK_0IRE 0x00
983 #define M1064_XGENCTRL_BLACK_75IRE 0x10
984 #define M1064_XGENCTRL_SYNC_ON_GREEN 0x00
985 #define M1064_XGENCTRL_NO_SYNC_ON_GREEN 0x20
986 #define M1064_XGENCTRL_SYNC_ON_GREEN_MASK 0x20
987 #define M1064_XMISCCTRL 0x1E
988 #define M1064_XMISCCTRL_DAC_DIS 0x00
989 #define M1064_XMISCCTRL_DAC_EN 0x01
990 #define M1064_XMISCCTRL_MFC_VGA 0x00
991 #define M1064_XMISCCTRL_MFC_MAFC 0x02
992 #define M1064_XMISCCTRL_MFC_DIS 0x06
993 #define M1064_XMISCCTRL_DAC_6BIT 0x00
994 #define M1064_XMISCCTRL_DAC_8BIT 0x08
995 #define M1064_XMISCCTRL_LUT_DIS 0x00
996 #define M1064_XMISCCTRL_LUT_EN 0x10
997 #define M1064_XGENIOCTRL 0x2A
998 #define M1064_XGENIODATA 0x2B
999 #define DAC1064_XSYSPLLM 0x2C
1000 #define DAC1064_XSYSPLLN 0x2D
1001 #define DAC1064_XSYSPLLP 0x2E
1002 #define DAC1064_XSYSPLLSTAT 0x2F
1003 #define M1064_XZOOMCTRL 0x38
1004 #define M1064_XZOOMCTRL_1 0x00
1005 #define M1064_XZOOMCTRL_2 0x01
1006 #define M1064_XZOOMCTRL_4 0x03
1007 #define M1064_XSENSETEST 0x3A
1008 #define M1064_XSENSETEST_BCOMP 0x01
1009 #define M1064_XSENSETEST_GCOMP 0x02
1010 #define M1064_XSENSETEST_RCOMP 0x04
1011 #define M1064_XSENSETEST_PDOWN 0x00
1012 #define M1064_XSENSETEST_PUP 0x80
1013 #define M1064_XCRCREML 0x3C
1014 #define M1064_XCRCREMH 0x3D
1015 #define M1064_XCRCBITSEL 0x3E
1016 #define M1064_XCOLKEYMASKL 0x40
1017 #define M1064_XCOLKEYMASKH 0x41
1018 #define M1064_XCOLKEYL 0x42
1019 #define M1064_XCOLKEYH 0x43
1020 #define M1064_XPIXPLLAM 0x44
1021 #define M1064_XPIXPLLAN 0x45
1022 #define M1064_XPIXPLLAP 0x46
1023 #define M1064_XPIXPLLBM 0x48
1024 #define M1064_XPIXPLLBN 0x49
1025 #define M1064_XPIXPLLBP 0x4A
1026 #define M1064_XPIXPLLCM 0x4C
1027 #define M1064_XPIXPLLCN 0x4D
1028 #define M1064_XPIXPLLCP 0x4E
1029 #define M1064_XPIXPLLSTAT 0x4F
1031 #endif
1033 #ifdef __LITTLE_ENDIAN
1034 #define MX_OPTION_BSWAP 0x00000000
1036 #define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
1037 #define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
1038 #define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
1039 #define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
1040 #define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
1041 #else
1042 #ifdef __BIG_ENDIAN
1043 #define MX_OPTION_BSWAP 0x80000000
1045 #define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) /* TODO */
1046 #define M_OPMODE_8BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT)
1047 #define M_OPMODE_16BPP (M_OPMODE_DMA_BE_16BPP | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT)
1048 #define M_OPMODE_24BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) /* TODO, ?32 */
1049 #define M_OPMODE_32BPP (M_OPMODE_DMA_BE_32BPP | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT)
1050 #else
1051 #error "Byte ordering have to be defined. Cannot continue."
1052 #endif
1053 #endif
1055 #define mga_inb(addr) mga_readb(ACCESS_FBINFO(mmio.vbase), (addr))
1056 #define mga_inl(addr) mga_readl(ACCESS_FBINFO(mmio.vbase), (addr))
1057 #define mga_outb(addr,val) mga_writeb(ACCESS_FBINFO(mmio.vbase), (addr), (val))
1058 #define mga_outw(addr,val) mga_writew(ACCESS_FBINFO(mmio.vbase), (addr), (val))
1059 #define mga_outl(addr,val) mga_writel(ACCESS_FBINFO(mmio.vbase), (addr), (val))
1060 #define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1))
1061 #ifdef __LITTLE_ENDIAN
1062 #define mga_setr(addr,port,val) mga_outw(addr, ((val)<<8) | (port))
1063 #else
1064 #define mga_setr(addr,port,val) do { mga_outb(addr, port); mga_outb((addr)+1, val); } while (0)
1065 #endif
1067 #ifdef __LITTLE_ENDIAN
1068 #define mga_fifo(n) do {} while (mga_inb(M_FIFOSTATUS) < (n))
1069 #else
1070 #define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
1071 #endif
1073 #define WaitTillIdle() do {} while (mga_inl(M_STATUS) & 0x10000)
1075 /* code speedup */
1076 #ifdef CONFIG_FB_MATROX_MILLENIUM
1077 #define isInterleave(x) (x->interleave)
1078 #define isMillenium(x) (x->millenium)
1079 #define isMilleniumII(x) (x->milleniumII)
1080 #else
1081 #define isInterleave(x) (0)
1082 #define isMillenium(x) (0)
1083 #define isMilleniumII(x) (0)
1084 #endif
1086 #ifdef MATROXFB_DEBUG_REENTER
1087 static atomic_t guard_counter = ATOMIC_INIT(1);
1088 static atomic_t guard_printing = ATOMIC_INIT(1);
1089 static void guard_start(void) {
1090 if (atomic_dec_and_test(&guard_counter)) { /* first level */
1091 if (!(bh_mask & (1 << CONSOLE_BH))) /* and CONSOLE_BH disabled */
1092 return; /* is OK */
1093 /* otherwise it is first level with CONSOLE_BH enabled -
1094 - if we are __sti or SMP, reentering from console_bh possible */
1095 atomic_dec(&guard_printing); /* disable reentrancy warning */
1096 printk(KERN_DEBUG "matroxfb entered without CONSOLE_BH disabled\n");
1097 #ifdef printstate
1098 printstate();
1099 #endif
1100 atomic_inc(&guard_printing);
1101 return;
1103 /* real reentering... You should be already warned by code above */
1104 if (atomic_dec_and_test(&guard_printing)) {
1105 #ifdef printstate
1106 printstate();
1107 #endif
1109 atomic_inc(&guard_printing);
1112 static inline void guard_end(void) {
1113 atomic_inc(&guard_counter);
1116 #define CRITBEGIN guard_start();
1117 #define CRITEND guard_end();
1119 #else
1121 #define CRITBEGIN
1122 #define CRITEND
1124 #endif
1126 #define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
1128 static void matrox_cfbX_init(WPMINFO struct display* p) {
1129 u_int32_t maccess;
1130 u_int32_t mpitch;
1131 u_int32_t mopmode;
1133 DBG("matrox_cfbX_init")
1135 mpitch = p->var.xres_virtual;
1137 if (p->type == FB_TYPE_TEXT) {
1138 maccess = 0x00000000;
1139 mpitch = (mpitch >> 4) | 0x8000; /* set something */
1140 mopmode = M_OPMODE_8BPP;
1141 } else {
1142 switch (p->var.bits_per_pixel) {
1143 case 4: maccess = 0x00000000; /* accelerate as 8bpp video */
1144 mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
1145 mopmode = M_OPMODE_4BPP;
1146 break;
1147 case 8: maccess = 0x00000000;
1148 mopmode = M_OPMODE_8BPP;
1149 break;
1150 case 16: if (p->var.green.length == 5)
1151 maccess = 0xC0000001;
1152 else
1153 maccess = 0x40000001;
1154 mopmode = M_OPMODE_16BPP;
1155 break;
1156 case 24: maccess = 0x00000003;
1157 mopmode = M_OPMODE_24BPP;
1158 break;
1159 case 32: maccess = 0x00000002;
1160 mopmode = M_OPMODE_32BPP;
1161 break;
1162 default: maccess = 0x00000000;
1163 mopmode = 0x00000000;
1164 break; /* turn off acceleration!!! */
1167 mga_fifo(8);
1168 mga_outl(M_PITCH, mpitch);
1169 mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
1170 if (ACCESS_FBINFO(capable.plnwt))
1171 mga_outl(M_PLNWT, -1);
1172 mga_outl(M_OPMODE, mopmode);
1173 mga_outl(M_CXBNDRY, 0xFFFF0000);
1174 mga_outl(M_YTOP, 0);
1175 mga_outl(M_YBOT, 0x01FFFFFF);
1176 mga_outl(M_MACCESS, maccess);
1177 ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
1178 if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
1179 ACCESS_FBINFO(accel.m_opmode) = mopmode;
1182 static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
1183 int pixx = p->var.xres_virtual, start, end;
1184 MINFO_FROM_DISP(p);
1186 DBG("matrox_cfbX_bmove")
1188 CRITBEGIN
1190 sx *= fontwidth(p);
1191 dx *= fontwidth(p);
1192 width *= fontwidth(p);
1193 height *= fontheight(p);
1194 sy *= fontheight(p);
1195 dy *= fontheight(p);
1196 if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
1197 mga_fifo(2);
1198 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
1199 M_DWG_BFCOL | M_DWG_REPLACE);
1200 mga_outl(M_AR5, pixx);
1201 width--;
1202 start = sy*pixx+sx+curr_ydstorg(MINFO);
1203 end = start+width;
1204 } else {
1205 mga_fifo(3);
1206 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
1207 mga_outl(M_SGN, 5);
1208 mga_outl(M_AR5, -pixx);
1209 width--;
1210 end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
1211 start = end+width;
1212 dy += height-1;
1214 mga_fifo(4);
1215 mga_outl(M_AR0, end);
1216 mga_outl(M_AR3, start);
1217 mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
1218 mga_ydstlen(dy, height);
1219 WaitTillIdle();
1221 CRITEND
1224 #ifdef FBCON_HAS_CFB4
1225 static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
1226 int pixx, start, end;
1227 MINFO_FROM_DISP(p);
1228 /* both (sx or dx or width) and fontwidth() are odd, so their multiply is
1229 also odd, that means that we cannot use acceleration */
1231 DBG("matrox_cfb4_bmove")
1233 CRITBEGIN
1235 if ((sx | dx | width) & fontwidth(p) & 1) {
1236 fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
1237 return;
1239 sx *= fontwidth(p);
1240 dx *= fontwidth(p);
1241 width *= fontwidth(p);
1242 height *= fontheight(p);
1243 sy *= fontheight(p);
1244 dy *= fontheight(p);
1245 pixx = p->var.xres_virtual >> 1;
1246 sx >>= 1;
1247 dx >>= 1;
1248 width >>= 1;
1249 if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
1250 mga_fifo(2);
1251 mga_outl(M_AR5, pixx);
1252 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
1253 M_DWG_BFCOL | M_DWG_REPLACE);
1254 width--;
1255 start = sy*pixx+sx+curr_ydstorg(MINFO);
1256 end = start+width;
1257 } else {
1258 mga_fifo(3);
1259 mga_outl(M_SGN, 5);
1260 mga_outl(M_AR5, -pixx);
1261 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
1262 width--;
1263 end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
1264 start = end+width;
1265 dy += height-1;
1267 mga_fifo(5);
1268 mga_outl(M_AR0, end);
1269 mga_outl(M_AR3, start);
1270 mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
1271 mga_outl(M_YDST, dy*pixx >> 5);
1272 mga_outl(M_LEN | M_EXEC, height);
1273 WaitTillIdle();
1275 CRITEND
1277 #endif
1279 static void matroxfb_accel_clear(CPMINFO u_int32_t color, int sy, int sx, int height,
1280 int width) {
1282 DBG("matroxfb_accel_clear")
1284 CRITBEGIN
1286 mga_fifo(5);
1287 mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
1288 mga_outl(M_FCOL, color);
1289 mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
1290 mga_ydstlen(sy, height);
1291 WaitTillIdle();
1293 CRITEND
1296 static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
1298 DBG("matrox_cfbX_clear")
1300 matroxfb_accel_clear(PMXINFO(p) color, sy * fontheight(p), sx * fontwidth(p),
1301 height * fontheight(p), width * fontwidth(p));
1304 #ifdef FBCON_HAS_CFB4
1305 static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
1306 u_int32_t bgx;
1307 int whattodo;
1308 MINFO_FROM_DISP(p);
1310 DBG("matrox_cfb4_clear")
1312 CRITBEGIN
1314 whattodo = 0;
1315 bgx = attr_bgcol_ec(p, conp);
1316 bgx |= bgx << 4;
1317 bgx |= bgx << 8;
1318 bgx |= bgx << 16;
1319 sy *= fontheight(p);
1320 sx *= fontwidth(p);
1321 height *= fontheight(p);
1322 width *= fontwidth(p);
1323 if (sx & 1) {
1324 sx ++;
1325 if (!width) return;
1326 width --;
1327 whattodo = 1;
1329 if (width & 1) {
1330 whattodo |= 2;
1332 width >>= 1;
1333 sx >>= 1;
1334 if (width) {
1335 mga_fifo(5);
1336 mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2);
1337 mga_outl(M_FCOL, bgx);
1338 mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
1339 mga_outl(M_YDST, sy * p->var.xres_virtual >> 6);
1340 mga_outl(M_LEN | M_EXEC, height);
1341 WaitTillIdle();
1343 if (whattodo) {
1344 u_int32_t step = p->var.xres_virtual >> 1;
1345 vaddr_t vbase = ACCESS_FBINFO(video.vbase);
1346 if (whattodo & 1) {
1347 unsigned int uaddr = sy * step + sx - 1;
1348 u_int32_t loop;
1349 u_int8_t bgx2 = bgx & 0xF0;
1350 for (loop = height; loop > 0; loop --) {
1351 mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2);
1352 uaddr += step;
1355 if (whattodo & 2) {
1356 unsigned int uaddr = sy * step + sx + width;
1357 u_int32_t loop;
1358 u_int8_t bgx2 = bgx & 0x0F;
1359 for (loop = height; loop > 0; loop --) {
1360 mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2);
1361 uaddr += step;
1366 CRITEND
1368 #endif
1370 #ifdef FBCON_HAS_CFB8
1371 static void matrox_cfb8_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
1372 u_int32_t bgx;
1374 DBG("matrox_cfb8_clear")
1376 bgx = attr_bgcol_ec(p, conp);
1377 bgx |= bgx << 8;
1378 bgx |= bgx << 16;
1379 matrox_cfbX_clear(bgx, p, sy, sx, height, width);
1381 #endif
1383 #ifdef FBCON_HAS_CFB16
1384 static void matrox_cfb16_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
1385 u_int32_t bgx;
1387 DBG("matrox_cfb16_clear")
1389 bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1390 matrox_cfbX_clear((bgx << 16) | bgx, p, sy, sx, height, width);
1392 #endif
1394 #if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
1395 static void matrox_cfb32_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
1396 u_int32_t bgx;
1398 DBG("matrox_cfb32_clear")
1400 bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1401 matrox_cfbX_clear(bgx, p, sy, sx, height, width);
1403 #endif
1405 static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
1406 unsigned int charcell;
1407 unsigned int ar3;
1408 MINFO_FROM_DISP(p);
1410 charcell = fontwidth(p) * fontheight(p);
1411 yy *= fontheight(p);
1412 xx *= fontwidth(p);
1414 CRITBEGIN
1416 mga_fifo(8);
1417 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
1419 mga_outl(M_FCOL, fgx);
1420 mga_outl(M_BCOL, bgx);
1421 mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx);
1422 ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell;
1423 mga_outl(M_AR3, ar3);
1424 mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
1425 mga_ydstlen(yy, fontheight(p));
1426 WaitTillIdle();
1428 CRITEND
1431 static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
1432 u_int32_t ar0;
1433 u_int32_t step;
1434 MINFO_FROM_DISP(p);
1436 DBG_HEAVY("matrox_cfbX_putc");
1438 yy *= fontheight(p);
1439 xx *= fontwidth(p);
1441 CRITBEGIN
1443 #ifdef __BIG_ENDIAN
1444 WaitTillIdle();
1445 mga_outl(M_OPMODE, M_OPMODE_8BPP);
1446 #else
1447 mga_fifo(7);
1448 #endif
1449 ar0 = fontwidth(p) - 1;
1450 mga_outl(M_FXBNDRY, ((xx+ar0)<<16) | xx);
1451 if (fontwidth(p) <= 8)
1452 step = 1;
1453 else if (fontwidth(p) <= 16)
1454 step = 2;
1455 else
1456 step = 4;
1457 if (fontwidth(p) == step << 3) {
1458 size_t charcell = fontheight(p)*step;
1459 /* TODO: Align charcell to 4B for BE */
1460 mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
1461 mga_outl(M_FCOL, fgx);
1462 mga_outl(M_BCOL, bgx);
1463 mga_outl(M_AR3, 0);
1464 mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1);
1465 mga_ydstlen(yy, fontheight(p));
1466 mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell);
1467 } else {
1468 u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step;
1469 int i;
1471 mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
1472 mga_outl(M_FCOL, fgx);
1473 mga_outl(M_BCOL, bgx);
1474 mga_outl(M_AR5, 0);
1475 mga_outl(M_AR3, 0);
1476 mga_outl(M_AR0, ar0);
1477 mga_ydstlen(yy, fontheight(p));
1479 switch (step) {
1480 case 1:
1481 for (i = fontheight(p); i > 0; i--) {
1482 #ifdef __LITTLE_ENDIAN
1483 mga_outl(0, *chardata++);
1484 #else
1485 mga_outl(0, (*chardata++) << 24);
1486 #endif
1488 break;
1489 case 2:
1490 for (i = fontheight(p); i > 0; i--) {
1491 #ifdef __LITTLE_ENDIAN
1492 mga_outl(0, *(u_int16_t*)chardata);
1493 #else
1494 mga_outl(0, (*(u_int16_t*)chardata) << 16);
1495 #endif
1496 chardata += 2;
1498 break;
1499 case 4:
1500 mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, chardata, fontheight(p) * 4);
1501 break;
1504 WaitTillIdle();
1505 #ifdef __BIG_ENDIAN
1506 mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
1507 #endif
1508 CRITEND
1511 #ifdef FBCON_HAS_CFB8
1512 static void matrox_cfb8_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
1513 u_int32_t fgx, bgx;
1514 MINFO_FROM_DISP(p);
1516 DBG_HEAVY("matroxfb_cfb8_putc");
1518 fgx = attr_fgcol(p, c);
1519 bgx = attr_bgcol(p, c);
1520 fgx |= (fgx << 8);
1521 fgx |= (fgx << 16);
1522 bgx |= (bgx << 8);
1523 bgx |= (bgx << 16);
1524 ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx);
1526 #endif
1528 #ifdef FBCON_HAS_CFB16
1529 static void matrox_cfb16_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
1530 u_int32_t fgx, bgx;
1531 MINFO_FROM_DISP(p);
1533 DBG_HEAVY("matroxfb_cfb16_putc");
1535 fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)];
1536 bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)];
1537 fgx |= (fgx << 16);
1538 bgx |= (bgx << 16);
1539 ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx);
1541 #endif
1543 #if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
1544 static void matrox_cfb32_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
1545 u_int32_t fgx, bgx;
1546 MINFO_FROM_DISP(p);
1548 DBG_HEAVY("matroxfb_cfb32_putc");
1550 fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)];
1551 bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)];
1552 ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx);
1554 #endif
1556 static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
1557 unsigned int charcell;
1558 MINFO_FROM_DISP(p);
1560 yy *= fontheight(p);
1561 xx *= fontwidth(p);
1562 charcell = fontwidth(p) * fontheight(p);
1564 CRITBEGIN
1566 mga_fifo(3);
1567 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
1568 mga_outl(M_FCOL, fgx);
1569 mga_outl(M_BCOL, bgx);
1570 while (count--) {
1571 u_int32_t ar3 = ACCESS_FBINFO(fastfont.mgabase) + (scr_readw(s++) & p->charmask)*charcell;
1573 mga_fifo(4);
1574 mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx);
1575 mga_outl(M_AR3, ar3);
1576 mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
1577 mga_ydstlen(yy, fontheight(p));
1578 xx += fontwidth(p);
1580 WaitTillIdle();
1582 CRITEND
1585 static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
1586 u_int32_t step;
1587 u_int32_t ydstlen;
1588 u_int32_t xlen;
1589 u_int32_t ar0;
1590 u_int32_t charcell;
1591 u_int32_t fxbndry;
1592 vaddr_t mmio;
1593 int easy;
1594 MINFO_FROM_DISP(p);
1596 DBG_HEAVY("matroxfb_cfbX_putcs");
1598 yy *= fontheight(p);
1599 xx *= fontwidth(p);
1600 if (fontwidth(p) <= 8)
1601 step = 1;
1602 else if (fontwidth(p) <= 16)
1603 step = 2;
1604 else
1605 step = 4;
1606 charcell = fontheight(p)*step;
1607 xlen = (charcell + 3) & ~3;
1608 ydstlen = (yy << 16) | fontheight(p);
1609 if (fontwidth(p) == step << 3) {
1610 ar0 = fontheight(p)*fontwidth(p) - 1;
1611 easy = 1;
1612 } else {
1613 ar0 = fontwidth(p) - 1;
1614 easy = 0;
1617 CRITBEGIN
1619 #ifdef __BIG_ENDIAN
1620 WaitTillIdle();
1621 mga_outl(M_OPMODE, M_OPMODE_8BPP);
1622 #else
1623 mga_fifo(3);
1624 #endif
1625 if (easy)
1626 mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
1627 else
1628 mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
1629 mga_outl(M_FCOL, fgx);
1630 mga_outl(M_BCOL, bgx);
1631 fxbndry = ((xx + fontwidth(p) - 1) << 16) | xx;
1632 mmio = ACCESS_FBINFO(mmio.vbase);
1633 while (count--) {
1634 u_int8_t* chardata = p->fontdata + (scr_readw(s++) & p->charmask)*charcell;
1636 mga_fifo(6);
1637 mga_writel(mmio, M_FXBNDRY, fxbndry);
1638 mga_writel(mmio, M_AR0, ar0);
1639 mga_writel(mmio, M_AR3, 0);
1640 if (easy) {
1641 mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
1642 mga_memcpy_toio(mmio, 0, chardata, xlen);
1643 } else {
1644 mga_writel(mmio, M_AR5, 0);
1645 mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
1646 switch (step) {
1647 case 1: {
1648 u_int8_t* charend = chardata + charcell;
1649 for (; chardata != charend; chardata++) {
1650 #ifdef __LITTLE_ENDIAN
1651 mga_writel(mmio, 0, *chardata);
1652 #else
1653 mga_writel(mmio, 0, (*chardata) << 24);
1654 #endif
1657 break;
1658 case 2: {
1659 u_int8_t* charend = chardata + charcell;
1660 for (; chardata != charend; chardata += 2) {
1661 #ifdef __LITTLE_ENDIAN
1662 mga_writel(mmio, 0, *(u_int16_t*)chardata);
1663 #else
1664 mga_writel(mmio, 0, (*(u_int16_t*)chardata) << 16);
1665 #endif
1668 break;
1669 default:
1670 mga_memcpy_toio(mmio, 0, chardata, charcell);
1671 break;
1674 fxbndry += fontwidth(p) + (fontwidth(p) << 16);
1676 WaitTillIdle();
1677 #ifdef __BIG_ENDIAN
1678 mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
1679 #endif
1680 CRITEND
1683 #ifdef FBCON_HAS_CFB8
1684 static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
1685 u_int32_t fgx, bgx;
1686 MINFO_FROM_DISP(p);
1688 DBG_HEAVY("matroxfb_cfb8_putcs");
1690 fgx = attr_fgcol(p, scr_readw(s));
1691 bgx = attr_bgcol(p, scr_readw(s));
1692 fgx |= (fgx << 8);
1693 fgx |= (fgx << 16);
1694 bgx |= (bgx << 8);
1695 bgx |= (bgx << 16);
1696 ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
1698 #endif
1700 #ifdef FBCON_HAS_CFB16
1701 static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
1702 u_int32_t fgx, bgx;
1703 MINFO_FROM_DISP(p);
1705 DBG_HEAVY("matroxfb_cfb16_putcs");
1707 fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
1708 bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
1709 fgx |= (fgx << 16);
1710 bgx |= (bgx << 16);
1711 ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
1713 #endif
1715 #if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
1716 static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
1717 u_int32_t fgx, bgx;
1718 MINFO_FROM_DISP(p);
1720 DBG_HEAVY("matroxfb_cfb32_putcs");
1722 fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
1723 bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
1724 ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
1726 #endif
1728 #ifdef FBCON_HAS_CFB4
1729 static void matrox_cfb4_revc(struct display* p, int xx, int yy) {
1730 MINFO_FROM_DISP(p);
1732 DBG_LOOP("matroxfb_cfb4_revc");
1734 if (fontwidth(p) & 1) {
1735 fbcon_cfb4_revc(p, xx, yy);
1736 return;
1738 yy *= fontheight(p);
1739 xx *= fontwidth(p);
1740 xx |= (xx + fontwidth(p)) << 16;
1741 xx >>= 1;
1743 CRITBEGIN
1745 mga_fifo(5);
1746 mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
1747 mga_outl(M_FCOL, 0xFFFFFFFF);
1748 mga_outl(M_FXBNDRY, xx);
1749 mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
1750 mga_outl(M_LEN | M_EXEC, fontheight(p));
1751 WaitTillIdle();
1753 CRITEND
1755 #endif
1757 #ifdef FBCON_HAS_CFB8
1758 static void matrox_cfb8_revc(struct display* p, int xx, int yy) {
1759 MINFO_FROM_DISP(p);
1761 DBG_LOOP("matrox_cfb8_revc")
1763 yy *= fontheight(p);
1764 xx *= fontwidth(p);
1766 CRITBEGIN
1768 mga_fifo(4);
1769 mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
1770 mga_outl(M_FCOL, 0x0F0F0F0F);
1771 mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
1772 mga_ydstlen(yy, fontheight(p));
1773 WaitTillIdle();
1775 CRITEND
1777 #endif
1779 static void matrox_cfbX_revc(struct display* p, int xx, int yy) {
1780 MINFO_FROM_DISP(p);
1782 DBG_LOOP("matrox_cfbX_revc")
1784 yy *= fontheight(p);
1785 xx *= fontwidth(p);
1787 CRITBEGIN
1789 mga_fifo(4);
1790 mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
1791 mga_outl(M_FCOL, 0xFFFFFFFF);
1792 mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
1793 mga_ydstlen(yy, fontheight(p));
1794 WaitTillIdle();
1796 CRITEND
1799 static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
1800 unsigned int bottom_height, right_width;
1801 unsigned int bottom_start, right_start;
1802 unsigned int cell_h, cell_w;
1804 DBG("matrox_cfbX_clear_margins")
1806 cell_w = fontwidth(p);
1807 if (!cell_w) return; /* PARANOID */
1808 right_width = p->var.xres % cell_w;
1809 right_start = p->var.xres - right_width;
1810 if (!bottom_only && right_width) {
1811 /* clear whole right margin, not only visible portion */
1812 matroxfb_accel_clear( PMXINFO(p)
1813 /* color */ 0x00000000,
1814 /* y */ 0,
1815 /* x */ p->var.xoffset + right_start,
1816 /* height */ p->var.yres_virtual,
1817 /* width */ right_width);
1819 cell_h = fontheight(p);
1820 if (!cell_h) return; /* PARANOID */
1821 bottom_height = p->var.yres % cell_h;
1822 if (bottom_height) {
1823 bottom_start = p->var.yres - bottom_height;
1824 matroxfb_accel_clear( PMXINFO(p)
1825 /* color */ 0x00000000,
1826 /* y */ p->var.yoffset + bottom_start,
1827 /* x */ p->var.xoffset,
1828 /* height */ bottom_height,
1829 /* width */ right_start);
1833 static void outDAC(CPMINFO int reg, int val) {
1834 DBG_REG("outDAC");
1835 mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
1836 mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val);
1839 static int inDAC(CPMINFO int reg) {
1840 DBG_REG("inDAC");
1841 mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
1842 return mga_inb(M_RAMDAC_BASE+M_X_DATAREG);
1845 #define outTi3026 outDAC
1846 #define inTi3026 inDAC
1847 #define outDAC1064 outDAC
1848 #define inDAC1064 inDAC
1850 static void matroxfb_createcursorshape(WPMINFO struct display* p, int vmode) {
1851 unsigned int h;
1852 unsigned int cu, cd;
1854 h = fontheight(p);
1856 if (vmode & FB_VMODE_DOUBLE)
1857 h *= 2;
1858 cd = h;
1859 if (cd >= 10)
1860 cd--;
1861 switch (ACCESS_FBINFO(cursor.type) = (p->conp->vc_cursor_type & CUR_HWMASK)) {
1862 case CUR_NONE:
1863 cu = cd;
1864 break;
1865 case CUR_UNDERLINE:
1866 cu = cd - 2;
1867 break;
1868 case CUR_LOWER_THIRD:
1869 cu = (h * 2) / 3;
1870 break;
1871 case CUR_LOWER_HALF:
1872 cu = h / 2;
1873 break;
1874 case CUR_TWO_THIRDS:
1875 cu = h / 3;
1876 break;
1877 case CUR_BLOCK:
1878 default:
1879 cu = 0;
1880 cd = h;
1881 break;
1883 ACCESS_FBINFO(cursor.w) = fontwidth(p);
1884 ACCESS_FBINFO(cursor.u) = cu;
1885 ACCESS_FBINFO(cursor.d) = cd;
1888 #ifdef CONFIG_FB_MATROX_MILLENIUM
1889 #define POS3026_XCURCTRL 20
1891 static void matroxfb_ti3026_flashcursor(unsigned long ptr) {
1892 #define minfo ((struct matrox_fb_info*)ptr)
1893 spin_lock(&ACCESS_FBINFO(lock.DAC));
1894 outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA);
1895 ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
1896 add_timer(&ACCESS_FBINFO(cursor.timer));
1897 spin_unlock(&ACCESS_FBINFO(lock.DAC));
1898 #undef minfo
1901 static void matroxfb_ti3026_createcursor(WPMINFO struct display* p) {
1902 unsigned long flags;
1903 u_int32_t xline;
1904 unsigned int i;
1905 unsigned int to;
1907 if (ACCESS_FBINFO(currcon_display) != p)
1908 return;
1910 DBG("matroxfb_ti3026_createcursor");
1912 matroxfb_createcursorshape(PMINFO p, p->var.vmode);
1914 xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
1915 spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
1916 mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, 0);
1917 to = ACCESS_FBINFO(cursor.u);
1918 for (i = 0; i < to; i++) {
1919 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1920 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1921 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1922 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1923 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1924 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1925 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1926 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1928 to = ACCESS_FBINFO(cursor.d);
1929 for (; i < to; i++) {
1930 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 24);
1931 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 16);
1932 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 8);
1933 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline);
1934 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1935 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1936 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1937 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1939 for (; i < 64; i++) {
1940 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1941 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1942 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1943 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1944 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1945 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1946 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1947 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
1949 for (i = 0; i < 512; i++)
1950 mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0xFF);
1951 spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags);
1954 static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) {
1955 unsigned long flags;
1956 MINFO_FROM_DISP(p);
1958 DBG("matroxfb_ti3026_cursor")
1960 if (ACCESS_FBINFO(currcon_display) != p)
1961 return;
1963 if (mode == CM_ERASE) {
1964 if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
1965 spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
1966 ACCESS_FBINFO(cursor.state) = CM_ERASE;
1967 del_timer(&ACCESS_FBINFO(cursor.timer));
1968 outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]));
1969 spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags);
1971 return;
1973 if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type))
1974 matroxfb_ti3026_createcursor(PMINFO p);
1975 x *= fontwidth(p);
1976 y *= fontheight(p);
1977 y -= p->var.yoffset;
1978 if (p->var.vmode & FB_VMODE_DOUBLE)
1979 y *= 2;
1980 spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
1981 if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) {
1982 ACCESS_FBINFO(cursor.redraw) = 0;
1983 ACCESS_FBINFO(cursor.x) = x;
1984 ACCESS_FBINFO(cursor.y) = y;
1985 x += 64;
1986 y += 64;
1987 outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]));
1988 mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXL, x);
1989 mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXH, x >> 8);
1990 mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYL, y);
1991 mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYH, y >> 8);
1993 ACCESS_FBINFO(cursor.state) = CM_DRAW;
1994 if (ACCESS_FBINFO(devflags.blink))
1995 mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2);
1996 outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) | TVP3026_XCURCTRL_XGA);
1997 spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags);
1999 #undef POS3026_XCURCTRL
2001 static int matroxfb_ti3026_setfont(struct display* p, int width, int height) {
2003 DBG("matrox_ti3026_setfont");
2005 if (p && p->conp)
2006 matroxfb_ti3026_createcursor(PMXINFO(p) p);
2007 return 0;
2009 #endif
2011 #ifdef NEED_DAC1064
2013 static void matroxfb_DAC1064_flashcursor(unsigned long ptr) {
2014 #define minfo ((struct matrox_fb_info*)ptr)
2015 spin_lock(&ACCESS_FBINFO(lock.DAC));
2016 outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA);
2017 ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
2018 add_timer(&ACCESS_FBINFO(cursor.timer));
2019 spin_unlock(&ACCESS_FBINFO(lock.DAC));
2020 #undef minfo
2023 static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) {
2024 vaddr_t cursorbase;
2025 u_int32_t xline;
2026 unsigned int i;
2027 unsigned int h, to;
2029 if (ACCESS_FBINFO(currcon_display) != p)
2030 return;
2032 matroxfb_createcursorshape(PMINFO p, p->var.vmode);
2034 xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
2035 cursorbase = ACCESS_FBINFO(video.vbase);
2036 h = ACCESS_FBINFO(features.DAC1064.cursorimage);
2038 CRITBEGIN
2040 #ifdef __BIG_ENDIAN
2041 WaitTillIdle();
2042 mga_outl(M_OPMODE, M_OPMODE_32BPP);
2043 #endif
2044 to = ACCESS_FBINFO(cursor.u);
2045 for (i = 0; i < to; i++) {
2046 mga_writel(cursorbase, h, 0);
2047 mga_writel(cursorbase, h+4, 0);
2048 mga_writel(cursorbase, h+8, ~0);
2049 mga_writel(cursorbase, h+12, ~0);
2050 h += 16;
2052 to = ACCESS_FBINFO(cursor.d);
2053 for (; i < to; i++) {
2054 mga_writel(cursorbase, h, 0);
2055 mga_writel(cursorbase, h+4, xline);
2056 mga_writel(cursorbase, h+8, ~0);
2057 mga_writel(cursorbase, h+12, ~0);
2058 h += 16;
2060 for (; i < 64; i++) {
2061 mga_writel(cursorbase, h, 0);
2062 mga_writel(cursorbase, h+4, 0);
2063 mga_writel(cursorbase, h+8, ~0);
2064 mga_writel(cursorbase, h+12, ~0);
2065 h += 16;
2067 #ifdef __BIG_ENDIAN
2068 mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
2069 #endif
2071 CRITEND
2074 static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) {
2075 unsigned long flags;
2076 MINFO_FROM_DISP(p);
2078 if (ACCESS_FBINFO(currcon_display) != p)
2079 return;
2081 if (mode == CM_ERASE) {
2082 if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
2083 spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
2084 ACCESS_FBINFO(cursor.state) = CM_ERASE;
2085 del_timer(&ACCESS_FBINFO(cursor.timer));
2086 outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS);
2087 spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags);
2089 return;
2091 if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type))
2092 matroxfb_DAC1064_createcursor(PMINFO p);
2093 x *= fontwidth(p);
2094 y *= fontheight(p);
2095 y -= p->var.yoffset;
2096 if (p->var.vmode & FB_VMODE_DOUBLE)
2097 y *= 2;
2098 spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
2099 if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) {
2100 ACCESS_FBINFO(cursor.redraw) = 0;
2101 ACCESS_FBINFO(cursor.x) = x;
2102 ACCESS_FBINFO(cursor.y) = y;
2103 x += 64;
2104 y += 64;
2105 outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS);
2106 mga_outb(M_RAMDAC_BASE+M1064_CURPOSXL, x);
2107 mga_outb(M_RAMDAC_BASE+M1064_CURPOSXH, x >> 8);
2108 mga_outb(M_RAMDAC_BASE+M1064_CURPOSYL, y);
2109 mga_outb(M_RAMDAC_BASE+M1064_CURPOSYH, y >> 8);
2111 ACCESS_FBINFO(cursor.state) = CM_DRAW;
2112 if (ACCESS_FBINFO(devflags.blink))
2113 mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2);
2114 outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_XGA);
2115 spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags);
2118 static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) {
2119 if (p && p->conp)
2120 matroxfb_DAC1064_createcursor(PMXINFO(p) p);
2121 return 0;
2123 #endif
2125 #ifndef FNTCHARCNT
2126 #define FNTCHARCNT(fd) (((int *)(fd))[-3])
2127 #endif
2129 static int matroxfb_fastfont_tryset(WPMINFO struct display* p) {
2130 unsigned int fsize;
2131 unsigned int width;
2133 if (!p || !p->fontdata)
2134 return 0;
2135 width = fontwidth(p);
2136 if (width > 32)
2137 return 0;
2138 fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p);
2139 if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size))
2140 return 0;
2142 CRITBEGIN
2144 mga_outl(M_OPMODE, M_OPMODE_8BPP);
2145 if (width <= 8) {
2146 if (width == 8)
2147 mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize);
2148 else {
2149 vaddr_t dst;
2150 unsigned int i;
2151 u_int8_t* font;
2152 u_int32_t mask, valid, reg;
2154 dst = ACCESS_FBINFO(fastfont.vbase);
2155 font = (u_int8_t*)p->fontdata;
2156 mask = ~0 << (8 - width);
2157 valid = 0;
2158 reg = 0;
2159 i = 0;
2160 while (fsize--) {
2161 reg |= (*font++ & mask) << (8 - valid);
2162 valid += width;
2163 if (valid >= 8) {
2164 mga_writeb(dst, i++, reg >> 8);
2165 reg = reg << 8;
2166 valid -= 8;
2169 if (valid)
2170 mga_writeb(dst, i, reg >> 8);
2172 } else if (width <= 16) {
2173 if (width == 16)
2174 mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*2);
2175 else {
2176 vaddr_t dst;
2177 u_int16_t* font;
2178 u_int32_t mask, valid, reg;
2179 unsigned int i;
2181 dst = ACCESS_FBINFO(fastfont.vbase);
2182 font = (u_int16_t*)p->fontdata;
2183 mask = ~0 << (16 - width);
2184 valid = 0;
2185 reg = 0;
2186 i = 0;
2187 while (fsize--) {
2188 reg |= (ntohs(*font++) & mask) << (16 - valid);
2189 valid += width;
2190 if (valid >= 16) {
2191 mga_writew(dst, i, htons(reg >> 16));
2192 i += 2;
2193 reg = reg << 16;
2194 valid -= 16;
2197 if (valid)
2198 mga_writew(dst, i, htons(reg >> 16));
2200 } else {
2201 if (width == 32)
2202 mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*4);
2203 else {
2204 vaddr_t dst;
2205 u_int32_t* font;
2206 u_int32_t mask, valid, reg;
2207 unsigned int i;
2209 dst = ACCESS_FBINFO(fastfont.vbase);
2210 font = (u_int32_t*)p->fontdata;
2211 mask = ~0 << (32 - width);
2212 valid = 0;
2213 reg = 0;
2214 i = 0;
2215 while (fsize--) {
2216 reg |= (ntohl(*font) & mask) >> valid;
2217 valid += width;
2218 if (valid >= 32) {
2219 mga_writel(dst, i, htonl(reg));
2220 i += 4;
2221 valid -= 32;
2222 if (valid)
2223 reg = (ntohl(*font) & mask) << (width - valid);
2224 else
2225 reg = 0;
2227 font++;
2229 if (valid)
2230 mga_writel(dst, i, htonl(reg));
2233 mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
2235 CRITEND
2237 return 1;
2240 static void matrox_text_setup(struct display* p) {
2241 MINFO_FROM_DISP(p);
2243 p->next_line = p->line_length ? p->line_length : ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
2244 p->next_plane = 0;
2247 static void matrox_text_bmove(struct display* p, int sy, int sx, int dy, int dx,
2248 int height, int width) {
2249 unsigned int srcoff;
2250 unsigned int dstoff;
2251 unsigned int step;
2252 MINFO_FROM_DISP(p);
2254 CRITBEGIN
2256 step = ACCESS_FBINFO(devflags.textstep);
2257 srcoff = (sy * p->next_line) + (sx * step);
2258 dstoff = (dy * p->next_line) + (dx * step);
2259 if (dstoff < srcoff) {
2260 while (height > 0) {
2261 int i;
2262 for (i = width; i > 0; dstoff += step, srcoff += step, i--)
2263 mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff));
2264 height--;
2265 dstoff += p->next_line - width * step;
2266 srcoff += p->next_line - width * step;
2268 } else {
2269 unsigned int off;
2271 off = (height - 1) * p->next_line + (width - 1) * step;
2272 srcoff += off;
2273 dstoff += off;
2274 while (height > 0) {
2275 int i;
2276 for (i = width; i > 0; dstoff -= step, srcoff -= step, i--)
2277 mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff));
2278 dstoff -= p->next_line - width * step;
2279 srcoff -= p->next_line - width * step;
2280 height--;
2283 CRITEND
2286 static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx,
2287 int height, int width) {
2288 unsigned int offs;
2289 unsigned int val;
2290 unsigned int step;
2291 MINFO_FROM_DISP(p);
2293 step = ACCESS_FBINFO(devflags.textstep);
2294 offs = sy * p->next_line + sx * step;
2295 val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8));
2297 CRITBEGIN
2299 while (height > 0) {
2300 int i;
2301 for (i = width; i > 0; offs += step, i--)
2302 mga_writew(ACCESS_FBINFO(video.vbase), offs, val);
2303 offs += p->next_line - width * step;
2304 height--;
2306 CRITEND
2309 static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
2310 unsigned int offs;
2311 unsigned int chr;
2312 unsigned int step;
2313 MINFO_FROM_DISP(p);
2315 step = ACCESS_FBINFO(devflags.textstep);
2316 offs = yy * p->next_line + xx * step;
2317 chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8);
2318 if (chr & 0x10000) chr |= 0x08;
2320 CRITBEGIN
2322 mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr));
2324 CRITEND
2327 static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s,
2328 int count, int yy, int xx) {
2329 unsigned int offs;
2330 unsigned int attr;
2331 unsigned int step;
2332 MINFO_FROM_DISP(p);
2334 step = ACCESS_FBINFO(devflags.textstep);
2335 offs = yy * p->next_line + xx * step;
2336 attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4);
2338 CRITBEGIN
2340 while (count-- > 0) {
2341 unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8;
2342 if (chr & 0x10000) chr ^= 0x10008;
2343 mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr));
2344 offs += step;
2347 CRITEND
2350 static void matrox_text_revc(struct display* p, int xx, int yy) {
2351 unsigned int offs;
2352 unsigned int step;
2353 MINFO_FROM_DISP(p);
2355 step = ACCESS_FBINFO(devflags.textstep);
2356 offs = yy * p->next_line + xx * step + 1;
2358 CRITBEGIN
2360 mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77);
2362 CRITEND
2365 static int matrox_text_loadfont(WPMINFO struct display* p) {
2366 unsigned int fsize;
2367 unsigned int width;
2368 vaddr_t dst;
2369 unsigned int i;
2370 u_int8_t* font;
2372 if (!p || !p->fontdata)
2373 return 0;
2374 width = fontwidth(p);
2375 fsize = p->userfont?FNTCHARCNT(p->fontdata):256;
2377 dst = ACCESS_FBINFO(video.vbase);
2378 i = 2;
2379 font = (u_int8_t*)p->fontdata;
2381 CRITBEGIN
2383 mga_setr(M_SEQ_INDEX, 0x02, 0x04);
2384 while (fsize--) {
2385 int l;
2387 for (l = 0; l < fontheight(p); l++) {
2388 mga_writeb(dst, i, *font++);
2389 if (fontwidth(p) > 8) font++;
2390 i += ACCESS_FBINFO(devflags.vgastep);
2392 i += (32 - fontheight(p)) * ACCESS_FBINFO(devflags.vgastep);
2394 mga_setr(M_SEQ_INDEX, 0x02, 0x03);
2396 CRITEND
2398 return 1;
2401 static void matrox_text_createcursor(WPMINFO struct display* p) {
2403 if (ACCESS_FBINFO(currcon_display) != p)
2404 return;
2406 matroxfb_createcursorshape(PMINFO p, 0);
2408 CRITBEGIN
2410 mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
2411 mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1);
2413 CRITEND
2416 static void matrox_text_cursor(struct display* p, int mode, int x, int y) {
2417 unsigned int pos;
2418 MINFO_FROM_DISP(p);
2420 if (ACCESS_FBINFO(currcon_display) != p)
2421 return;
2423 if (mode == CM_ERASE) {
2424 if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
2426 CRITBEGIN
2428 mga_setr(M_CRTC_INDEX, 0x0A, 0x20);
2430 CRITEND
2432 ACCESS_FBINFO(cursor.state) = CM_ERASE;
2434 return;
2436 if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type))
2437 matrox_text_createcursor(PMINFO p);
2439 /* DO NOT CHECK cursor.x != x because of vgaHWinit moves cursor to 0,0 */
2440 ACCESS_FBINFO(cursor.x) = x;
2441 ACCESS_FBINFO(cursor.y) = y;
2442 pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x;
2444 CRITBEGIN
2446 mga_setr(M_CRTC_INDEX, 0x0F, pos);
2447 mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8);
2449 mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
2451 CRITEND
2453 ACCESS_FBINFO(cursor.state) = CM_DRAW;
2456 static void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p) {
2457 unsigned hf;
2458 unsigned vf;
2459 unsigned vxres;
2460 unsigned ych;
2462 hf = fontwidth(p);
2463 if (!hf) hf = 8;
2464 /* do not touch xres */
2465 vxres = (var->xres_virtual + hf - 1) / hf;
2466 if (vxres >= 256)
2467 vxres = 255;
2468 if (vxres < 16)
2469 vxres = 16;
2470 vxres = (vxres + 1) & ~1; /* must be even */
2471 vf = fontheight(p);
2472 if (!vf) vf = 16;
2473 if (var->yres < var->yres_virtual) {
2474 ych = ACCESS_FBINFO(devflags.textvram) / vxres;
2475 var->yres_virtual = ych * vf;
2476 } else
2477 ych = var->yres_virtual / vf;
2478 if (vxres * ych > ACCESS_FBINFO(devflags.textvram)) {
2479 ych = ACCESS_FBINFO(devflags.textvram) / vxres;
2480 var->yres_virtual = ych * vf;
2482 var->xres_virtual = vxres * hf;
2485 static int matrox_text_setfont(struct display* p, int width, int height) {
2486 DBG("matrox_text_setfont");
2488 if (p) {
2489 MINFO_FROM_DISP(p);
2491 matrox_text_round(PMINFO &p->var, p);
2492 p->next_line = p->line_length = ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
2494 if (p->conp)
2495 matrox_text_createcursor(PMINFO p);
2497 return 0;
2500 #define matrox_cfb16_revc matrox_cfbX_revc
2501 #define matrox_cfb24_revc matrox_cfbX_revc
2502 #define matrox_cfb32_revc matrox_cfbX_revc
2504 #define matrox_cfb24_clear matrox_cfb32_clear
2505 #define matrox_cfb24_putc matrox_cfb32_putc
2506 #define matrox_cfb24_putcs matrox_cfb32_putcs
2508 #ifdef FBCON_HAS_VGATEXT
2509 static struct display_switch matroxfb_text = {
2510 matrox_text_setup, matrox_text_bmove, matrox_text_clear,
2511 matrox_text_putc, matrox_text_putcs, matrox_text_revc,
2512 matrox_text_cursor, matrox_text_setfont, NULL,
2513 FONTWIDTH(8)|FONTWIDTH(9)
2515 #endif
2517 #ifdef FBCON_HAS_CFB4
2518 static struct display_switch matroxfb_cfb4 = {
2519 fbcon_cfb4_setup, matrox_cfb4_bmove, matrox_cfb4_clear,
2520 fbcon_cfb4_putc, fbcon_cfb4_putcs, matrox_cfb4_revc,
2521 NULL, NULL, NULL,
2522 /* cursor... */ /* set_font... */
2523 FONTWIDTH(8) /* fix, fix, fix it */
2525 #endif
2527 #ifdef FBCON_HAS_CFB8
2528 static struct display_switch matroxfb_cfb8 = {
2529 fbcon_cfb8_setup, matrox_cfbX_bmove, matrox_cfb8_clear,
2530 matrox_cfb8_putc, matrox_cfb8_putcs, matrox_cfb8_revc,
2531 NULL, NULL, matrox_cfbX_clear_margins,
2532 ~1 /* FONTWIDTHS */
2534 #endif
2536 #ifdef FBCON_HAS_CFB16
2537 static struct display_switch matroxfb_cfb16 = {
2538 fbcon_cfb16_setup, matrox_cfbX_bmove, matrox_cfb16_clear,
2539 matrox_cfb16_putc, matrox_cfb16_putcs, matrox_cfb16_revc,
2540 NULL, NULL, matrox_cfbX_clear_margins,
2541 ~1 /* FONTWIDTHS */
2543 #endif
2545 #ifdef FBCON_HAS_CFB24
2546 static struct display_switch matroxfb_cfb24 = {
2547 fbcon_cfb24_setup, matrox_cfbX_bmove, matrox_cfb24_clear,
2548 matrox_cfb24_putc, matrox_cfb24_putcs, matrox_cfb24_revc,
2549 NULL, NULL, matrox_cfbX_clear_margins,
2550 ~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */
2552 #endif
2554 #ifdef FBCON_HAS_CFB32
2555 static struct display_switch matroxfb_cfb32 = {
2556 fbcon_cfb32_setup, matrox_cfbX_bmove, matrox_cfb32_clear,
2557 matrox_cfb32_putc, matrox_cfb32_putcs, matrox_cfb32_revc,
2558 NULL, NULL, matrox_cfbX_clear_margins,
2559 ~1 /* FONTWIDTHS */
2561 #endif
2563 static struct pci_dev* pci_find(struct pci_dev* p) {
2565 DBG("pci_find")
2567 if (p) return p->next;
2568 return pci_devices;
2571 static void initMatrox(WPMINFO struct display* p) {
2572 struct display_switch *swtmp;
2574 DBG("initMatrox")
2576 if (ACCESS_FBINFO(currcon_display) != p)
2577 return;
2578 if (p->dispsw && p->conp)
2579 fb_con.con_cursor(p->conp, CM_ERASE);
2580 p->dispsw_data = NULL;
2581 if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
2582 if (p->type == FB_TYPE_TEXT) {
2583 swtmp = &matroxfb_text;
2584 } else {
2585 switch (p->var.bits_per_pixel) {
2586 #ifdef FBCON_HAS_CFB4
2587 case 4:
2588 swtmp = &fbcon_cfb4;
2589 break;
2590 #endif
2591 #ifdef FBCON_HAS_CFB8
2592 case 8:
2593 swtmp = &fbcon_cfb8;
2594 break;
2595 #endif
2596 #ifdef FBCON_HAS_CFB16
2597 case 16:
2598 p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
2599 swtmp = &fbcon_cfb16;
2600 break;
2601 #endif
2602 #ifdef FBCON_HAS_CFB24
2603 case 24:
2604 p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
2605 swtmp = &fbcon_cfb24;
2606 break;
2607 #endif
2608 #ifdef FBCON_HAS_CFB32
2609 case 32:
2610 p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
2611 swtmp = &fbcon_cfb32;
2612 break;
2613 #endif
2614 default:
2615 p->dispsw = &fbcon_dummy;
2616 return;
2619 dprintk(KERN_INFO "matroxfb: acceleration disabled\n");
2620 } else if (p->type == FB_TYPE_TEXT) {
2621 swtmp = &matroxfb_text;
2622 } else {
2623 switch (p->var.bits_per_pixel) {
2624 #ifdef FBCON_HAS_CFB4
2625 case 4:
2626 swtmp = &matroxfb_cfb4;
2627 break;
2628 #endif
2629 #ifdef FBCON_HAS_CFB8
2630 case 8:
2631 swtmp = &matroxfb_cfb8;
2632 break;
2633 #endif
2634 #ifdef FBCON_HAS_CFB16
2635 case 16:
2636 p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
2637 swtmp = &matroxfb_cfb16;
2638 break;
2639 #endif
2640 #ifdef FBCON_HAS_CFB24
2641 case 24:
2642 p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
2643 swtmp = &matroxfb_cfb24;
2644 break;
2645 #endif
2646 #ifdef FBCON_HAS_CFB32
2647 case 32:
2648 p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
2649 swtmp = &matroxfb_cfb32;
2650 break;
2651 #endif
2652 default:
2653 p->dispsw = &fbcon_dummy;
2654 return;
2657 memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw)));
2658 p->dispsw = &ACCESS_FBINFO(dispsw);
2659 if ((p->type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) {
2660 if (isMillenium(MINFO)) {
2661 #ifdef CONFIG_FB_MATROX_MILLENIUM
2662 ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor;
2663 ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont;
2664 #endif
2665 } else {
2666 #ifdef NEED_DAC1064
2667 ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor;
2668 ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont;
2669 #endif
2674 /* --------------------------------------------------------------------- */
2677 * card parameters
2680 /* --------------------------------------------------------------------- */
2682 static struct fb_var_screeninfo vesafb_defined __initdata = {
2683 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
2684 0,0, /* virtual -> visible no offset */
2685 8, /* depth -> load bits_per_pixel */
2686 0, /* greyscale ? */
2687 {0,0,0}, /* R */
2688 {0,0,0}, /* G */
2689 {0,0,0}, /* B */
2690 {0,0,0}, /* transparency */
2691 0, /* standard pixel format */
2692 FB_ACTIVATE_NOW,
2693 -1,-1,
2694 FB_ACCELF_TEXT, /* accel flags */
2695 39721L,48L,16L,33L,10L,
2696 96L,2L,~0, /* No sync info */
2697 FB_VMODE_NONINTERLACED,
2698 {0,0,0,0,0,0}
2703 /* --------------------------------------------------------------------- */
2705 static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
2706 unsigned int pos;
2707 unsigned short p0, p1, p2;
2708 #ifdef CONFIG_FB_MATROX_32MB
2709 unsigned int p3;
2710 #endif
2711 struct display *disp;
2713 DBG("matrox_pan_var")
2715 disp = ACCESS_FBINFO(currcon_display);
2716 if (disp->type == FB_TYPE_TEXT) {
2717 pos = var->yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(disp)?fontwidth(disp):8);
2718 } else {
2719 pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
2720 pos += ACCESS_FBINFO(curr.ydstorg.chunks);
2722 p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF;
2723 p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8;
2724 p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
2725 #ifdef CONFIG_FB_MATROX_32MB
2726 p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21;
2727 #endif
2729 CRITBEGIN
2731 mga_setr(M_CRTC_INDEX, 0x0D, p0);
2732 mga_setr(M_CRTC_INDEX, 0x0C, p1);
2733 #ifdef CONFIG_FB_MATROX_32MB
2734 if (ACCESS_FBINFO(devflags.support32MB))
2735 mga_setr(M_EXTVGA_INDEX, 0x08, p3);
2736 #endif
2737 mga_setr(M_EXTVGA_INDEX, 0x00, p2);
2739 CRITEND
2743 * Open/Release the frame buffer device
2746 static int matroxfb_open(struct fb_info *info, int user)
2748 DBG_LOOP("matroxfb_open")
2751 * Nothing, only a usage count for the moment
2753 MOD_INC_USE_COUNT;
2754 return(0);
2757 static int matroxfb_release(struct fb_info *info, int user)
2759 DBG_LOOP("matroxfb_release")
2761 MOD_DEC_USE_COUNT;
2762 return(0);
2765 static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
2766 struct fb_info* info) {
2767 #define minfo ((struct matrox_fb_info*)info)
2769 DBG("matroxfb_pan_display")
2771 if (var->vmode & FB_VMODE_YWRAP) {
2772 if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
2773 return -EINVAL;
2774 } else {
2775 if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
2776 var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
2777 return -EINVAL;
2779 if (con == ACCESS_FBINFO(currcon))
2780 matrox_pan_var(PMINFO var);
2781 fb_display[con].var.xoffset = var->xoffset;
2782 fb_display[con].var.yoffset = var->yoffset;
2783 if (var->vmode & FB_VMODE_YWRAP)
2784 fb_display[con].var.vmode |= FB_VMODE_YWRAP;
2785 else
2786 fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
2787 return 0;
2788 #undef minfo
2791 static int matroxfb_updatevar(int con, struct fb_info *info)
2793 #define minfo ((struct matrox_fb_info*)info)
2794 DBG("matroxfb_updatevar");
2796 matrox_pan_var(PMINFO &fb_display[con].var);
2797 return 0;
2798 #undef minfo
2801 static int matroxfb_get_final_bppShift(CPMINFO int bpp) {
2802 int bppshft2;
2804 DBG("matroxfb_get_final_bppShift")
2806 bppshft2 = bpp;
2807 if (!bppshft2) {
2808 return 8;
2810 if (isInterleave(MINFO))
2811 bppshft2 >>= 1;
2812 if (ACCESS_FBINFO(devflags.video64bits))
2813 bppshft2 >>= 1;
2814 return bppshft2;
2817 static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) {
2818 int over;
2819 int rounding;
2821 DBG("matroxfb_test_and_set_rounding")
2823 switch (bpp) {
2824 case 0: return xres;
2825 case 4: rounding = 128;
2826 break;
2827 case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */
2828 break;
2829 case 16: rounding = 32;
2830 break;
2831 case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */
2832 break;
2833 default: rounding = 16;
2834 /* on G400, 16 really does not work */
2835 if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
2836 rounding = 32;
2837 break;
2839 if (isInterleave(MINFO)) {
2840 rounding *= 2;
2842 over = xres % rounding;
2843 if (over)
2844 xres += rounding-over;
2845 return xres;
2848 static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) {
2849 const int* width;
2850 int xres_new;
2852 DBG("matroxfb_pitch_adjust")
2854 if (!bpp) return xres;
2856 width = ACCESS_FBINFO(capable.vxres);
2858 if (ACCESS_FBINFO(devflags.precise_width)) {
2859 while (*width) {
2860 if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) {
2861 break;
2863 width++;
2865 xres_new = *width;
2866 } else {
2867 xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp);
2869 if (!xres_new) return 0;
2870 if (xres != xres_new) {
2871 printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new);
2873 return xres_new;
2876 #ifdef CONFIG_FB_MATROX_MILLENIUM
2877 static const unsigned char DACseq[] =
2878 { TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL,
2879 TVP3026_XMUXCTRL, TVP3026_XCLKCTRL,
2880 TVP3026_XPALETTEPAGE,
2881 TVP3026_XGENCTRL,
2882 TVP3026_XMISCCTRL,
2883 TVP3026_XGENIOCTRL,
2884 TVP3026_XGENIODATA,
2885 TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
2886 TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
2887 TVP3026_XCOLKEYCTRL,
2888 TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
2890 #define POS3026_XLATCHCTRL 0
2891 #define POS3026_XTRUECOLORCTRL 1
2892 #define POS3026_XMUXCTRL 2
2893 #define POS3026_XCLKCTRL 3
2894 #define POS3026_XGENCTRL 5
2895 #define POS3026_XMISCCTRL 6
2896 #define POS3026_XMEMPLLCTRL 18
2897 #define POS3026_XCURCTRL 20
2899 static const unsigned char MGADACbpp32[] =
2900 { TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
2901 0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL,
2902 0x00,
2903 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,
2904 TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH,
2905 0x00,
2906 0x1E,
2907 0xFF, 0xFF, 0xFF, 0xFF,
2908 0xFF, 0xFF, 0xFF, 0xFF,
2909 TVP3026_XCOLKEYCTRL_ZOOM1,
2910 0x00, 0x00, TVP3026_XCURCTRL_DIS };
2911 #endif /* CONFIG_FB_MATROX_MILLENIUM */
2913 static int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
2914 unsigned int bestdiff = ~0;
2915 unsigned int bestvco = 0;
2916 unsigned int fxtal = ACCESS_FBINFO(features.pll.ref_freq);
2917 unsigned int fwant;
2918 unsigned int p;
2920 DBG("PLL_calcclock")
2922 fwant = freq;
2924 #ifdef DEBUG
2925 printk(KERN_ERR "post_shift_max: %d\n", ACCESS_FBINFO(features.pll.post_shift_max));
2926 printk(KERN_ERR "ref_freq: %d\n", ACCESS_FBINFO(features.pll.ref_freq));
2927 printk(KERN_ERR "freq: %d\n", freq);
2928 printk(KERN_ERR "vco_freq_min: %d\n", ACCESS_FBINFO(features.pll.vco_freq_min));
2929 printk(KERN_ERR "in_div_min: %d\n", ACCESS_FBINFO(features.pll.in_div_min));
2930 printk(KERN_ERR "in_div_max: %d\n", ACCESS_FBINFO(features.pll.in_div_max));
2931 printk(KERN_ERR "feed_div_min: %d\n", ACCESS_FBINFO(features.pll.feed_div_min));
2932 printk(KERN_ERR "feed_div_max: %d\n", ACCESS_FBINFO(features.pll.feed_div_max));
2933 printk(KERN_ERR "fmax: %d\n", fmax);
2934 #endif
2935 for (p = 1; p <= ACCESS_FBINFO(features.pll.post_shift_max); p++) {
2936 if (fwant * 2 > fmax)
2937 break;
2938 fwant *= 2;
2940 if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) fwant = ACCESS_FBINFO(features.pll.vco_freq_min);
2941 if (fwant > fmax) fwant = fmax;
2942 for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) {
2943 unsigned int m;
2945 if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) break;
2946 for (m = ACCESS_FBINFO(features.pll.in_div_min); m <= ACCESS_FBINFO(features.pll.in_div_max); m++) {
2947 unsigned int diff, fvco;
2948 unsigned int n;
2950 n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1;
2951 if (n > ACCESS_FBINFO(features.pll.feed_div_max))
2952 break;
2953 if (n < ACCESS_FBINFO(features.pll.feed_div_min))
2954 n = ACCESS_FBINFO(features.pll.feed_div_min);
2955 fvco = (fxtal * (n + 1)) / (m + 1);
2956 if (fvco < fwant)
2957 diff = fwant - fvco;
2958 else
2959 diff = fvco - fwant;
2960 if (diff < bestdiff) {
2961 bestdiff = diff;
2962 *post = p;
2963 *in = m;
2964 *feed = n;
2965 bestvco = fvco;
2969 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant);
2970 return bestvco;
2973 #ifdef NEED_DAC1064
2974 static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
2975 unsigned int fvco;
2976 unsigned int p;
2978 DBG("DAC1064_calcclock")
2980 fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
2981 p = (1 << p) - 1;
2982 if (fvco <= 100000)
2984 else if (fvco <= 140000)
2985 p |= 0x08;
2986 else if (fvco <= 180000)
2987 p |= 0x10;
2988 else
2989 p |= 0x18;
2990 *post = p;
2992 #endif
2994 #ifdef CONFIG_FB_MATROX_MILLENIUM
2995 static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) {
2996 unsigned int fvco;
2997 unsigned int lin, lfeed, lpost;
2999 DBG("Ti3026_calcclock")
3001 fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost);
3002 fvco >>= (*post = lpost);
3003 *in = 64 - lin;
3004 *feed = 64 - lfeed;
3005 return fvco;
3008 static int Ti3026_setpclk(CPMINFO struct matrox_hw_state* hw, int clk, struct display* p) {
3009 unsigned int f_pll;
3010 unsigned int pixfeed, pixin, pixpost;
3012 DBG("Ti3026_setpclk")
3014 f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost);
3016 hw->DACclk[0] = pixin | 0xC0;
3017 hw->DACclk[1] = pixfeed;
3018 hw->DACclk[2] = pixpost | 0xB0;
3020 if (p->type == FB_TYPE_TEXT) {
3021 hw->DACreg[POS3026_XMEMPLLCTRL] = TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_PIXPLL;
3022 hw->DACclk[3] = 0xFD;
3023 hw->DACclk[4] = 0x3D;
3024 hw->DACclk[5] = 0x70;
3025 } else {
3026 unsigned int loopfeed, loopin, looppost, loopdiv, z;
3027 unsigned int Bpp;
3029 Bpp = ACCESS_FBINFO(curr.final_bppShift);
3031 if (p->var.bits_per_pixel == 24) {
3032 loopfeed = 3; /* set lm to any possible value */
3033 loopin = 3 * 32 / Bpp;
3034 } else {
3035 loopfeed = 4;
3036 loopin = 4 * 32 / Bpp;
3038 z = (110000 * loopin) / (f_pll * loopfeed);
3039 loopdiv = 0; /* div 2 */
3040 if (z < 2)
3041 looppost = 0;
3042 else if (z < 4)
3043 looppost = 1;
3044 else if (z < 8)
3045 looppost = 2;
3046 else {
3047 looppost = 3;
3048 loopdiv = z/16;
3050 if (p->var.bits_per_pixel == 24) {
3051 hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
3052 hw->DACclk[4] = (65 - loopfeed) | 0x80;
3053 if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) {
3054 if (isInterleave(MINFO))
3055 hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
3056 else {
3057 hw->DACclk[4] &= ~0xC0;
3058 hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
3060 } else {
3061 if (isInterleave(MINFO))
3062 ; /* default... */
3063 else {
3064 hw->DACclk[4] ^= 0xC0; /* change from 0x80 to 0x40 */
3065 hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3;
3068 hw->DACclk[5] = looppost | 0xF8;
3069 if (ACCESS_FBINFO(devflags.mga_24bpp_fix))
3070 hw->DACclk[5] ^= 0x40;
3071 } else {
3072 hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
3073 hw->DACclk[4] = 65 - loopfeed;
3074 hw->DACclk[5] = looppost | 0xF0;
3076 hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
3078 return 0;
3080 #endif
3082 static void var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
3083 unsigned int pixclock = var->pixclock;
3085 DBG("var2my")
3087 if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
3088 mt->pixclock = 1000000000 / pixclock;
3089 if (mt->pixclock < 1) mt->pixclock = 1;
3090 mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
3091 mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
3092 mt->HDisplay = var->xres;
3093 mt->HSyncStart = mt->HDisplay + var->right_margin;
3094 mt->HSyncEnd = mt->HSyncStart + var->hsync_len;
3095 mt->HTotal = mt->HSyncEnd + var->left_margin;
3096 mt->VDisplay = var->yres;
3097 mt->VSyncStart = mt->VDisplay + var->lower_margin;
3098 mt->VSyncEnd = mt->VSyncStart + var->vsync_len;
3099 mt->VTotal = mt->VSyncEnd + var->upper_margin;
3100 mt->sync = var->sync;
3103 static int vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
3104 unsigned int hd, hs, he, hbe, ht;
3105 unsigned int vd, vs, ve, vt;
3106 unsigned int wd;
3107 unsigned int divider;
3108 int i;
3109 int text = p->type == FB_TYPE_TEXT;
3110 int fwidth;
3112 if (text) {
3113 fwidth = fontwidth(p);
3114 if (!fwidth) fwidth = 8;
3115 } else
3116 fwidth = 8;
3118 DBG("vgaHWinit")
3120 hw->SEQ[0] = 0x00;
3121 if (fwidth == 9)
3122 hw->SEQ[1] = 0x00;
3123 else
3124 hw->SEQ[1] = 0x01; /* or 0x09 */
3125 hw->SEQ[2] = 0x0F; /* bitplanes */
3126 hw->SEQ[3] = 0x00;
3127 if (text)
3128 hw->SEQ[4] = 0x02;
3129 else
3130 hw->SEQ[4] = 0x0E;
3131 /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millenium code... Hope that by MGA1064 too */
3132 if (m->dblscan) {
3133 m->VTotal <<= 1;
3134 m->VDisplay <<= 1;
3135 m->VSyncStart <<= 1;
3136 m->VSyncEnd <<= 1;
3138 if (m->interlaced) {
3139 m->VTotal >>= 1;
3140 m->VDisplay >>= 1;
3141 m->VSyncStart >>= 1;
3142 m->VSyncEnd >>= 1;
3145 /* GCTL is ignored when not using 0xA0000 aperture */
3146 hw->GCTL[0] = 0x00;
3147 hw->GCTL[1] = 0x00;
3148 hw->GCTL[2] = 0x00;
3149 hw->GCTL[3] = 0x00;
3150 hw->GCTL[4] = 0x00;
3151 if (text) {
3152 hw->GCTL[5] = 0x10;
3153 hw->GCTL[6] = 0x02;
3154 } else {
3155 hw->GCTL[5] = 0x40;
3156 hw->GCTL[6] = 0x05;
3158 hw->GCTL[7] = 0x0F;
3159 hw->GCTL[8] = 0xFF;
3161 /* Whole ATTR is ignored in PowerGraphics mode */
3162 for (i = 0; i < 16; i++)
3163 hw->ATTR[i] = i;
3164 if (text) {
3165 hw->ATTR[16] = 0x04;
3166 } else {
3167 hw->ATTR[16] = 0x41;
3169 hw->ATTR[17] = 0xFF;
3170 hw->ATTR[18] = 0x0F;
3171 if (fwidth == 9)
3172 hw->ATTR[19] = 0x08;
3173 else
3174 hw->ATTR[19] = 0x00;
3175 hw->ATTR[20] = 0x00;
3177 if (text) {
3178 hd = m->HDisplay / fwidth;
3179 hs = m->HSyncStart / fwidth;
3180 he = m->HSyncEnd / fwidth;
3181 ht = m->HTotal / fwidth;
3182 divider = 8;
3183 } else {
3184 hd = m->HDisplay >> 3;
3185 hs = m->HSyncStart >> 3;
3186 he = m->HSyncEnd >> 3;
3187 ht = m->HTotal >> 3;
3188 /* standard timmings are in 8pixels, but for interleaved we cannot */
3189 /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */
3190 /* using 16 or more pixels per unit can save us */
3191 divider = ACCESS_FBINFO(curr.final_bppShift);
3193 while (divider & 3) {
3194 hd >>= 1;
3195 hs >>= 1;
3196 he >>= 1;
3197 ht >>= 1;
3198 divider <<= 1;
3200 divider = divider / 4;
3201 /* divider can be from 1 to 8 */
3202 while (divider > 8) {
3203 hd <<= 1;
3204 hs <<= 1;
3205 he <<= 1;
3206 ht <<= 1;
3207 divider >>= 1;
3209 hd = hd - 1;
3210 hs = hs - 1;
3211 he = he - 1;
3212 ht = ht - 1;
3213 vd = m->VDisplay - 1;
3214 vs = m->VSyncStart - 1;
3215 ve = m->VSyncEnd - 1;
3216 vt = m->VTotal - 2;
3217 /* G200 cannot work with (ht & 7) == 6 */
3218 if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04))
3219 ht++;
3220 if (text) {
3221 hbe = ht - 1;
3222 wd = p->var.xres_virtual / (fwidth * 2);
3223 } else {
3224 hbe = ht;
3225 wd = p->var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64;
3228 hw->CRTCEXT[0] = 0;
3229 hw->CRTCEXT[5] = 0;
3230 if (m->interlaced) {
3231 hw->CRTCEXT[0] = 0x80;
3232 hw->CRTCEXT[5] = (hs + he - ht) >> 1;
3233 if (!m->dblscan)
3234 wd <<= 1;
3235 vt &= ~1;
3237 hw->CRTCEXT[0] |= (wd & 0x300) >> 4;
3238 hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) |
3239 ((hd & 0x100) >> 7) | /* blanking */
3240 ((hs & 0x100) >> 6) | /* sync start */
3241 (hbe & 0x040); /* end hor. blanking */
3242 hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) |
3243 ((vd & 0x400) >> 8) | /* disp end */
3244 ((vd & 0xC00) >> 7) | /* vblanking start */
3245 ((vs & 0xC00) >> 5);
3246 if (text)
3247 hw->CRTCEXT[3] = 0x00;
3248 else
3249 hw->CRTCEXT[3] = (divider - 1) | 0x80;
3250 hw->CRTCEXT[4] = 0;
3252 hw->CRTC[0] = ht-4;
3253 hw->CRTC[1] = hd;
3254 hw->CRTC[2] = hd;
3255 hw->CRTC[3] = (hbe & 0x1F) | 0x80;
3256 hw->CRTC[4] = hs;
3257 hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F);
3258 if (text)
3259 hw->CRTC[5] |= 0x60; /* delay sync for 3 clocks (to same picture position on MGA and VGA) */
3260 hw->CRTC[6] = vt & 0xFF;
3261 hw->CRTC[7] = ((vt & 0x100) >> 8) |
3262 ((vd & 0x100) >> 7) |
3263 ((vs & 0x100) >> 6) |
3264 ((vd & 0x100) >> 5) |
3265 0x10 |
3266 ((vt & 0x200) >> 4) |
3267 ((vd & 0x200) >> 3) |
3268 ((vs & 0x200) >> 2);
3269 hw->CRTC[8] = 0x00;
3270 hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40;
3271 if (text)
3272 hw->CRTC[9] |= fontheight(p) - 1;
3273 if (m->dblscan && !m->interlaced)
3274 hw->CRTC[9] |= 0x80;
3275 for (i = 10; i < 16; i++)
3276 hw->CRTC[i] = 0x00;
3277 hw->CRTC[16] = vs /* & 0xFF */;
3278 hw->CRTC[17] = (ve & 0x0F) | 0x20;
3279 hw->CRTC[18] = vd /* & 0xFF */;
3280 hw->CRTC[19] = wd /* & 0xFF */;
3281 hw->CRTC[20] = 0x00;
3282 hw->CRTC[21] = vd /* & 0xFF */;
3283 hw->CRTC[22] = (vt + 1) /* & 0xFF */;
3284 if (text) {
3285 if (ACCESS_FBINFO(devflags.textmode) == 1)
3286 hw->CRTC[23] = 0xC3;
3287 else
3288 hw->CRTC[23] = 0xA3;
3289 if (ACCESS_FBINFO(devflags.textmode) == 4)
3290 hw->CRTC[20] = 0x5F;
3291 else
3292 hw->CRTC[20] = 0x1F;
3293 } else
3294 hw->CRTC[23] = 0xC3;
3295 hw->CRTC[24] = 0xFF;
3296 return 0;
3299 #ifdef NEED_DAC1064
3301 static const unsigned char MGA1064_DAC_regs[] = {
3302 M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
3303 M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
3304 M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
3305 M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE,
3306 DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL,
3307 M1064_XMISCCTRL,
3308 M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST,
3309 M1064_XCRCBITSEL,
3310 M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
3312 #define POS1064_XCURADDL 0
3313 #define POS1064_XCURADDH 1
3314 #define POS1064_XVREFCTRL 12
3315 #define POS1064_XMULCTRL 13
3316 #define POS1064_XGENCTRL 15
3317 #define POS1064_XMISCCTRL 16
3319 static const unsigned char MGA1064_DAC[] = {
3320 0x00, 0x00, M1064_XCURCTRL_DIS,
3321 0x00, 0x00, 0x00, /* black */
3322 0xFF, 0xFF, 0xFF, /* white */
3323 0xFF, 0x00, 0x00, /* red */
3324 0x00, 0,
3325 M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL,
3326 M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN,
3327 M1064_XMISCCTRL_DAC_EN | M1064_XMISCCTRL_MFC_DIS | M1064_XMISCCTRL_DAC_8BIT | M1064_XMISCCTRL_LUT_EN,
3328 0x10, 0x3F, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN,
3329 0x00,
3330 0x00, 0x00, 0xFF, 0xFF};
3332 static void DAC1064_setpclk(CPMINFO struct matrox_hw_state* hw, unsigned long fout) {
3333 unsigned int m, n, p;
3335 DBG("DAC1064_setpclk")
3337 DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
3338 hw->DACclk[0] = m;
3339 hw->DACclk[1] = n;
3340 hw->DACclk[2] = p;
3343 static void __init DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem){
3344 u_int32_t mx;
3346 DBG("DAC1064_setmclk")
3348 if (ACCESS_FBINFO(devflags.noinit)) {
3349 /* read MCLK and give up... */
3350 hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
3351 hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
3352 hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
3353 return;
3355 mx = hw->MXoptionReg | 0x00000004;
3356 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
3357 mx &= ~0x000000BB;
3358 if (oscinfo & DAC1064_OPT_GDIV1)
3359 mx |= 0x00000008;
3360 if (oscinfo & DAC1064_OPT_MDIV1)
3361 mx |= 0x00000010;
3362 if (oscinfo & DAC1064_OPT_RESERVED)
3363 mx |= 0x00000080;
3364 if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
3365 /* select PCI clock until we have setup oscilator... */
3366 int clk;
3367 unsigned int m, n, p;
3369 /* powerup system PLL, select PCI clock */
3370 mx |= 0x00000020;
3371 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
3372 mx &= ~0x00000004;
3373 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
3375 /* !!! you must not access device if MCLK is not running !!!
3376 Doing so cause immediate PCI lockup :-( Maybe they should
3377 generate ABORT or I/O (parity...) error and Linux should
3378 recover from this... (kill driver/process). But world is not
3379 perfect... */
3380 /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
3381 select PLL... because of PLL can be stopped at this time) */
3382 DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
3383 outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m);
3384 outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n);
3385 outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p);
3386 for (clk = 65536; clk; --clk) {
3387 if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
3388 break;
3390 if (!clk)
3391 printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
3392 /* select PLL */
3393 mx |= 0x00000005;
3394 } else {
3395 /* select specified system clock source */
3396 mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
3398 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
3399 mx &= ~0x00000004;
3400 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
3401 hw->MXoptionReg = mx;
3404 static int DAC1064_init_1(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display *p) {
3406 DBG("DAC1064_init_1")
3408 memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
3409 if (p->type == FB_TYPE_TEXT) {
3410 hw->DACreg[POS1064_XMISCCTRL] = M1064_XMISCCTRL_DAC_EN
3411 | M1064_XMISCCTRL_MFC_DIS
3412 | M1064_XMISCCTRL_DAC_6BIT
3413 | M1064_XMISCCTRL_LUT_EN;
3414 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP
3415 | M1064_XMULCTRL_GRAPHICS_PALETIZED;
3416 } else {
3417 switch (p->var.bits_per_pixel) {
3418 /* case 4: not supported by MGA1064 DAC */
3419 case 8:
3420 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
3421 break;
3422 case 16:
3423 if (p->var.green.length == 5)
3424 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
3425 else
3426 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
3427 break;
3428 case 24:
3429 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
3430 break;
3431 case 32:
3432 hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
3433 break;
3434 default:
3435 return 1; /* unsupported depth */
3438 hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
3439 hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
3440 hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
3441 hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10;
3442 hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18;
3443 return 0;
3446 static int DAC1064_init_2(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
3448 DBG("DAC1064_init_2")
3450 DAC1064_setpclk(PMINFO hw, m->pixclock);
3451 if (p->var.bits_per_pixel > 16) { /* 256 entries */
3452 int i;
3454 for (i = 0; i < 256; i++) {
3455 hw->DACpal[i * 3 + 0] = i;
3456 hw->DACpal[i * 3 + 1] = i;
3457 hw->DACpal[i * 3 + 2] = i;
3459 } else if (p->var.bits_per_pixel > 8) {
3460 if (p->var.green.length == 5) { /* 0..31, 128..159 */
3461 int i;
3463 for (i = 0; i < 32; i++) {
3464 /* with p15 == 0 */
3465 hw->DACpal[i * 3 + 0] = i << 3;
3466 hw->DACpal[i * 3 + 1] = i << 3;
3467 hw->DACpal[i * 3 + 2] = i << 3;
3468 /* with p15 == 1 */
3469 hw->DACpal[(i + 128) * 3 + 0] = i << 3;
3470 hw->DACpal[(i + 128) * 3 + 1] = i << 3;
3471 hw->DACpal[(i + 128) * 3 + 2] = i << 3;
3473 } else {
3474 int i;
3476 for (i = 0; i < 64; i++) { /* 0..63 */
3477 hw->DACpal[i * 3 + 0] = i << 3;
3478 hw->DACpal[i * 3 + 1] = i << 2;
3479 hw->DACpal[i * 3 + 2] = i << 3;
3482 } else {
3483 memset(hw->DACpal, 0, 768);
3485 return 0;
3488 static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
3490 DBG("DAC1064_restore_1")
3492 CRITBEGIN
3494 outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
3495 outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
3496 outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
3497 if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) {
3498 unsigned int i;
3500 for (i = 0; i < sizeof(MGA1064_DAC_regs); i++)
3501 outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
3504 CRITEND
3507 static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) {
3508 unsigned int i;
3509 unsigned int tmout;
3511 DBG("DAC1064_restore_2")
3513 CRITBEGIN
3515 for (i = 0; i < 3; i++)
3516 outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
3517 for (tmout = 500000; tmout; tmout--) {
3518 if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
3519 break;
3520 udelay(10);
3523 CRITEND
3525 if (!tmout)
3526 printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
3528 if (p && p->conp) {
3529 if (p->type == FB_TYPE_TEXT) {
3530 matrox_text_createcursor(PMINFO p);
3531 matrox_text_loadfont(PMINFO p);
3532 i = 0;
3533 } else {
3534 matroxfb_DAC1064_createcursor(PMINFO p);
3535 i = matroxfb_fastfont_tryset(PMINFO p);
3537 } else
3538 i = 0;
3539 if (i) {
3540 ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc;
3541 ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs;
3542 } else {
3543 ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc;
3544 ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs;
3546 #ifdef DEBUG
3547 dprintk(KERN_DEBUG "DAC1064regs ");
3548 for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
3549 dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], hw->DACreg[i]);
3550 if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
3552 dprintk("\n" KERN_DEBUG "DAC1064clk ");
3553 for (i = 0; i < 6; i++)
3554 dprintk("C%02X=%02X ", i, hw->DACclk[i]);
3555 dprintk("\n");
3556 #endif
3558 #endif /* NEED_DAC1064 */
3560 #ifdef CONFIG_FB_MATROX_MYSTIQUE
3561 static int MGA1064_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
3563 DBG("MGA1064_init")
3565 if (DAC1064_init_1(PMINFO hw, m, p)) return 1;
3566 if (vgaHWinit(PMINFO hw, m, p)) return 1;
3568 hw->MiscOutReg = 0xCB;
3569 if (m->sync & FB_SYNC_HOR_HIGH_ACT)
3570 hw->MiscOutReg &= ~0x40;
3571 if (m->sync & FB_SYNC_VERT_HIGH_ACT)
3572 hw->MiscOutReg &= ~0x80;
3573 if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
3574 hw->CRTCEXT[3] |= 0x40;
3576 if (DAC1064_init_2(PMINFO hw, m, p)) return 1;
3577 return 0;
3579 #endif
3581 #ifdef CONFIG_FB_MATROX_G100
3582 static int MGAG100_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
3584 DBG("MGAG100_init")
3586 if (DAC1064_init_1(PMINFO hw, m, p)) return 1;
3587 hw->MXoptionReg &= ~0x2000;
3588 if (vgaHWinit(PMINFO hw, m, p)) return 1;
3590 hw->MiscOutReg = 0xEF;
3591 if (m->sync & FB_SYNC_HOR_HIGH_ACT)
3592 hw->MiscOutReg &= ~0x40;
3593 if (m->sync & FB_SYNC_VERT_HIGH_ACT)
3594 hw->MiscOutReg &= ~0x80;
3595 if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
3596 hw->CRTCEXT[3] |= 0x40;
3598 if (DAC1064_init_2(PMINFO hw, m, p)) return 1;
3599 return 0;
3601 #endif /* G100 */
3603 #ifdef CONFIG_FB_MATROX_MILLENIUM
3604 static int Ti3026_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
3605 u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
3607 DBG("Ti3026_init")
3609 memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
3610 if (p->type == FB_TYPE_TEXT) {
3611 hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;
3612 hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
3613 hw->DACreg[POS3026_XMUXCTRL] = TVP3026_XMUXCTRL_VGA;
3614 hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL |
3615 TVP3026_XCLKCTRL_DIV4;
3616 hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_6BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
3617 } else {
3618 switch (p->var.bits_per_pixel) {
3619 case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1; /* or _8_1, they are same */
3620 hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
3621 hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
3622 hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
3623 hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
3624 break;
3625 case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; /* or _4_1, they are same */
3626 hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
3627 hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
3628 hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
3629 hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
3630 break;
3631 case 16:
3632 /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */
3633 hw->DACreg[POS3026_XTRUECOLORCTRL] = (p->var.green.length == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565);
3634 hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
3635 hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
3636 break;
3637 case 24:
3638 /* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
3639 hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
3640 hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
3641 hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
3642 break;
3643 case 32:
3644 /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */
3645 hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
3646 break;
3647 default:
3648 return 1; /* TODO: failed */
3651 if (vgaHWinit(PMINFO hw, m, p)) return 1;
3653 /* set SYNC */
3654 hw->MiscOutReg = 0xCB;
3655 if (m->sync & FB_SYNC_HOR_HIGH_ACT)
3656 hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
3657 if (m->sync & FB_SYNC_VERT_HIGH_ACT)
3658 hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
3659 if (m->sync & FB_SYNC_ON_GREEN)
3660 hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
3662 /* set DELAY */
3663 if (ACCESS_FBINFO(video.len) < 0x400000)
3664 hw->CRTCEXT[3] |= 0x08;
3665 else if (ACCESS_FBINFO(video.len) > 0x400000)
3666 hw->CRTCEXT[3] |= 0x10;
3668 /* set HWCURSOR */
3669 if (m->interlaced) {
3670 hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
3672 if (m->HTotal >= 1536)
3673 hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096;
3675 /* set interleaving */
3676 hw->MXoptionReg &= ~0x00001000;
3677 if ((p->type != FB_TYPE_TEXT) && isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
3679 /* set DAC */
3680 Ti3026_setpclk(PMINFO hw, m->pixclock, p);
3681 return 0;
3683 #endif /* CONFIG_FB_MATROX_MILLENIUM */
3685 static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
3687 DBG("matroxfb_get_cmap_len")
3689 switch (var->bits_per_pixel) {
3690 #ifdef FBCON_HAS_VGATEXT
3691 case 0:
3692 return 16; /* pseudocolor... 16 entries HW palette */
3693 #endif
3694 #ifdef FBCON_HAS_CFB4
3695 case 4:
3696 return 16; /* pseudocolor... 16 entries HW palette */
3697 #endif
3698 #ifdef FBCON_HAS_CFB8
3699 case 8:
3700 return 256; /* pseudocolor... 256 entries HW palette */
3701 #endif
3702 #ifdef FBCON_HAS_CFB16
3703 case 16:
3704 return 16; /* directcolor... 16 entries SW palette */
3705 /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
3706 #endif
3707 #ifdef FBCON_HAS_CFB24
3708 case 24:
3709 return 16; /* directcolor... 16 entries SW palette */
3710 /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
3711 #endif
3712 #ifdef FBCON_HAS_CFB32
3713 case 32:
3714 return 16; /* directcolor... 16 entries SW palette */
3715 /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
3716 #endif
3718 return 16; /* return something reasonable... or panic()? */
3721 static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) {
3722 unsigned int vramlen;
3723 unsigned int memlen;
3725 DBG("matroxfb_decode_var")
3727 switch (var->bits_per_pixel) {
3728 #ifdef FBCON_HAS_VGATEXT
3729 case 0: if (!ACCESS_FBINFO(capable.text)) return -EINVAL;
3730 break;
3731 #endif
3732 #ifdef FBCON_HAS_CFB4
3733 case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL;
3734 break;
3735 #endif
3736 #ifdef FBCON_HAS_CFB8
3737 case 8: break;
3738 #endif
3739 #ifdef FBCON_HAS_CFB16
3740 case 16: break;
3741 #endif
3742 #ifdef FBCON_HAS_CFB24
3743 case 24: break;
3744 #endif
3745 #ifdef FBCON_HAS_CFB32
3746 case 32: break;
3747 #endif
3748 default: return -EINVAL;
3750 *ydstorg = 0;
3751 vramlen = ACCESS_FBINFO(video.len_usable);
3752 if (var->bits_per_pixel) {
3753 var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel);
3754 memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
3755 if (memlen > vramlen) {
3756 var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
3757 memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
3759 /* There is hardware bug that no line can cross 4MB boundary */
3760 /* give up for CFB24, it is impossible to easy workaround it */
3761 /* for other try to do something */
3762 if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) {
3763 if (var->bits_per_pixel == 24) {
3764 /* sorry */
3765 } else {
3766 unsigned int linelen;
3767 unsigned int m1 = linelen = var->xres_virtual * var->bits_per_pixel / 8;
3768 unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */
3769 unsigned int max_yres;
3771 while (m1) {
3772 int t;
3774 while (m2 >= m1) m2 -= m1;
3775 t = m1;
3776 m1 = m2;
3777 m2 = t;
3779 m2 = linelen * PAGE_SIZE / m2;
3780 *ydstorg = m2 = 0x400000 % m2;
3781 max_yres = (vramlen - m2) / linelen;
3782 if (var->yres_virtual > max_yres)
3783 var->yres_virtual = max_yres;
3786 } else {
3787 matrox_text_round(PMINFO var, p);
3788 #if 0
3789 /* we must limit pixclock by mclk...
3790 Millenium I: 66 MHz = 15000
3791 Millenium II: 61 MHz = 16300
3792 Millenium G200: 83 MHz = 12000 */
3793 if (var->pixclock < 15000)
3794 var->pixclock = 15000; /* limit for "normal" gclk & mclk */
3795 #endif
3797 /* YDSTLEN contains only signed 16bit value */
3798 if (var->yres_virtual > 32767)
3799 var->yres_virtual = 32767;
3800 if (var->yres_virtual < var->yres)
3801 var->yres = var->yres_virtual;
3802 if (var->xres_virtual < var->xres)
3803 var->xres = var->xres_virtual;
3804 if (var->xoffset + var->xres > var->xres_virtual)
3805 var->xoffset = var->xres_virtual - var->xres;
3806 if (var->yoffset + var->yres > var->yres_virtual)
3807 var->yoffset = var->yres_virtual - var->yres;
3809 if (var->bits_per_pixel == 0) {
3810 var->red.offset = 0;
3811 var->red.length = 6;
3812 var->green.offset = 0;
3813 var->green.length = 6;
3814 var->blue.offset = 0;
3815 var->blue.length = 6;
3816 var->transp.offset = 0;
3817 var->transp.length = 0;
3818 *visual = MX_VISUAL_PSEUDOCOLOR;
3819 } else if (var->bits_per_pixel == 4) {
3820 var->red.offset = 0;
3821 var->red.length = 8;
3822 var->green.offset = 0;
3823 var->green.length = 8;
3824 var->blue.offset = 0;
3825 var->blue.length = 8;
3826 var->transp.offset = 0;
3827 var->transp.length = 0;
3828 *visual = MX_VISUAL_PSEUDOCOLOR;
3829 } else if (var->bits_per_pixel <= 8) {
3830 var->red.offset = 0;
3831 var->red.length = 8;
3832 var->green.offset = 0;
3833 var->green.length = 8;
3834 var->blue.offset = 0;
3835 var->blue.length = 8;
3836 var->transp.offset = 0;
3837 var->transp.length = 0;
3838 *visual = MX_VISUAL_PSEUDOCOLOR;
3839 } else {
3840 if (var->bits_per_pixel <= 16) {
3841 if (var->green.length == 5) {
3842 var->red.offset = 10;
3843 var->red.length = 5;
3844 var->green.offset = 5;
3845 var->green.length = 5;
3846 var->blue.offset = 0;
3847 var->blue.length = 5;
3848 var->transp.offset = 15;
3849 var->transp.length = 1;
3850 } else {
3851 var->red.offset = 11;
3852 var->red.length = 5;
3853 var->green.offset = 5;
3854 var->green.length = 6;
3855 var->blue.offset = 0;
3856 var->blue.length = 5;
3857 var->transp.offset = 0;
3858 var->transp.length = 0;
3860 } else if (var->bits_per_pixel <= 24) {
3861 var->red.offset = 16;
3862 var->red.length = 8;
3863 var->green.offset = 8;
3864 var->green.length = 8;
3865 var->blue.offset = 0;
3866 var->blue.length = 8;
3867 var->transp.offset = 0;
3868 var->transp.length = 0;
3869 } else {
3870 var->red.offset = 16;
3871 var->red.length = 8;
3872 var->green.offset = 8;
3873 var->green.length = 8;
3874 var->blue.offset = 0;
3875 var->blue.length = 8;
3876 var->transp.offset = 24;
3877 var->transp.length = 8;
3879 dprintk("matroxfb: truecolor: "
3880 "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
3881 var->transp.length,
3882 var->red.length,
3883 var->green.length,
3884 var->blue.length,
3885 var->transp.offset,
3886 var->red.offset,
3887 var->green.offset,
3888 var->blue.offset);
3889 *visual = MX_VISUAL_DIRECTCOLOR;
3891 *video_cmap_len = matroxfb_get_cmap_len(var);
3892 dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
3893 var->xres_virtual, var->yres_virtual);
3894 return 0;
3897 #ifdef CONFIG_FB_MATROX_MILLENIUM
3898 static void __init ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout){
3899 unsigned int f_pll;
3900 unsigned int pclk_m, pclk_n, pclk_p;
3901 unsigned int mclk_m, mclk_n, mclk_p;
3902 unsigned int rfhcnt, mclk_ctl;
3903 int tmout;
3905 DBG("ti3026_setMCLK")
3907 f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p);
3909 /* save pclk */
3910 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
3911 pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
3912 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD);
3913 pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
3914 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
3915 pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
3917 /* stop pclk */
3918 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
3919 outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
3921 /* set pclk to new mclk */
3922 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
3923 outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
3924 outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m);
3925 outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
3927 /* wait for PLL to lock */
3928 for (tmout = 500000; tmout; tmout--) {
3929 if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
3930 break;
3931 udelay(10);
3933 if (!tmout)
3934 printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
3936 /* output pclk on mclk pin */
3937 mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL);
3938 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
3939 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
3941 /* stop MCLK */
3942 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB);
3943 outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00);
3945 /* set mclk to new freq */
3946 outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3);
3947 outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
3948 outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m);
3949 outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
3951 /* wait for PLL to lock */
3952 for (tmout = 500000; tmout; tmout--) {
3953 if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40)
3954 break;
3955 udelay(10);
3957 if (!tmout)
3958 printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
3960 f_pll = f_pll * 333 / (10000 << mclk_p);
3961 if (isMilleniumII(MINFO)) {
3962 rfhcnt = (f_pll - 128) / 256;
3963 if (rfhcnt > 15)
3964 rfhcnt = 15;
3965 } else {
3966 rfhcnt = (f_pll - 64) / 128;
3967 if (rfhcnt > 15)
3968 rfhcnt = 0;
3970 hw->MXoptionReg = (hw->MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
3971 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
3973 /* output MCLK to MCLK pin */
3974 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
3975 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
3977 /* stop PCLK */
3978 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
3979 outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
3981 /* restore pclk */
3982 outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
3983 outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n);
3984 outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m);
3985 outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p);
3987 /* wait for PLL to lock */
3988 for (tmout = 500000; tmout; tmout--) {
3989 if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
3990 break;
3991 udelay(10);
3993 if (!tmout)
3994 printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
3997 static void __init ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw){
3999 DBG("ti3026_ramdac_init")
4001 ACCESS_FBINFO(features.pll.vco_freq_min) = 110000;
4002 ACCESS_FBINFO(features.pll.ref_freq) = 114545;
4003 ACCESS_FBINFO(features.pll.feed_div_min) = 2;
4004 ACCESS_FBINFO(features.pll.feed_div_max) = 24;
4005 ACCESS_FBINFO(features.pll.in_div_min) = 2;
4006 ACCESS_FBINFO(features.pll.in_div_max) = 63;
4007 ACCESS_FBINFO(features.pll.post_shift_max) = 3;
4008 if (ACCESS_FBINFO(devflags.noinit))
4009 return;
4010 ti3026_setMCLK(PMINFO hw, 60000);
4012 #endif
4014 static void matroxfb_fastfont_init(struct matrox_fb_info* minfo){
4015 unsigned int size;
4017 size = ACCESS_FBINFO(fastfont.size);
4018 ACCESS_FBINFO(fastfont.size) = 0;
4019 if (size) {
4020 unsigned int end = ACCESS_FBINFO(video.len_usable);
4022 if (size < end) {
4023 unsigned int start;
4025 start = (end - size) & PAGE_MASK;
4026 if (start >= 0x00100000) {
4027 ACCESS_FBINFO(video.len_usable) = start;
4028 ACCESS_FBINFO(fastfont.mgabase) = start * 8;
4029 ACCESS_FBINFO(fastfont.vbase) = ACCESS_FBINFO(video.vbase);
4030 vaddr_add(&ACCESS_FBINFO(fastfont.vbase), start);
4031 ACCESS_FBINFO(fastfont.size) = end - start;
4037 #ifdef CONFIG_FB_MATROX_MYSTIQUE
4038 static void __init MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw){
4040 DBG("MGA1064_ramdac_init");
4042 /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */
4043 ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
4044 ACCESS_FBINFO(features.pll.ref_freq) = 14318;
4045 ACCESS_FBINFO(features.pll.feed_div_min) = 100;
4046 ACCESS_FBINFO(features.pll.feed_div_max) = 127;
4047 ACCESS_FBINFO(features.pll.in_div_min) = 1;
4048 ACCESS_FBINFO(features.pll.in_div_max) = 31;
4049 ACCESS_FBINFO(features.pll.post_shift_max) = 3;
4050 ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL;
4051 /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
4052 DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
4055 static int __init MGA1064_preinit(WPMINFO struct matrox_hw_state* hw){
4056 static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960,
4057 1024, 1152, 1280, 1600, 1664, 1920,
4058 2048, 0};
4059 DBG("MGA1064_preinit")
4061 /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
4062 ACCESS_FBINFO(capable.text) = 1;
4063 ACCESS_FBINFO(capable.vxres) = vxres_mystique;
4064 ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
4065 ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
4067 if (ACCESS_FBINFO(devflags.noinit))
4068 return 0; /* do not modify settings */
4069 hw->MXoptionReg &= 0xC0000100;
4070 hw->MXoptionReg |= 0x00094E20;
4071 if (ACCESS_FBINFO(devflags.novga))
4072 hw->MXoptionReg &= ~0x00000100;
4073 if (ACCESS_FBINFO(devflags.nobios))
4074 hw->MXoptionReg &= ~0x40000000;
4075 if (ACCESS_FBINFO(devflags.nopciretry))
4076 hw->MXoptionReg |= 0x20000000;
4077 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
4078 mga_setr(M_SEQ_INDEX, 0x01, 0x20);
4079 mga_outl(M_CTLWTST, 0x00000000);
4080 udelay(200);
4081 mga_outl(M_MACCESS, 0x00008000);
4082 udelay(100);
4083 mga_outl(M_MACCESS, 0x0000C000);
4084 return 0;
4087 static void __init MGA1064_reset(WPMINFO struct matrox_hw_state* hw){
4089 DBG("MGA1064_reset");
4091 ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024;
4092 if (ACCESS_FBINFO(devflags.hwcursor))
4093 ACCESS_FBINFO(video.len_usable) -= 1024;
4094 matroxfb_fastfont_init(MINFO);
4095 MGA1064_ramdac_init(PMINFO hw);
4097 #endif
4099 #ifdef CONFIG_FB_MATROX_G100
4100 /* BIOS environ */
4101 static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
4102 /* G100 wants 0x10, G200 SGRAM does not care... */
4103 #if 0
4104 static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
4105 #endif
4107 static void __init MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p){
4108 int reg;
4109 int selClk;
4110 int clk;
4112 DBG("MGAG100_progPixClock")
4114 outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS |
4115 M1064_XPIXCLKCTRL_PLL_UP);
4116 switch (flags & 3) {
4117 case 0: reg = M1064_XPIXPLLAM; break;
4118 case 1: reg = M1064_XPIXPLLBM; break;
4119 default: reg = M1064_XPIXPLLCM; break;
4121 outDAC1064(PMINFO reg++, m);
4122 outDAC1064(PMINFO reg++, n);
4123 outDAC1064(PMINFO reg, p);
4124 selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
4125 /* there should be flags & 0x03 & case 0/1/else */
4126 /* and we should first select source and after that we should wait for PLL */
4127 /* and we are waiting for PLL with oscilator disabled... Is it right? */
4128 switch (flags & 0x03) {
4129 case 0x00: break;
4130 case 0x01: selClk |= 4; break;
4131 default: selClk |= 0x0C; break;
4133 mga_outb(M_MISC_REG, selClk);
4134 for (clk = 500000; clk; clk--) {
4135 if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
4136 break;
4137 udelay(10);
4139 if (!clk)
4140 printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
4141 selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
4142 switch (flags & 0x0C) {
4143 case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
4144 case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
4145 default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
4147 outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk);
4148 outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
4151 static void __init MGAG100_setPixClock(CPMINFO int flags, int freq){
4152 unsigned int m, n, p;
4154 DBG("MGAG100_setPixClock")
4156 DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
4157 MGAG100_progPixClock(PMINFO flags, m, n, p);
4160 static int __init MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){
4161 static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960,
4162 1024, 1152, 1280, 1600, 1664, 1920,
4163 2048, 0};
4164 u_int32_t reg50;
4165 #if 0
4166 u_int32_t q;
4167 #endif
4169 DBG("MGAG100_preinit")
4171 /* there are some instabilities if in_div > 19 && vco < 61000 */
4172 ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
4173 ACCESS_FBINFO(features.pll.ref_freq) = 27000;
4174 ACCESS_FBINFO(features.pll.feed_div_min) = 7;
4175 ACCESS_FBINFO(features.pll.feed_div_max) = 127;
4176 ACCESS_FBINFO(features.pll.in_div_min) = 1;
4177 ACCESS_FBINFO(features.pll.in_div_max) = 31;
4178 ACCESS_FBINFO(features.pll.post_shift_max) = 3;
4179 ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT;
4180 /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
4181 ACCESS_FBINFO(capable.text) = 1;
4182 ACCESS_FBINFO(capable.vxres) = vxres_g100;
4183 ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
4184 ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
4185 ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG100;
4187 if (ACCESS_FBINFO(devflags.noinit))
4188 return 0;
4189 hw->MXoptionReg &= 0xC0000100;
4190 hw->MXoptionReg |= 0x00078020;
4191 if (ACCESS_FBINFO(devflags.novga))
4192 hw->MXoptionReg &= ~0x00000100;
4193 if (ACCESS_FBINFO(devflags.nobios))
4194 hw->MXoptionReg &= ~0x40000000;
4195 if (ACCESS_FBINFO(devflags.nopciretry))
4196 hw->MXoptionReg |= 0x20000000;
4197 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
4198 pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, &reg50);
4199 reg50 &= ~0x3000;
4200 pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50);
4202 DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333);
4204 if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) {
4205 hw->MXoptionReg |= 0x1080;
4206 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
4207 mga_outl(M_CTLWTST, 0x00000300);
4208 /* mga_outl(M_CTLWTST, 0x03258A31); */
4209 udelay(100);
4210 mga_outb(0x1C05, 0x00);
4211 mga_outb(0x1C05, 0x80);
4212 udelay(100);
4213 mga_outb(0x1C05, 0x40);
4214 mga_outb(0x1C05, 0xC0);
4215 udelay(100);
4216 reg50 &= ~0xFF;
4217 reg50 |= 0x07;
4218 pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50);
4219 /* it should help with G100 */
4220 mga_outb(M_GRAPHICS_INDEX, 6);
4221 mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
4222 mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
4223 mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
4224 mga_writeb(ACCESS_FBINFO(video.vbase), 0x0000, 0xAA);
4225 mga_writeb(ACCESS_FBINFO(video.vbase), 0x0800, 0x55);
4226 mga_writeb(ACCESS_FBINFO(video.vbase), 0x4000, 0x55);
4227 #if 0
4228 if (mga_readb(ACCESS_FBINFO(video.vbase), 0x0000) != 0xAA) {
4229 hw->MXoptionReg &= ~0x1000;
4231 #endif
4232 } else {
4233 hw->MXoptionReg |= 0x00000C00;
4234 if (ACCESS_FBINFO(devflags.sgram))
4235 hw->MXoptionReg |= 0x4000;
4236 mga_outl(M_CTLWTST, 0x042450A1);
4237 mga_outb(0x1E47, 0x00);
4238 mga_outb(0x1E46, 0x00);
4239 udelay(10);
4240 mga_outb(0x1C05, 0x00);
4241 mga_outb(0x1C05, 0x80);
4242 udelay(100);
4243 mga_outw(0x1E44, 0x0108);
4245 hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000;
4246 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
4247 return 0;
4250 static void __init MGAG100_reset(WPMINFO struct matrox_hw_state* hw){
4251 u_int8_t b;
4253 DBG("MGAG100_reset")
4255 ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024;
4256 if (ACCESS_FBINFO(devflags.hwcursor))
4257 ACCESS_FBINFO(video.len_usable) -= 1024;
4258 matroxfb_fastfont_init(MINFO);
4261 #ifdef G100_BROKEN_IBM_82351
4262 u_int32_t d;
4264 find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
4265 pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
4266 if (b == ACCESS_FBINFO(pcidev)->bus->number) {
4267 pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */
4268 pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */
4269 pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */
4270 pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */
4272 #endif
4273 if (!ACCESS_FBINFO(devflags.noinit)) {
4274 if (x7AF4 & 8) {
4275 hw->MXoptionReg |= 0x40;
4276 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
4278 mga_setr(M_EXTVGA_INDEX, 0x06, 0x50);
4281 DAC1064_setmclk(PMINFO hw, DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333);
4282 if (ACCESS_FBINFO(devflags.noinit))
4283 return;
4284 MGAG100_setPixClock(PMINFO 4, 25175);
4285 MGAG100_setPixClock(PMINFO 5, 28322);
4286 if (x7AF4 & 0x10) {
4287 b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1;
4288 outDAC1064(PMINFO M1064_XGENIODATA, b);
4289 b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1;
4290 outDAC1064(PMINFO M1064_XGENIOCTRL, b);
4293 #endif
4295 static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw) {
4296 int i;
4298 DBG("vgaHWrestore")
4300 dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg);
4301 dprintk(KERN_INFO "SEQ regs: ");
4302 for (i = 0; i < 5; i++)
4303 dprintk("%02X:", hw->SEQ[i]);
4304 dprintk("\n");
4305 dprintk(KERN_INFO "GDC regs: ");
4306 for (i = 0; i < 9; i++)
4307 dprintk("%02X:", hw->GCTL[i]);
4308 dprintk("\n");
4309 dprintk(KERN_INFO "CRTC regs: ");
4310 for (i = 0; i < 25; i++)
4311 dprintk("%02X:", hw->CRTC[i]);
4312 dprintk("\n");
4313 dprintk(KERN_INFO "ATTR regs: ");
4314 for (i = 0; i < 21; i++)
4315 dprintk("%02X:", hw->ATTR[i]);
4316 dprintk("\n");
4318 CRITBEGIN
4320 mga_inb(M_ATTR_RESET);
4321 mga_outb(M_ATTR_INDEX, 0);
4322 mga_outb(M_MISC_REG, hw->MiscOutReg);
4323 for (i = 1; i < 5; i++)
4324 mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]);
4325 mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F);
4326 for (i = 0; i < 25; i++)
4327 mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]);
4328 for (i = 0; i < 9; i++)
4329 mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]);
4330 for (i = 0; i < 21; i++) {
4331 mga_inb(M_ATTR_RESET);
4332 mga_outb(M_ATTR_INDEX, i);
4333 mga_outb(M_ATTR_INDEX, hw->ATTR[i]);
4335 mga_outb(M_PALETTE_MASK, 0xFF);
4336 mga_outb(M_DAC_REG, 0x00);
4337 for (i = 0; i < 768; i++)
4338 mga_outb(M_DAC_VAL, hw->DACpal[i]);
4339 mga_inb(M_ATTR_RESET);
4340 mga_outb(M_ATTR_INDEX, 0x20);
4342 CRITEND
4345 static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
4346 unsigned blue, unsigned transp,
4347 struct fb_info *fb_info)
4349 struct display* p;
4350 #ifdef CONFIG_FB_MATROX_MULTIHEAD
4351 struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info;
4352 #endif
4354 DBG("matrox_setcolreg")
4357 * Set a single color register. The values supplied are
4358 * already rounded down to the hardware's capabilities
4359 * (according to the entries in the `var' structure). Return
4360 * != 0 for invalid regno.
4363 if (regno >= ACCESS_FBINFO(curr.cmap_len))
4364 return 1;
4366 ACCESS_FBINFO(palette[regno].red) = red;
4367 ACCESS_FBINFO(palette[regno].green) = green;
4368 ACCESS_FBINFO(palette[regno].blue) = blue;
4369 ACCESS_FBINFO(palette[regno].transp) = transp;
4371 p = ACCESS_FBINFO(currcon_display);
4372 if (p->var.grayscale) {
4373 /* gray = 0.30*R + 0.59*G + 0.11*B */
4374 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
4377 red = CNVT_TOHW(red, p->var.red.length);
4378 green = CNVT_TOHW(green, p->var.green.length);
4379 blue = CNVT_TOHW(blue, p->var.blue.length);
4380 transp = CNVT_TOHW(transp, p->var.transp.length);
4382 switch (p->var.bits_per_pixel) {
4383 #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_VGATEXT)
4384 #ifdef FBCON_HAS_VGATEXT
4385 case 0:
4386 #endif
4387 #ifdef FBCON_HAS_CFB4
4388 case 4:
4389 #endif
4390 #ifdef FBCON_HAS_CFB8
4391 case 8:
4392 #endif
4393 mga_outb(M_DAC_REG, regno);
4394 mga_outb(M_DAC_VAL, red);
4395 mga_outb(M_DAC_VAL, green);
4396 mga_outb(M_DAC_VAL, blue);
4397 break;
4398 #endif
4399 #ifdef FBCON_HAS_CFB16
4400 case 16:
4401 ACCESS_FBINFO(cmap.cfb16[regno]) =
4402 (red << p->var.red.offset) |
4403 (green << p->var.green.offset) |
4404 (blue << p->var.blue.offset) |
4405 (transp << p->var.transp.offset); /* for 1:5:5:5 */
4406 break;
4407 #endif
4408 #ifdef FBCON_HAS_CFB24
4409 case 24:
4410 ACCESS_FBINFO(cmap.cfb24[regno]) =
4411 (red << p->var.red.offset) |
4412 (green << p->var.green.offset) |
4413 (blue << p->var.blue.offset);
4414 break;
4415 #endif
4416 #ifdef FBCON_HAS_CFB32
4417 case 32:
4418 ACCESS_FBINFO(cmap.cfb32[regno]) =
4419 (red << p->var.red.offset) |
4420 (green << p->var.green.offset) |
4421 (blue << p->var.blue.offset) |
4422 (transp << p->var.transp.offset); /* 8:8:8:8 */
4423 break;
4424 #endif
4426 return 0;
4429 static void do_install_cmap(WPMINFO struct display* dsp)
4431 DBG("do_install_cmap")
4433 if (dsp->cmap.len)
4434 fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
4435 else
4436 fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)),
4437 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
4440 #ifdef CONFIG_FB_MATROX_MYSTIQUE
4441 static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
4442 int i;
4444 DBG("MGA1064_restore")
4446 CRITBEGIN
4448 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
4449 mga_outb(M_IEN, 0x00);
4450 mga_outb(M_CACHEFLUSH, 0x00);
4452 CRITEND
4454 DAC1064_restore_1(PMINFO hw, oldhw);
4455 vgaHWrestore(PMINFO hw, oldhw);
4456 for (i = 0; i < 6; i++)
4457 mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
4458 DAC1064_restore_2(PMINFO hw, oldhw, p);
4460 #endif
4462 #ifdef CONFIG_FB_MATROX_G100
4463 static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
4464 int i;
4466 DBG("MGAG100_restore")
4468 CRITBEGIN
4470 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
4471 CRITEND
4473 DAC1064_restore_1(PMINFO hw, oldhw);
4474 vgaHWrestore(PMINFO hw, oldhw);
4475 #ifdef CONFIG_FB_MATROX_32MB
4476 if (ACCESS_FBINFO(devflags.support32MB))
4477 mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
4478 #endif
4479 for (i = 0; i < 6; i++)
4480 mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
4481 DAC1064_restore_2(PMINFO hw, oldhw, p);
4483 #endif
4485 #ifdef CONFIG_FB_MATROX_MILLENIUM
4486 static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
4487 int i;
4489 DBG("Ti3026_restore")
4491 dprintk(KERN_INFO "EXTVGA regs: ");
4492 for (i = 0; i < 6; i++)
4493 dprintk("%02X:", hw->CRTCEXT[i]);
4494 dprintk("\n");
4496 CRITBEGIN
4498 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
4500 CRITEND
4502 vgaHWrestore(PMINFO hw, oldhw);
4504 CRITBEGIN
4506 for (i = 0; i < 6; i++)
4507 mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
4509 for (i = 0; i < 21; i++) {
4510 outTi3026(PMINFO DACseq[i], hw->DACreg[i]);
4512 if (oldhw) {
4513 outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
4514 oldhw->DACclk[0] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
4515 oldhw->DACclk[3] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
4516 outTi3026(PMINFO TVP3026_XPLLADDR, 0x15);
4517 oldhw->DACclk[1] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
4518 oldhw->DACclk[4] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
4519 outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
4520 oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
4521 oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
4523 CRITEND
4524 if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
4525 /* agrhh... setting up PLL is very slow on Millenium... */
4526 /* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
4527 /* Maybe even we should call schedule() ? */
4529 CRITBEGIN
4530 outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
4531 outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
4532 outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
4533 outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0);
4535 outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
4536 for (i = 0; i < 3; i++)
4537 outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]);
4538 /* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */
4539 if (hw->MiscOutReg & 0x08) {
4540 int tmout;
4541 outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
4542 for (tmout = 500000; tmout; --tmout) {
4543 if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
4544 break;
4545 udelay(10);
4548 CRITEND
4550 if (!tmout)
4551 printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
4552 else
4553 dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
4554 CRITBEGIN
4556 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
4557 outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
4558 for (i = 3; i < 6; i++)
4559 outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
4560 CRITEND
4561 if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
4562 int tmout;
4564 CRITBEGIN
4565 outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
4566 for (tmout = 500000; tmout; --tmout) {
4567 if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40)
4568 break;
4569 udelay(10);
4571 CRITEND
4572 if (!tmout)
4573 printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
4574 else
4575 dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
4578 if (p && p->conp) {
4579 if (p->type == FB_TYPE_TEXT) {
4580 matrox_text_createcursor(PMINFO p);
4581 matrox_text_loadfont(PMINFO p);
4582 i = 0;
4583 } else {
4584 matroxfb_ti3026_createcursor(PMINFO p);
4585 i = matroxfb_fastfont_tryset(PMINFO p);
4587 } else
4588 i = 0;
4589 if (i) {
4590 ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc;
4591 ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs;
4592 } else {
4593 ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc;
4594 ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs;
4597 dprintk(KERN_DEBUG "3026DACregs ");
4598 for (i = 0; i < 21; i++) {
4599 dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
4600 if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
4602 dprintk("\n" KERN_DEBUG "DACclk ");
4603 for (i = 0; i < 6; i++)
4604 dprintk("C%02X=%02X ", i, hw->DACclk[i]);
4605 dprintk("\n");
4607 #endif
4609 static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con,
4610 struct fb_info *info)
4612 struct display* p;
4613 DBG("matroxfb_get_fix")
4615 #define minfo ((struct matrox_fb_info*)info)
4617 if (con >= 0)
4618 p = fb_display + con;
4619 else
4620 p = ACCESS_FBINFO(fbcon.disp);
4622 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
4623 strcpy(fix->id,"MATROX");
4625 fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
4626 fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
4627 fix->type = p->type;
4628 fix->type_aux = p->type_aux;
4629 fix->visual = p->visual;
4630 fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
4631 fix->ypanstep = 1;
4632 fix->ywrapstep = 0;
4633 fix->line_length = p->line_length;
4634 fix->mmio_start = ACCESS_FBINFO(mmio.base);
4635 fix->mmio_len = ACCESS_FBINFO(mmio.len);
4636 fix->accel = ACCESS_FBINFO(devflags.accelerator);
4637 return 0;
4638 #undef minfo
4641 static int matroxfb_get_var(struct fb_var_screeninfo *var, int con,
4642 struct fb_info *info)
4644 #define minfo ((struct matrox_fb_info*)info)
4645 DBG("matroxfb_get_var")
4647 if(con < 0)
4648 *var=ACCESS_FBINFO(fbcon.disp)->var;
4649 else
4650 *var=fb_display[con].var;
4651 return 0;
4652 #undef minfo
4655 static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
4656 struct fb_info *info)
4658 #define minfo ((struct matrox_fb_info*)info)
4659 int err;
4660 int visual;
4661 int cmap_len;
4662 unsigned int ydstorg;
4663 struct display* display;
4664 int chgvar;
4666 DBG("matroxfb_set_var")
4668 if (con >= 0)
4669 display = fb_display + con;
4670 else
4671 display = ACCESS_FBINFO(fbcon.disp);
4672 if ((err = matroxfb_decode_var(PMINFO display, var, &visual, &cmap_len, &ydstorg)) != 0)
4673 return err;
4674 switch (var->activate & FB_ACTIVATE_MASK) {
4675 case FB_ACTIVATE_TEST: return 0;
4676 case FB_ACTIVATE_NXTOPEN: /* ?? */
4677 case FB_ACTIVATE_NOW: break; /* continue */
4678 default: return -EINVAL; /* unknown */
4680 if (con >= 0) {
4681 chgvar = ((display->var.xres != var->xres) ||
4682 (display->var.yres != var->yres) ||
4683 (display->var.xres_virtual != var->xres_virtual) ||
4684 (display->var.yres_virtual != var->yres_virtual) ||
4685 (display->var.bits_per_pixel != var->bits_per_pixel) ||
4686 memcmp(&display->var.red, &var->red, sizeof(var->red)) ||
4687 memcmp(&display->var.green, &var->green, sizeof(var->green)) ||
4688 memcmp(&display->var.blue, &var->blue, sizeof(var->blue)));
4689 } else {
4690 chgvar = 0;
4692 display->var = *var;
4693 /* cmap */
4694 display->screen_base = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
4695 display->visual = visual;
4696 display->ypanstep = 1;
4697 display->ywrapstep = 0;
4698 if (var->bits_per_pixel) {
4699 display->type = FB_TYPE_PACKED_PIXELS;
4700 display->type_aux = 0;
4701 display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
4702 } else {
4703 display->type = FB_TYPE_TEXT;
4704 display->type_aux = ACCESS_FBINFO(devflags.text_type_aux);
4705 display->next_line = display->line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep);
4707 display->can_soft_blank = 1;
4708 display->inverse = ACCESS_FBINFO(devflags.inverse);
4709 /* conp, fb_info, vrows, cursor_x, cursor_y, fgcol, bgcol */
4710 /* next_plane, fontdata, _font*, userfont */
4711 initMatrox(PMINFO display); /* dispsw */
4712 /* dispsw, scrollmode, yscroll */
4713 /* fgshift, bgshift, charmask */
4714 if (chgvar && info && info->changevar)
4715 info->changevar(con);
4716 if (con == ACCESS_FBINFO(currcon)) {
4717 unsigned int pos;
4719 ACCESS_FBINFO(curr.cmap_len) = cmap_len;
4720 if (display->type == FB_TYPE_TEXT) {
4721 /* textmode must be in first megabyte, so no ydstorg allowed */
4722 ACCESS_FBINFO(curr.ydstorg.bytes) = 0;
4723 ACCESS_FBINFO(curr.ydstorg.chunks) = 0;
4724 ACCESS_FBINFO(curr.ydstorg.pixels) = 0;
4725 } else {
4726 ydstorg += ACCESS_FBINFO(devflags.ydstorg);
4727 ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg;
4728 ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2);
4729 if (var->bits_per_pixel == 4)
4730 ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg;
4731 else
4732 ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel;
4734 ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel);
4735 if (visual == MX_VISUAL_PSEUDOCOLOR) {
4736 int i;
4738 for (i = 0; i < 16; i++) {
4739 int j;
4741 j = color_table[i];
4742 ACCESS_FBINFO(palette[i].red) = default_red[j];
4743 ACCESS_FBINFO(palette[i].green) = default_grn[j];
4744 ACCESS_FBINFO(palette[i].blue) = default_blu[j];
4748 { struct my_timming mt;
4749 struct matrox_hw_state* hw;
4750 struct matrox_hw_state* ohw;
4752 var2my(var, &mt);
4753 hw = ACCESS_FBINFO(newhw);
4754 ohw = ACCESS_FBINFO(currenthw);
4756 /* MXoptionReg is not set from scratch */
4757 hw->MXoptionReg = ohw->MXoptionReg;
4758 /* DACclk[3]..[5] are not initialized with DAC1064 */
4759 memcpy(hw->DACclk, ohw->DACclk, sizeof(hw->DACclk));
4760 /* others are initialized by init() */
4762 del_timer(&ACCESS_FBINFO(cursor.timer));
4763 ACCESS_FBINFO(cursor.state) = CM_ERASE;
4765 ACCESS_FBINFO(hw_switch->init(PMINFO hw, &mt, display));
4766 if (display->type == FB_TYPE_TEXT) {
4767 if (fontheight(display))
4768 pos = var->yoffset / fontheight(display) * display->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(display)?fontwidth(display):8);
4769 else
4770 pos = 0;
4771 } else {
4772 pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
4773 pos += ACCESS_FBINFO(curr.ydstorg.chunks);
4776 hw->CRTC[0x0D] = pos & 0xFF;
4777 hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
4778 hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
4779 hw->CRTCEXT[8] = pos >> 21;
4780 ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
4781 ACCESS_FBINFO(cursor.redraw) = 1;
4782 ACCESS_FBINFO(currenthw) = hw;
4783 ACCESS_FBINFO(newhw) = ohw;
4784 matrox_cfbX_init(PMINFO display);
4785 do_install_cmap(PMINFO display);
4786 #if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC)
4787 if (console_fb_info == &ACCESS_FBINFO(fbcon)) {
4788 int vmode, cmode;
4790 display_info.width = var->xres;
4791 display_info.height = var->yres;
4792 display_info.depth = var->bits_per_pixel;
4793 display_info.pitch = (var->xres_virtual)*(var->bits_per_pixel)/8;
4794 if (mac_var_to_vmode(var, &vmode, &cmode))
4795 display_info.mode = 0;
4796 else
4797 display_info.mode = vmode;
4798 strcpy(display_info.name, ACCESS_FBINFO(matrox_name));
4799 display_info.fb_address = ACCESS_FBINFO(video.base);
4800 display_info.cmap_adr_address = 0;
4801 display_info.cmap_data_address = 0;
4802 display_info.disp_reg_address = ACCESS_FBINFO(mmio.base);
4804 #endif /* CONFIG_FB_OF && CONFIG_FB_COMPAT_XPMAC */
4807 return 0;
4808 #undef minfo
4811 static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green,
4812 unsigned *blue, unsigned *transp,
4813 struct fb_info *info)
4816 DBG("matrox_getcolreg")
4818 #define minfo ((struct matrox_fb_info*)info)
4820 * Read a single color register and split it into colors/transparent.
4821 * Return != 0 for invalid regno.
4824 if (regno >= ACCESS_FBINFO(curr.cmap_len))
4825 return 1;
4827 *red = ACCESS_FBINFO(palette[regno].red);
4828 *green = ACCESS_FBINFO(palette[regno].green);
4829 *blue = ACCESS_FBINFO(palette[regno].blue);
4830 *transp = ACCESS_FBINFO(palette[regno].transp);
4831 return 0;
4832 #undef minfo
4835 static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
4836 struct fb_info *info)
4838 #define minfo ((struct matrox_fb_info*)info)
4839 struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp)
4840 : fb_display + con;
4842 DBG("matroxfb_get_cmap")
4844 if (con == ACCESS_FBINFO(currcon)) /* current console? */
4845 return fb_get_cmap(cmap, kspc, matrox_getcolreg, info);
4846 else if (dsp->cmap.len) /* non default colormap? */
4847 fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
4848 else
4849 fb_copy_cmap(fb_default_cmap(matroxfb_get_cmap_len(&dsp->var)),
4850 cmap, kspc ? 0 : 2);
4851 return 0;
4852 #undef minfo
4855 static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
4856 struct fb_info *info)
4858 unsigned int cmap_len;
4859 struct display* dsp = (con < 0) ? info->disp : (fb_display + con);
4860 #define minfo ((struct matrox_fb_info*)info)
4862 DBG("matroxfb_set_cmap")
4864 cmap_len = matroxfb_get_cmap_len(&dsp->var);
4865 if (dsp->cmap.len != cmap_len) {
4866 int err;
4868 err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0);
4869 if (err)
4870 return err;
4872 if (con == ACCESS_FBINFO(currcon)) { /* current console? */
4873 return fb_set_cmap(cmap, kspc, matrox_setcolreg, info);
4874 } else
4875 fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
4876 return 0;
4877 #undef minfo
4880 static int matroxfb_ioctl(struct inode *inode, struct file *file,
4881 unsigned int cmd, unsigned long arg, int con,
4882 struct fb_info *info)
4885 DBG("matroxfb_ioctl")
4887 return -EINVAL;
4890 static struct fb_ops matroxfb_ops = {
4891 matroxfb_open,
4892 matroxfb_release,
4893 matroxfb_get_fix,
4894 matroxfb_get_var,
4895 matroxfb_set_var,
4896 matroxfb_get_cmap,
4897 matroxfb_set_cmap,
4898 matroxfb_pan_display,
4899 matroxfb_ioctl,
4900 NULL /* mmap */
4903 static int matroxfb_switch(int con, struct fb_info *info)
4905 #define minfo ((struct matrox_fb_info*)info)
4906 struct fb_cmap* cmap;
4908 DBG("matroxfb_switch");
4910 if (ACCESS_FBINFO(currcon) >= 0) {
4911 /* Do we have to save the colormap? */
4912 cmap = &(ACCESS_FBINFO(currcon_display)->cmap);
4913 dprintk(KERN_DEBUG "switch1: con = %d, cmap.len = %d\n", ACCESS_FBINFO(currcon), cmap->len);
4915 if (cmap->len) {
4916 dprintk(KERN_DEBUG "switch1a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
4917 fb_get_cmap(cmap, 1, matrox_getcolreg, info);
4918 #ifdef DEBUG
4919 if (cmap->red) {
4920 dprintk(KERN_DEBUG "switch1r: %X\n", cmap->red[0]);
4922 #endif
4925 ACCESS_FBINFO(currcon) = con;
4926 ACCESS_FBINFO(currcon_display) = fb_display + con;
4927 fb_display[con].var.activate = FB_ACTIVATE_NOW;
4928 #ifdef DEBUG
4929 cmap = &fb_display[con].cmap;
4930 dprintk(KERN_DEBUG "switch2: con = %d, cmap.len = %d\n", con, cmap->len);
4931 dprintk(KERN_DEBUG "switch2a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
4932 if (fb_display[con].cmap.red) {
4933 dprintk(KERN_DEBUG "switch2r: %X\n", cmap->red[0]);
4935 #endif
4936 matroxfb_set_var(&fb_display[con].var, con, info);
4937 #ifdef DEBUG
4938 dprintk(KERN_DEBUG "switch3: con = %d, cmap.len = %d\n", con, cmap->len);
4939 dprintk(KERN_DEBUG "switch3a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
4940 if (fb_display[con].cmap.red) {
4941 dprintk(KERN_DEBUG "switch3r: %X\n", cmap->red[0]);
4943 #endif
4944 return 0;
4945 #undef minfo
4948 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
4950 static void matroxfb_blank(int blank, struct fb_info *info)
4952 #define minfo ((struct matrox_fb_info*)info)
4953 int seq;
4954 int crtc;
4956 DBG("matroxfb_blank")
4958 switch (blank) {
4959 case 1: seq = 0x20; crtc = 0x00; break; /* works ??? */
4960 case 2: seq = 0x20; crtc = 0x10; break;
4961 case 3: seq = 0x20; crtc = 0x20; break;
4962 case 4: seq = 0x20; crtc = 0x30; break;
4963 default: seq = 0x00; crtc = 0x00; break;
4966 CRITBEGIN
4968 mga_outb(M_SEQ_INDEX, 1);
4969 mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
4970 mga_outb(M_EXTVGA_INDEX, 1);
4971 mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
4973 CRITEND
4975 #undef minfo
4978 #define RSResolution(X) ((X) & 0x0F)
4979 #define RS640x400 1
4980 #define RS640x480 2
4981 #define RS800x600 3
4982 #define RS1024x768 4
4983 #define RS1280x1024 5
4984 #define RS1600x1200 6
4985 #define RS768x576 7
4986 #define RS960x720 8
4987 #define RS1152x864 9
4988 #define RS1408x1056 10
4989 #define RS640x350 11
4990 #define RS1056x344 12 /* 132 x 43 text */
4991 #define RS1056x400 13 /* 132 x 50 text */
4992 #define RS1056x480 14 /* 132 x 60 text */
4993 #define RSNoxNo 15
4994 /* 10-FF */
4995 static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
4996 { 640, 400, 48, 16, 39, 8, 96, 2, 70 },
4997 { 640, 480, 48, 16, 33, 10, 96, 2, 60 },
4998 { 800, 600, 144, 24, 28, 8, 112, 6, 60 },
4999 { 1024, 768, 160, 32, 30, 4, 128, 4, 60 },
5000 { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 },
5001 { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 },
5002 { 768, 576, 144, 16, 28, 6, 112, 4, 60 },
5003 { 960, 720, 144, 24, 28, 8, 112, 4, 60 },
5004 { 1152, 864, 192, 32, 30, 4, 128, 4, 60 },
5005 { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 },
5006 { 640, 350, 48, 16, 39, 8, 96, 2, 70 },
5007 { 1056, 344, 96, 24, 59, 44, 160, 2, 70 },
5008 { 1056, 400, 96, 24, 39, 8, 160, 2, 70 },
5009 { 1056, 480, 96, 24, 36, 12, 160, 3, 60 },
5010 { 0, 0, ~0, ~0, ~0, ~0, 0, 0, 0 }
5013 #define RSDepth(X) (((X) >> 8) & 0x0F)
5014 #define RS8bpp 0x1
5015 #define RS15bpp 0x2
5016 #define RS16bpp 0x3
5017 #define RS32bpp 0x4
5018 #define RS4bpp 0x5
5019 #define RS24bpp 0x6
5020 #define RSText 0x7
5021 #define RSText8 0x8
5022 /* 9-F */
5023 static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] __initdata = {
5024 { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 },
5025 { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 },
5026 { { 11, 5, 0}, { 6, 5, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 },
5027 { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 },
5028 { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 },
5029 { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 },
5030 { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */
5031 { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */
5034 #define RSCreate(X,Y) ((X) | ((Y) << 8))
5035 static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = {
5036 /* default must be first */
5037 #ifdef FBCON_HAS_CFB8
5038 { ~0, RSCreate(RSNoxNo, RS8bpp ) },
5039 { 0x101, RSCreate(RS640x480, RS8bpp ) },
5040 { 0x100, RSCreate(RS640x400, RS8bpp ) },
5041 { 0x180, RSCreate(RS768x576, RS8bpp ) },
5042 { 0x103, RSCreate(RS800x600, RS8bpp ) },
5043 { 0x188, RSCreate(RS960x720, RS8bpp ) },
5044 { 0x105, RSCreate(RS1024x768, RS8bpp ) },
5045 { 0x190, RSCreate(RS1152x864, RS8bpp ) },
5046 { 0x107, RSCreate(RS1280x1024, RS8bpp ) },
5047 { 0x198, RSCreate(RS1408x1056, RS8bpp ) },
5048 { 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
5049 #endif
5050 #ifdef FBCON_HAS_CFB16
5051 { ~0, RSCreate(RSNoxNo, RS15bpp) },
5052 { 0x110, RSCreate(RS640x480, RS15bpp) },
5053 { 0x181, RSCreate(RS768x576, RS15bpp) },
5054 { 0x113, RSCreate(RS800x600, RS15bpp) },
5055 { 0x189, RSCreate(RS960x720, RS15bpp) },
5056 { 0x116, RSCreate(RS1024x768, RS15bpp) },
5057 { 0x191, RSCreate(RS1152x864, RS15bpp) },
5058 { 0x119, RSCreate(RS1280x1024, RS15bpp) },
5059 { 0x199, RSCreate(RS1408x1056, RS15bpp) },
5060 { 0x11D, RSCreate(RS1600x1200, RS15bpp) },
5061 { 0x111, RSCreate(RS640x480, RS16bpp) },
5062 { 0x182, RSCreate(RS768x576, RS16bpp) },
5063 { 0x114, RSCreate(RS800x600, RS16bpp) },
5064 { 0x18A, RSCreate(RS960x720, RS16bpp) },
5065 { 0x117, RSCreate(RS1024x768, RS16bpp) },
5066 { 0x192, RSCreate(RS1152x864, RS16bpp) },
5067 { 0x11A, RSCreate(RS1280x1024, RS16bpp) },
5068 { 0x19A, RSCreate(RS1408x1056, RS16bpp) },
5069 { 0x11E, RSCreate(RS1600x1200, RS16bpp) },
5070 #endif
5071 #ifdef FBCON_HAS_CFB24
5072 { ~0, RSCreate(RSNoxNo, RS24bpp) },
5073 { 0x1B2, RSCreate(RS640x480, RS24bpp) },
5074 { 0x184, RSCreate(RS768x576, RS24bpp) },
5075 { 0x1B5, RSCreate(RS800x600, RS24bpp) },
5076 { 0x18C, RSCreate(RS960x720, RS24bpp) },
5077 { 0x1B8, RSCreate(RS1024x768, RS24bpp) },
5078 { 0x194, RSCreate(RS1152x864, RS24bpp) },
5079 { 0x1BB, RSCreate(RS1280x1024, RS24bpp) },
5080 { 0x19C, RSCreate(RS1408x1056, RS24bpp) },
5081 { 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
5082 #endif
5083 #ifdef FBCON_HAS_CFB32
5084 { ~0, RSCreate(RSNoxNo, RS32bpp) },
5085 { 0x112, RSCreate(RS640x480, RS32bpp) },
5086 { 0x183, RSCreate(RS768x576, RS32bpp) },
5087 { 0x115, RSCreate(RS800x600, RS32bpp) },
5088 { 0x18B, RSCreate(RS960x720, RS32bpp) },
5089 { 0x118, RSCreate(RS1024x768, RS32bpp) },
5090 { 0x193, RSCreate(RS1152x864, RS32bpp) },
5091 { 0x11B, RSCreate(RS1280x1024, RS32bpp) },
5092 { 0x19B, RSCreate(RS1408x1056, RS32bpp) },
5093 { 0x11F, RSCreate(RS1600x1200, RS32bpp) },
5094 #endif
5095 #ifdef FBCON_HAS_VGATEXT
5096 { ~0, RSCreate(RSNoxNo, RSText) },
5097 { 0x002, RSCreate(RS640x400, RSText) }, /* 80x25 */
5098 { 0x003, RSCreate(RS640x400, RSText) }, /* 80x25 */
5099 { 0x007, RSCreate(RS640x400, RSText) }, /* 80x25 */
5100 { 0x1C0, RSCreate(RS640x400, RSText8) }, /* 80x50 */
5101 { 0x108, RSCreate(RS640x480, RSText8) }, /* 80x60 */
5102 { 0x109, RSCreate(RS1056x400, RSText) }, /* 132x25 */
5103 { 0x10A, RSCreate(RS1056x344, RSText8) }, /* 132x43 */
5104 { 0x10B, RSCreate(RS1056x400, RSText8) }, /* 132x50 */
5105 { 0x10C, RSCreate(RS1056x480, RSText8) }, /* 132x60 */
5106 #endif
5107 #ifdef FBCON_HAS_CFB4
5108 { ~0, RSCreate(RSNoxNo, RS4bpp ) },
5109 { 0x010, RSCreate(RS640x350, RS4bpp ) },
5110 { 0x012, RSCreate(RS640x480, RS4bpp ) },
5111 { 0x102, RSCreate(RS800x600, RS4bpp ) },
5112 { 0x104, RSCreate(RS1024x768, RS4bpp ) },
5113 { 0x106, RSCreate(RS1280x1024, RS4bpp ) },
5114 #endif
5115 { 0, 0 }};
5117 /* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
5118 static unsigned int mem = 0; /* "matrox:mem:xxxxxM" */
5119 static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */
5120 static int inv24 = 0; /* "matrox:inv24" */
5121 static int cross4MB = -1; /* "matrox:cross4MB" */
5122 static int disabled = 0; /* "matrox:disabled" */
5123 static int noaccel = 0; /* "matrox:noaccel" */
5124 static int nopan = 0; /* "matrox:nopan" */
5125 static int no_pci_retry = 0; /* "matrox:nopciretry" */
5126 static int novga = 0; /* "matrox:novga" */
5127 static int nobios = 0; /* "matrox:nobios" */
5128 static int noinit = 1; /* "matrox:init" */
5129 static int inverse = 0; /* "matrox:inverse" */
5130 static int hwcursor = 1; /* "matrox:nohwcursor" */
5131 static int blink = 1; /* "matrox:noblink" */
5132 static int sgram = 0; /* "matrox:sgram" */
5133 #ifdef CONFIG_MTRR
5134 static int mtrr = 1; /* "matrox:nomtrr" */
5135 #endif
5136 static int grayscale = 0; /* "matrox:grayscale" */
5137 static unsigned int fastfont = 0; /* "matrox:fastfont:xxxxx" */
5138 static int dev = -1; /* "matrox:dev:xxxxx" */
5139 static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */
5140 static int depth = -1; /* "matrox:depth:xxxxx" */
5141 static unsigned int xres = 0; /* "matrox:xres:xxxxx" */
5142 static unsigned int yres = 0; /* "matrox:yres:xxxxx" */
5143 static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */
5144 static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */
5145 static unsigned int vslen = 0; /* "matrox:vslen:xxxxx" */
5146 static unsigned int left = ~0; /* "matrox:left:xxxxx" */
5147 static unsigned int right = ~0; /* "matrox:right:xxxxx" */
5148 static unsigned int hslen = 0; /* "matrox:hslen:xxxxx" */
5149 static unsigned int pixclock = 0; /* "matrox:pixclock:xxxxx" */
5150 static int sync = -1; /* "matrox:sync:xxxxx" */
5151 static unsigned int fv = 0; /* "matrox:fv:xxxxx" */
5152 static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */
5153 static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */
5154 static char fontname[64]; /* "matrox:font:xxxxx" */
5156 #ifndef MODULE
5157 static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */
5158 #endif
5160 #ifndef MODULE
5161 int __init matroxfb_setup(char *options) {
5162 char *this_opt;
5164 DBG("matroxfb_setup")
5166 fontname[0] = '\0';
5168 if (!options || !*options)
5169 return 0;
5171 for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
5172 if (!*this_opt) continue;
5174 dprintk("matroxfb_setup: option %s\n", this_opt);
5176 if (!strncmp(this_opt, "dev:", 4))
5177 dev = simple_strtoul(this_opt+4, NULL, 0);
5178 else if (!strncmp(this_opt, "depth:", 6)) {
5179 switch (simple_strtoul(this_opt+6, NULL, 0)) {
5180 case 0: depth = RSText; break;
5181 case 4: depth = RS4bpp; break;
5182 case 8: depth = RS8bpp; break;
5183 case 15:depth = RS15bpp; break;
5184 case 16:depth = RS16bpp; break;
5185 case 24:depth = RS24bpp; break;
5186 case 32:depth = RS32bpp; break;
5187 default:
5188 printk(KERN_ERR "matroxfb: unsupported color depth\n");
5190 } else if (!strncmp(this_opt, "xres:", 5))
5191 xres = simple_strtoul(this_opt+5, NULL, 0);
5192 else if (!strncmp(this_opt, "yres:", 5))
5193 yres = simple_strtoul(this_opt+5, NULL, 0);
5194 else if (!strncmp(this_opt, "vslen:", 6))
5195 vslen = simple_strtoul(this_opt+6, NULL, 0);
5196 else if (!strncmp(this_opt, "hslen:", 6))
5197 hslen = simple_strtoul(this_opt+6, NULL, 0);
5198 else if (!strncmp(this_opt, "left:", 5))
5199 left = simple_strtoul(this_opt+5, NULL, 0);
5200 else if (!strncmp(this_opt, "right:", 6))
5201 right = simple_strtoul(this_opt+6, NULL, 0);
5202 else if (!strncmp(this_opt, "upper:", 6))
5203 upper = simple_strtoul(this_opt+6, NULL, 0);
5204 else if (!strncmp(this_opt, "lower:", 6))
5205 lower = simple_strtoul(this_opt+6, NULL, 0);
5206 else if (!strncmp(this_opt, "pixclock:", 9))
5207 pixclock = simple_strtoul(this_opt+9, NULL, 0);
5208 else if (!strncmp(this_opt, "sync:", 5))
5209 sync = simple_strtoul(this_opt+5, NULL, 0);
5210 else if (!strncmp(this_opt, "vesa:", 5))
5211 vesa = simple_strtoul(this_opt+5, NULL, 0);
5212 else if (!strncmp(this_opt, "font:", 5))
5213 strncpy(fontname, this_opt+5, sizeof(fontname)-1);
5214 else if (!strncmp(this_opt, "maxclk:", 7))
5215 maxclk = simple_strtoul(this_opt+7, NULL, 0);
5216 else if (!strncmp(this_opt, "fh:", 3))
5217 fh = simple_strtoul(this_opt+3, NULL, 0);
5218 else if (!strncmp(this_opt, "fv:", 3))
5219 fv = simple_strtoul(this_opt+3, NULL, 0);
5220 else if (!strncmp(this_opt, "mem:", 4))
5221 mem = simple_strtoul(this_opt+4, NULL, 0);
5222 else if (!strncmp(this_opt, "mode:", 5))
5223 strncpy(videomode, this_opt+5, sizeof(videomode)-1);
5224 #ifdef CONFIG_FB_OF
5225 else if (!strncmp(this_opt, "vmode:", 6)) {
5226 unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
5227 if (vmode > 0 && vmode <= VMODE_MAX)
5228 default_vmode = vmode;
5229 } else if (!strncmp(this_opt, "cmode:", 6)) {
5230 unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
5231 switch (cmode) {
5232 case 0:
5233 case 8:
5234 default_cmode = CMODE_8;
5235 break;
5236 case 15:
5237 case 16:
5238 default_cmode = CMODE_16;
5239 break;
5240 case 24:
5241 case 32:
5242 default_cmode = CMODE_32;
5243 break;
5246 #endif
5247 else if (!strncmp(this_opt, "fastfont:", 9))
5248 fastfont = simple_strtoul(this_opt+9, NULL, 0);
5249 else if (!strcmp(this_opt, "nofastfont")) /* fastfont:N and nofastfont (nofastfont = fastfont:0) */
5250 fastfont = 0;
5251 else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */
5252 disabled = 1;
5253 else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */
5254 disabled = 0;
5255 else if (!strcmp(this_opt, "sgram")) /* nosgram == sdram */
5256 sgram = 1;
5257 else if (!strcmp(this_opt, "sdram"))
5258 sgram = 0;
5259 else {
5260 int value = 1;
5262 if (!strncmp(this_opt, "no", 2)) {
5263 value = 0;
5264 this_opt += 2;
5266 if (! strcmp(this_opt, "inverse"))
5267 inverse = value;
5268 else if (!strcmp(this_opt, "accel"))
5269 noaccel = !value;
5270 else if (!strcmp(this_opt, "pan"))
5271 nopan = !value;
5272 else if (!strcmp(this_opt, "pciretry"))
5273 no_pci_retry = !value;
5274 else if (!strcmp(this_opt, "vga"))
5275 novga = !value;
5276 else if (!strcmp(this_opt, "bios"))
5277 nobios = !value;
5278 else if (!strcmp(this_opt, "init"))
5279 noinit = !value;
5280 #ifdef CONFIG_MTRR
5281 else if (!strcmp(this_opt, "mtrr"))
5282 mtrr = value;
5283 #endif
5284 else if (!strcmp(this_opt, "inv24"))
5285 inv24 = value;
5286 else if (!strcmp(this_opt, "cross4MB"))
5287 cross4MB = value;
5288 else if (!strcmp(this_opt, "hwcursor"))
5289 hwcursor = value;
5290 else if (!strcmp(this_opt, "blink"))
5291 blink = value;
5292 else if (!strcmp(this_opt, "grayscale"))
5293 grayscale = value;
5294 else {
5295 strncpy(videomode, this_opt, sizeof(videomode)-1);
5299 return 0;
5301 #endif /* !MODULE */
5303 static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize){
5304 vaddr_t vm;
5305 unsigned int offs;
5306 unsigned int offs2;
5307 unsigned char store;
5308 unsigned char bytes[32];
5309 unsigned char* tmp;
5310 unsigned long cbase;
5311 unsigned long mbase;
5312 unsigned int clen;
5313 unsigned int mlen;
5315 DBG("matroxfb_getmemory")
5317 vm = ACCESS_FBINFO(video.vbase);
5318 maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */
5319 /* at least 2MB */
5320 if (maxSize < 0x0200000) return 0;
5321 if (maxSize > 0x2000000) maxSize = 0x2000000;
5323 mga_outb(M_EXTVGA_INDEX, 0x03);
5324 mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
5326 store = mga_readb(vm, 0x1234);
5327 tmp = bytes;
5328 for (offs = 0x100000; offs < maxSize; offs += 0x200000)
5329 *tmp++ = mga_readb(vm, offs);
5330 for (offs = 0x100000; offs < maxSize; offs += 0x200000)
5331 mga_writeb(vm, offs, 0x02);
5332 if (ACCESS_FBINFO(features.accel.has_cacheflush))
5333 mga_outb(M_CACHEFLUSH, 0x00);
5334 else
5335 mga_writeb(vm, 0x1234, 0x99);
5336 cbase = mbase = 0;
5337 clen = mlen = 0;
5338 for (offs = 0x100000; offs < maxSize; offs += 0x200000) {
5339 if (mga_readb(vm, offs) != 0x02)
5340 continue;
5341 mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02);
5342 if (mga_readb(vm, offs))
5343 continue;
5344 if (offs - 0x100000 == cbase + clen) {
5345 clen += 0x200000;
5346 } else {
5347 cbase = offs - 0x100000;
5348 clen = 0x200000;
5350 if ((clen > mlen)
5351 #ifndef MATROX_2MB_WITH_4MB_ADDON
5352 && (cbase == 0)
5353 #endif
5355 mbase = cbase;
5356 mlen = clen;
5359 tmp = bytes;
5360 for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000)
5361 mga_writeb(vm, offs2, *tmp++);
5362 mga_writeb(vm, 0x1234, store);
5364 mga_outb(M_EXTVGA_INDEX, 0x03);
5365 mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80);
5367 *realOffset = mbase;
5368 *realSize = mlen;
5369 #ifdef CONFIG_FB_MATROX_MILLENIUM
5370 ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || (mbase & 0x3FFFFF) || (mlen & 0x3FFFFF));
5371 #endif
5372 return 1;
5375 #ifdef CONFIG_FB_MATROX_MILLENIUM
5376 static int __init Ti3026_preinit(WPMINFO struct matrox_hw_state* hw){
5377 static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960,
5378 1024, 1152, 1280, 1600, 1664, 1920,
5379 2048, 0};
5380 static const int vxres_mill1[] = { 640, 768, 800, 960,
5381 1024, 1152, 1280, 1600, 1920,
5382 2048, 0};
5384 DBG("Ti3026_preinit")
5386 ACCESS_FBINFO(millenium) = 1;
5387 ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL);
5388 ACCESS_FBINFO(capable.cfb4) = 1;
5389 ACCESS_FBINFO(capable.text) = 1; /* isMilleniumII(MINFO); */
5390 ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
5391 ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor;
5393 if (ACCESS_FBINFO(devflags.noinit))
5394 return 0;
5395 /* preserve VGA I/O, BIOS and PPC */
5396 hw->MXoptionReg &= 0xC0000100;
5397 hw->MXoptionReg |= 0x002C0000;
5398 if (ACCESS_FBINFO(devflags.novga))
5399 hw->MXoptionReg &= ~0x00000100;
5400 if (ACCESS_FBINFO(devflags.nobios))
5401 hw->MXoptionReg &= ~0x40000000;
5402 if (ACCESS_FBINFO(devflags.nopciretry))
5403 hw->MXoptionReg |= 0x20000000;
5404 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
5406 ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV);
5408 outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
5409 outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
5410 outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
5412 outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
5413 outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00);
5414 outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
5416 mga_outb(M_MISC_REG, 0x67);
5418 outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
5420 mga_outl(M_RESET, 1);
5421 udelay(250);
5422 mga_outl(M_RESET, 0);
5423 udelay(250);
5424 mga_outl(M_MACCESS, 0x00008000);
5425 udelay(10);
5426 return 0;
5429 static void __init Ti3026_reset(WPMINFO struct matrox_hw_state* hw){
5431 DBG("Ti3026_reset")
5433 matroxfb_fastfont_init(MINFO);
5435 ti3026_ramdac_init(PMINFO hw);
5437 #endif
5439 #ifdef CONFIG_FB_MATROX_MILLENIUM
5440 static struct matrox_switch matrox_millenium = {
5441 Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore
5443 #endif
5445 #ifdef CONFIG_FB_MATROX_MYSTIQUE
5446 static struct matrox_switch matrox_mystique = {
5447 MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore
5449 #endif
5451 #ifdef CONFIG_FB_MATROX_G100
5452 static struct matrox_switch matrox_G100 = {
5453 MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore
5455 #endif
5457 struct video_board {
5458 int maxvram;
5459 int maxdisplayable;
5460 int accelID;
5461 struct matrox_switch* lowlevel;
5463 #ifdef CONFIG_FB_MATROX_MILLENIUM
5464 static struct video_board vbMillenium __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millenium};
5465 static struct video_board vbMillenium2 __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W, &matrox_millenium};
5466 static struct video_board vbMillenium2A __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millenium};
5467 #endif /* CONFIG_FB_MATROX_MILLENIUM */
5468 #ifdef CONFIG_FB_MATROX_MYSTIQUE
5469 static struct video_board vbMystique __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique};
5470 #endif /* CONFIG_FB_MATROX_MYSTIQUE */
5471 #ifdef CONFIG_FB_MATROX_G100
5472 static struct video_board vbG100 __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100};
5473 static struct video_board vbG200 __initdata = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100};
5474 #ifdef CONFIG_FB_MATROX_32MB
5475 /* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for
5476 whole 32MB */
5477 static struct video_board vbG400 __initdata = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100};
5478 #else
5479 static struct video_board vbG400 __initdata = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100};
5480 #endif
5481 #endif
5483 #define DEVF_VIDEO64BIT 0x01
5484 #define DEVF_SWAPS 0x02
5485 #define DEVF_MILLENIUM 0x04
5486 #define DEVF_MILLENIUM2 0x08
5487 #define DEVF_CROSS4MB 0x10
5488 #define DEVF_TEXT4B 0x20
5489 #define DEVF_DDC_8_2 0x40
5490 #define DEVF_DMA 0x80
5491 #define DEVF_SUPPORT32MB 0x100
5492 #define DEVF_ANY_VXRES 0x200
5494 #define DEVF_G100 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2) /* no doc, no vxres... */
5495 #define DEVF_G200 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES)
5496 #define DEVF_G400 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES | DEVF_SUPPORT32MB)
5498 static struct board {
5499 unsigned short vendor, device, rev, svid, sid;
5500 unsigned int flags;
5501 unsigned int maxclk;
5502 struct video_board* base;
5503 const char* name;
5504 } dev_list[] __initdata = {
5505 #ifdef CONFIG_FB_MATROX_MILLENIUM
5506 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF,
5507 0, 0,
5508 DEVF_MILLENIUM | DEVF_TEXT4B,
5509 230000,
5510 &vbMillenium,
5511 "Millennium (PCI)"},
5512 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF,
5513 0, 0,
5514 DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS,
5515 220000,
5516 &vbMillenium2,
5517 "Millennium II (PCI)"},
5518 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF,
5519 0, 0,
5520 DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS,
5521 250000,
5522 &vbMillenium2A,
5523 "Millennium II (AGP)"},
5524 #endif
5525 #ifdef CONFIG_FB_MATROX_MYSTIQUE
5526 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02,
5527 0, 0,
5528 DEVF_VIDEO64BIT,
5529 180000,
5530 &vbMystique,
5531 "Mystique (PCI)"},
5532 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF,
5533 0, 0,
5534 DEVF_VIDEO64BIT | DEVF_SWAPS,
5535 220000,
5536 &vbMystique,
5537 "Mystique 220 (PCI)"},
5538 #endif
5539 #ifdef CONFIG_FB_MATROX_G100
5540 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF,
5541 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_PCI,
5542 DEVF_G100,
5543 230000,
5544 &vbG100,
5545 "MGA-G100 (PCI)"},
5546 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF,
5547 0, 0,
5548 DEVF_G100,
5549 230000,
5550 &vbG100,
5551 "unknown G100 (PCI)"},
5552 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
5553 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC,
5554 DEVF_G100,
5555 230000,
5556 &vbG100,
5557 "MGA-G100 (AGP)"},
5558 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
5559 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_AGP,
5560 DEVF_G100,
5561 230000,
5562 &vbG100,
5563 "MGA-G100 (AGP)"},
5564 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
5565 PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G100_AGP,
5566 DEVF_G100,
5567 230000,
5568 &vbG100,
5569 "MGA-G100 (AGP)"},
5570 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
5571 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP,
5572 DEVF_G100,
5573 230000,
5574 &vbG100,
5575 "Productiva G100 (AGP)"},
5576 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
5577 0, 0,
5578 DEVF_G100,
5579 230000,
5580 &vbG100,
5581 "unknown G100 (AGP)"},
5582 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF,
5583 0, 0,
5584 DEVF_G200,
5585 250000,
5586 &vbG200,
5587 "unknown G200 (PCI)"},
5588 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
5589 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC,
5590 DEVF_G200,
5591 220000,
5592 &vbG200,
5593 "MGA-G200 (AGP)"},
5594 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
5595 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
5596 DEVF_G200,
5597 230000,
5598 &vbG200,
5599 "Mystique G200 (AGP)"},
5600 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
5601 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
5602 DEVF_G200,
5603 250000,
5604 &vbG200,
5605 "Millennium G200 (AGP)"},
5606 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
5607 PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP,
5608 DEVF_G200,
5609 230000,
5610 &vbG200,
5611 "Marvel G200 (AGP)"},
5612 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
5613 PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP,
5614 DEVF_G200,
5615 230000,
5616 &vbG200,
5617 "MGA-G200 (AGP)"},
5618 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
5619 0, 0,
5620 DEVF_G200,
5621 230000,
5622 &vbG200,
5623 "unknown G200 (AGP)"},
5624 {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF,
5625 0, 0,
5626 DEVF_G400,
5627 360000,
5628 &vbG400,
5629 "unknown G400 (AGP)"},
5630 #endif
5631 {0, 0, 0xFF,
5632 0, 0,
5635 NULL,
5636 NULL}};
5638 #ifndef MODULE
5639 /* it cannot be static const struct due to __initdata
5640 marker */
5641 static struct fb_videomode defaultmode __initdata = {
5642 /* 640x480 @ 60Hz, 31.5 kHz */
5643 NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
5644 0, FB_VMODE_NONINTERLACED
5646 #endif /* !MODULE */
5648 static int __init initMatrox2(WPMINFO struct display* d, struct board* b){
5649 unsigned long ctrlptr_phys = 0;
5650 unsigned long video_base_phys = 0;
5651 unsigned int memsize;
5652 struct matrox_hw_state* hw = ACCESS_FBINFO(currenthw);
5654 DBG("initMatrox2")
5656 /* set default values... */
5657 vesafb_defined.accel_flags = FB_ACCELF_TEXT;
5659 ACCESS_FBINFO(hw_switch) = b->base->lowlevel;
5660 ACCESS_FBINFO(devflags.accelerator) = b->base->accelID;
5661 ACCESS_FBINFO(max_pixel_clock) = b->maxclk;
5663 printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
5664 ACCESS_FBINFO(capable.plnwt) = 1;
5665 ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
5666 if (b->flags & DEVF_TEXT4B) {
5667 ACCESS_FBINFO(devflags.vgastep) = 4;
5668 ACCESS_FBINFO(devflags.textmode) = 4;
5669 ACCESS_FBINFO(devflags.vgastepdisp) = 16;
5670 ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
5671 } else {
5672 ACCESS_FBINFO(devflags.vgastep) = 8;
5673 ACCESS_FBINFO(devflags.textmode) = 1;
5674 ACCESS_FBINFO(devflags.vgastepdisp) = 64;
5675 ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
5677 #ifdef CONFIG_FB_MATROX_32MB
5678 ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
5679 #endif
5680 ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
5681 ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
5682 ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
5684 if (ACCESS_FBINFO(capable.cross4MB) < 0)
5685 ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB;
5686 if (b->flags & DEVF_SWAPS) {
5687 ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
5688 video_base_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
5689 } else {
5690 ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
5691 video_base_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
5693 if (!ctrlptr_phys) {
5694 printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
5695 return -EINVAL;
5697 if (!video_base_phys) {
5698 printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n");
5699 return -EINVAL;
5701 if (mga_ioremap(ctrlptr_phys, 16384, MGA_IOREMAP_MMIO, &ACCESS_FBINFO(mmio.vbase))) {
5702 printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys);
5703 return -ENOMEM;
5705 ACCESS_FBINFO(mmio.base) = ctrlptr_phys;
5706 ACCESS_FBINFO(mmio.len) = 16384;
5707 memsize = b->base->maxvram;
5708 /* convert mem (autodetect k, M) */
5709 if (mem < 1024) mem *= 1024;
5710 if (mem < 0x00100000) mem *= 1024;
5712 if (mem && (mem < memsize))
5713 memsize = mem;
5714 ACCESS_FBINFO(video.base) = video_base_phys;
5715 if (mga_ioremap(video_base_phys, memsize, MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) {
5716 printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
5717 video_base_phys, memsize);
5718 mga_iounmap(ACCESS_FBINFO(mmio.vbase));
5719 return -ENOMEM;
5722 u_int32_t cmd;
5723 u_int32_t mga_option;
5725 /* Matrox MilleniumII is deactivated on bootup, but address
5726 regions are assigned to board. So we have to enable it */
5727 pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option);
5728 pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
5729 mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
5730 if ((cmd & PCI_COMMAND_MEMORY) !=
5731 PCI_COMMAND_MEMORY) {
5732 /* But if we have to enable it, we have probably to
5733 disable VGA I/O and BIOS... Sure? */
5734 dprintk(KERN_WARNING "matroxfb: PCI BIOS did not enable device!\n");
5735 cmd = (cmd | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_VGA_PALETTE;
5736 mga_option &= 0xBFFFFEFF;
5737 /* we must not enable VGA, BIOS if PCI BIOS did not enable device itself */
5738 ACCESS_FBINFO(devflags.novga) = 1;
5739 ACCESS_FBINFO(devflags.nobios) = 1;
5740 /* we must initialize device if PCI BIOS did not enable it.
5741 It probably means that it is second head ... */
5742 ACCESS_FBINFO(devflags.noinit) = 0;
5744 mga_option |= MX_OPTION_BSWAP;
5745 if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, NULL)) {
5746 if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
5747 printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
5749 mga_option |= 0x20000000;
5750 ACCESS_FBINFO(devflags.nopciretry) = 1;
5752 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd);
5753 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option);
5754 hw->MXoptionReg = mga_option;
5756 /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */
5757 /* maybe preinit() candidate, but it is same... for all devices... at this time... */
5758 pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00);
5761 if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO hw)) {
5762 mga_iounmap(ACCESS_FBINFO(video.vbase));
5763 mga_iounmap(ACCESS_FBINFO(mmio.vbase));
5764 return -ENXIO;
5768 unsigned int offs;
5770 if (!matroxfb_getmemory(PMINFO memsize, &offs, &ACCESS_FBINFO(video.len)) || !ACCESS_FBINFO(video.len)) {
5771 printk(KERN_ERR "matroxfb: cannot determine memory size\n");
5772 mga_iounmap(ACCESS_FBINFO(video.vbase));
5773 mga_iounmap(ACCESS_FBINFO(mmio.vbase));
5774 return -ENOMEM;
5776 #ifdef MATROX_2MB_WITH_4MB_ADDON
5777 #ifdef FBCON_HAS_CFB24
5779 unsigned int end = offs + ACCESS_FBINFO(video.len);
5781 if (offs)
5782 offs = ((offs - 1) / (4096 * 3) + 1) * 4096 * 3;
5783 ACCESS_FBINFO(video.len) = end - offs;
5785 #endif
5786 ACCESS_FBINFO(devflags.ydstorg) = offs;
5787 video_base_phys += offs;
5788 if (offs)
5789 ACCESS_FBINFO(capable.text) = 0;
5790 #else
5791 ACCESS_FBINFO(devflags.ydstorg) = 0;
5792 #endif
5794 ACCESS_FBINFO(currcon) = -1;
5795 ACCESS_FBINFO(currcon_display) = d;
5796 mga_iounmap(ACCESS_FBINFO(video.vbase));
5797 ACCESS_FBINFO(video.base) = video_base_phys;
5798 if (mga_ioremap(video_base_phys, ACCESS_FBINFO(video.len), MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) {
5799 printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
5800 video_base_phys, ACCESS_FBINFO(video.len));
5801 mga_iounmap(ACCESS_FBINFO(mmio.vbase));
5802 return -ENOMEM;
5804 ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len);
5805 if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable)
5806 ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable;
5807 #ifdef CONFIG_MTRR
5808 if (mtrr) {
5809 ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1);
5810 ACCESS_FBINFO(mtrr.vram_valid) = 1;
5811 printk(KERN_INFO "matroxfb: MTRR's turned on\n");
5813 #endif /* CONFIG_MTRR */
5815 if (!ACCESS_FBINFO(devflags.novga))
5816 request_region(0x3C0, 32, "matrox");
5817 ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
5819 /* validate params, autodetect k, M */
5820 if (fh < 1000) fh *= 1000; /* 1kHz minimum */
5821 if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */
5822 if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */
5823 if (vesa != ~0)
5824 vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */
5826 ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
5827 ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
5828 ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0;
5829 ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv;
5830 ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */
5832 /* static settings */
5833 for (RSptr = vesamap; RSptr->vesa; RSptr++) {
5834 if (RSptr->vesa == vesa) break;
5836 if (!RSptr->vesa) {
5837 printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa);
5838 RSptr = vesamap;
5841 int res = RSResolution(RSptr->info)-1;
5842 if (left == ~0)
5843 left = timmings[res].left;
5844 if (!xres)
5845 xres = timmings[res].xres;
5846 if (right == ~0)
5847 right = timmings[res].right;
5848 if (!hslen)
5849 hslen = timmings[res].hslen;
5850 if (upper == ~0)
5851 upper = timmings[res].upper;
5852 if (!yres)
5853 yres = timmings[res].yres;
5854 if (lower == ~0)
5855 lower = timmings[res].lower;
5856 if (!vslen)
5857 vslen = timmings[res].vslen;
5858 if (!(fv||fh||maxclk||pixclock))
5859 fv = timmings[res].vfreq;
5860 if (depth == -1)
5861 depth = RSDepth(RSptr->info);
5863 if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) {
5864 strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8");
5866 vesafb_defined.red = colors[depth-1].red;
5867 vesafb_defined.green = colors[depth-1].green;
5868 vesafb_defined.blue = colors[depth-1].blue;
5869 vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
5870 vesafb_defined.grayscale = grayscale;
5871 vesafb_defined.vmode = 0;
5872 if (noaccel)
5873 vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
5875 strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA");
5876 ACCESS_FBINFO(fbcon.changevar) = NULL;
5877 ACCESS_FBINFO(fbcon.node) = -1;
5878 ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops;
5879 ACCESS_FBINFO(fbcon.disp) = d;
5880 ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch;
5881 ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
5882 ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
5883 ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT;
5884 ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
5886 #ifndef MODULE
5887 /* mode database is marked __init ... */
5889 fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL,
5890 NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel);
5892 #endif /* !MODULE */
5894 /* mode modifiers */
5895 if (hslen)
5896 vesafb_defined.hsync_len = hslen;
5897 if (vslen)
5898 vesafb_defined.vsync_len = vslen;
5899 if (left != ~0)
5900 vesafb_defined.left_margin = left;
5901 if (right != ~0)
5902 vesafb_defined.right_margin = right;
5903 if (upper != ~0)
5904 vesafb_defined.upper_margin = upper;
5905 if (lower != ~0)
5906 vesafb_defined.lower_margin = lower;
5907 if (xres)
5908 vesafb_defined.xres = xres;
5909 if (yres)
5910 vesafb_defined.yres = yres;
5911 if (sync != -1)
5912 vesafb_defined.sync = sync;
5913 else if (vesafb_defined.sync == ~0) {
5914 vesafb_defined.sync = 0;
5915 if (yres < 400)
5916 vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT;
5917 else if (yres < 480)
5918 vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT;
5921 /* fv, fh, maxclk limits was specified */
5923 unsigned int tmp;
5925 if (fv) {
5926 tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
5927 + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
5928 if ((tmp < fh) || (fh == 0)) fh = tmp;
5930 if (fh) {
5931 tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
5932 + vesafb_defined.right_margin + vesafb_defined.hsync_len);
5933 if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
5935 maxclk = (maxclk + 499) / 500;
5936 if (maxclk) {
5937 tmp = (2000000000 + maxclk) / maxclk;
5938 if (tmp > pixclock) pixclock = tmp;
5941 if (pixclock) {
5942 if (pixclock < 2000) /* > 500MHz */
5943 pixclock = 4000; /* 250MHz */
5944 if (pixclock > 1000000)
5945 pixclock = 1000000; /* 1MHz */
5946 vesafb_defined.pixclock = pixclock;
5949 /* FIXME: Where to move this?! */
5950 #if defined(CONFIG_FB_OF)
5951 #if defined(CONFIG_FB_COMPAT_XPMAC)
5952 strcpy(ACCESS_FBINFO(matrox_name), "MTRX,"); /* OpenFirmware naming convension */
5953 strncat(ACCESS_FBINFO(matrox_name), b->name, 26);
5954 if (!console_fb_info)
5955 console_fb_info = &ACCESS_FBINFO(fbcon);
5956 #endif
5957 if ((xres <= 640) && (yres <= 480)) {
5958 struct fb_var_screeninfo var;
5959 if (default_vmode == VMODE_NVRAM) {
5960 default_vmode = nvram_read_byte(NV_VMODE);
5961 if (default_vmode <= 0 || default_vmode > VMODE_MAX)
5962 default_vmode = VMODE_CHOOSE;
5964 if (default_vmode <= 0 || default_vmode > VMODE_MAX)
5965 default_vmode = VMODE_640_480_60;
5966 if (default_cmode == CMODE_NVRAM)
5967 default_cmode = nvram_read_byte(NV_CMODE);
5968 if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
5969 default_cmode = CMODE_8;
5970 if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
5971 var.accel_flags = vesafb_defined.accel_flags;
5972 var.xoffset = var.yoffset = 0;
5973 vesafb_defined = var; /* Note: mac_vmode_to_var() doesnot set all parameters */
5976 #endif
5977 vesafb_defined.xres_virtual = vesafb_defined.xres;
5978 if (nopan) {
5979 vesafb_defined.yres_virtual = vesafb_defined.yres;
5980 } else {
5981 vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
5982 to yres_virtual * xres_virtual < 2^32 */
5984 if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) {
5985 printk(KERN_ERR "matroxfb: cannot set required parameters\n");
5986 return -EINVAL;
5989 printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
5990 vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
5991 vesafb_defined.xres_virtual, vesafb_defined.yres_virtual);
5992 printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n",
5993 ACCESS_FBINFO(video.base), vaddr_va(ACCESS_FBINFO(video.vbase)), ACCESS_FBINFO(video.len));
5995 /* We do not have to set currcon to 0... register_framebuffer do it for us on first console
5996 * and we do not want currcon == 0 for subsequent framebuffers */
5998 if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) {
5999 return -EINVAL;
6001 printk("fb%d: %s frame buffer device\n",
6002 GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename));
6003 if (ACCESS_FBINFO(currcon) < 0) {
6004 /* there is no console on this fb... but we have to initialize hardware
6005 * until someone tells me what is proper thing to do */
6006 printk(KERN_INFO "fb%d: initializing hardware\n",
6007 GET_FB_IDX(ACCESS_FBINFO(fbcon.node)));
6008 matroxfb_set_var(&vesafb_defined, -1, &ACCESS_FBINFO(fbcon));
6010 return 0;
6013 static struct matrox_fb_info* fb_list = NULL;
6015 static int __init matrox_init(void){
6016 struct pci_dev* pdev = NULL;
6018 DBG("matrox_init")
6020 if (disabled)
6021 return -ENXIO;
6022 while ((pdev = pci_find(pdev)) != NULL) {
6023 struct board* b;
6024 u_int8_t rev;
6025 u_int16_t svid;
6026 u_int16_t sid;
6028 pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
6029 pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
6030 pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sid);
6031 for (b = dev_list; b->vendor; b++) {
6032 if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
6033 if (b->svid)
6034 if ((b->svid != svid) || (b->sid != sid)) continue;
6035 if (dev <= 0) {
6036 struct matrox_fb_info* minfo;
6037 struct display* d;
6038 int err;
6040 #ifdef CONFIG_FB_MATROX_MULTIHEAD
6041 minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL);
6042 if (minfo) {
6043 d = (struct display*)kmalloc(sizeof(*d), GFP_KERNEL);
6044 if (d) {
6045 #else
6046 minfo = &global_mxinfo;
6047 d = &global_disp;
6048 #endif
6049 memset(MINFO, 0, sizeof(*MINFO));
6050 memset(d, 0, sizeof(*d));
6052 ACCESS_FBINFO(currenthw) = &ACCESS_FBINFO(hw1);
6053 ACCESS_FBINFO(newhw) = &ACCESS_FBINFO(hw2);
6054 ACCESS_FBINFO(pcidev) = pdev;
6055 /* CMDLINE */
6056 memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname)));
6057 /* DEVFLAGS */
6058 ACCESS_FBINFO(devflags.inverse) = inverse;
6059 ACCESS_FBINFO(devflags.novga) = novga;
6060 ACCESS_FBINFO(devflags.nobios) = nobios;
6061 ACCESS_FBINFO(devflags.noinit) = noinit;
6062 ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry;
6063 ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24;
6064 ACCESS_FBINFO(devflags.precise_width) = option_precise_width;
6065 ACCESS_FBINFO(devflags.hwcursor) = hwcursor;
6066 ACCESS_FBINFO(devflags.blink) = blink;
6067 ACCESS_FBINFO(devflags.sgram) = sgram;
6068 ACCESS_FBINFO(capable.cross4MB) = cross4MB;
6070 ACCESS_FBINFO(fastfont.size) = fastfont;
6072 ACCESS_FBINFO(cursor.state) = CM_ERASE;
6073 ACCESS_FBINFO(cursor.timer.prev) = ACCESS_FBINFO(cursor.timer.next) = NULL;
6074 ACCESS_FBINFO(cursor.timer.data) = (unsigned long)MINFO;
6075 spin_lock_init(&ACCESS_FBINFO(lock.DAC));
6077 err = initMatrox2(PMINFO d, b);
6078 if (!err) {
6079 ACCESS_FBINFO(next_fb) = fb_list;
6080 fb_list = MINFO;
6081 #ifdef CONFIG_FB_MATROX_MULTIHEAD
6082 goto leave;
6083 #else
6084 return 0;
6085 #endif
6087 #ifdef CONFIG_FB_MATROX_MULTIHEAD
6088 kfree(d);
6090 kfree(minfo);
6092 #endif
6094 #ifdef CONFIG_FB_MATROX_MULTIHEAD
6095 leave:;
6096 #endif
6097 if (dev == 0) return 0;
6098 if (dev > 0) dev--;
6099 break;
6102 return 0;
6105 #ifndef MODULE
6106 static int __init initialized = 0;
6108 int __init matroxfb_init(void)
6110 DBG("matroxfb_init")
6112 if (!initialized) {
6113 initialized = 1;
6114 matrox_init();
6116 if (!fb_list) return -ENXIO;
6117 return 0;
6120 #if defined(CONFIG_FB_OF)
6121 int __init matrox_of_init(struct device_node *dp){
6122 DBG("matrox_of_init");
6124 if (!initialized) {
6125 initialized = 1;
6126 matrox_init();
6128 if (!fb_list) return -ENXIO;
6129 return 0;
6131 #endif /* CONFIG_FB_OF */
6133 #else
6135 MODULE_AUTHOR("(c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>");
6136 MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400");
6137 MODULE_PARM(mem, "i");
6138 MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
6139 MODULE_PARM(disabled, "i");
6140 MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled), meaningless for module (default=0)");
6141 MODULE_PARM(noaccel, "i");
6142 MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)");
6143 MODULE_PARM(nopan, "i");
6144 MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)");
6145 MODULE_PARM(no_pci_retry, "i");
6146 MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)");
6147 MODULE_PARM(novga, "i");
6148 MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)");
6149 MODULE_PARM(nobios, "i");
6150 MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)");
6151 MODULE_PARM(noinit, "i");
6152 MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)");
6153 MODULE_PARM(mtrr, "i");
6154 MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
6155 MODULE_PARM(sgram, "i");
6156 MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
6157 MODULE_PARM(inv24, "i");
6158 MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
6159 MODULE_PARM(inverse, "i");
6160 MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)");
6161 #ifdef CONFIG_FB_MATROX_MULTIHEAD
6162 MODULE_PARM(dev, "i");
6163 MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)");
6164 #else
6165 MODULE_PARM(dev, "i");
6166 MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)");
6167 #endif
6168 MODULE_PARM(vesa, "i");
6169 MODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)");
6170 MODULE_PARM(xres, "i");
6171 MODULE_PARM_DESC(xres, "Horizontal resolutioni (px), overrides xres from vesa (default=vesa)");
6172 MODULE_PARM(yres, "i");
6173 MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)");
6174 MODULE_PARM(upper, "i");
6175 MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)");
6176 MODULE_PARM(lower, "i");
6177 MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)");
6178 MODULE_PARM(vslen, "i");
6179 MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)");
6180 MODULE_PARM(left, "i");
6181 MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)");
6182 MODULE_PARM(right, "i");
6183 MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)");
6184 MODULE_PARM(hslen, "i");
6185 MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)");
6186 MODULE_PARM(pixclock, "i");
6187 MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)");
6188 MODULE_PARM(sync, "i");
6189 MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)");
6190 MODULE_PARM(depth, "i");
6191 MODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)");
6192 MODULE_PARM(maxclk, "i");
6193 MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz");
6194 MODULE_PARM(fh, "i");
6195 MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz");
6196 MODULE_PARM(fv, "i");
6197 MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n"
6198 "You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n");
6199 MODULE_PARM(hwcursor, "i");
6200 MODULE_PARM_DESC(hwcursor, "Enables hardware cursor (0 or 1) (default=0)");
6201 MODULE_PARM(blink, "i");
6202 MODULE_PARM_DESC(blink, "Enables hardware cursor blinking (0 or 1) (default=1)");
6203 MODULE_PARM(fastfont, "i");
6204 MODULE_PARM_DESC(fastfont, "Specifies, how much memory should be used for font data (0, 1024-65536 are reasonable) (default=0)");
6205 MODULE_PARM(grayscale, "i");
6206 MODULE_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)");
6207 MODULE_PARM(cross4MB, "i");
6208 MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
6209 #ifdef CONFIG_FB_OF
6210 MODULE_PARM(vmode, "i");
6211 MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
6212 MODULE_PARM(cmode, "i");
6213 MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
6214 #endif
6216 int __init init_module(void){
6218 DBG("init_module")
6220 #ifdef DEBUG
6221 if( disabled )
6222 return -ENXIO;
6223 #endif /* DEBUG */
6225 if (depth == 0)
6226 depth = RSText;
6227 else if (depth == 4)
6228 depth = RS4bpp;
6229 else if (depth == 8)
6230 depth = RS8bpp;
6231 else if (depth == 15)
6232 depth = RS15bpp;
6233 else if (depth == 16)
6234 depth = RS16bpp;
6235 else if (depth == 24)
6236 depth = RS24bpp;
6237 else if (depth == 32)
6238 depth = RS32bpp;
6239 else if (depth != -1) {
6240 printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth);
6241 depth = -1;
6243 matrox_init();
6244 if (!fb_list) return -ENXIO;
6245 return 0;
6248 void cleanup_module(void) {
6250 DBG("cleanup_module")
6252 #ifdef DEBUG
6253 if( disabled )
6254 return;
6255 #endif /* DEBUG */
6257 while (fb_list) {
6258 struct matrox_fb_info* minfo;
6260 minfo = fb_list;
6261 fb_list = fb_list->next_fb;
6262 unregister_framebuffer(&ACCESS_FBINFO(fbcon));
6263 del_timer(&ACCESS_FBINFO(cursor.timer));
6264 #ifdef CONFIG_MTRR
6265 if (ACCESS_FBINFO(mtrr.vram_valid))
6266 mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len));
6267 #endif
6268 mga_iounmap(ACCESS_FBINFO(mmio.vbase));
6269 mga_iounmap(ACCESS_FBINFO(video.vbase));
6270 #ifdef CONFIG_FB_MATROX_MULTIHEAD
6271 kfree_s(ACCESS_FBINFO(fbcon.disp), sizeof(struct display));
6272 kfree_s(minfo, sizeof(struct matrox_fb_info));
6273 #endif
6276 #endif /* MODULE */
6278 * Overrides for Emacs so that we follow Linus's tabbing style.
6279 * ---------------------------------------------------------------------------
6280 * Local variables:
6281 * c-basic-offset: 8
6282 * End: