]> Pileus Git - ~andy/linux/blob - drivers/video/tridentfb.c
tridentfb: add acceleration for TGUI families
[~andy/linux] / drivers / video / tridentfb.c
1 /*
2  * Frame buffer driver for Trident Blade and Image series
3  *
4  * Copyright 2001, 2002 - Jani Monoses   <jani@iv.ro>
5  *
6  *
7  * CREDITS:(in order of appearance)
8  *      skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
9  *      Special thanks ;) to Mattia Crivellini <tia@mclink.it>
10  *      much inspired by the XFree86 4.x Trident driver sources
11  *      by Alan Hourihane the FreeVGA project
12  *      Francesco Salvestrini <salvestrini@users.sf.net> XP support,
13  *      code, suggestions
14  * TODO:
15  *      timing value tweaking so it looks good on every monitor in every mode
16  *      TGUI acceleration
17  */
18
19 #include <linux/module.h>
20 #include <linux/fb.h>
21 #include <linux/init.h>
22 #include <linux/pci.h>
23
24 #include <linux/delay.h>
25 #include <video/vga.h>
26 #include <video/trident.h>
27
28 #define VERSION         "0.7.9-NEWAPI"
29
30 struct tridentfb_par {
31         void __iomem *io_virt;  /* iospace virtual memory address */
32         u32 pseudo_pal[16];
33         int chip_id;
34         int flatpanel;
35         void (*init_accel) (struct tridentfb_par *, int, int);
36         void (*wait_engine) (struct tridentfb_par *);
37         void (*fill_rect)
38                 (struct tridentfb_par *par, u32, u32, u32, u32, u32, u32);
39         void (*copy_rect)
40                 (struct tridentfb_par *par, u32, u32, u32, u32, u32, u32);
41 };
42
43 static unsigned char eng_oper;  /* engine operation... */
44 static struct fb_ops tridentfb_ops;
45
46 static struct fb_fix_screeninfo tridentfb_fix = {
47         .id = "Trident",
48         .type = FB_TYPE_PACKED_PIXELS,
49         .ypanstep = 1,
50         .visual = FB_VISUAL_PSEUDOCOLOR,
51         .accel = FB_ACCEL_NONE,
52 };
53
54 /* defaults which are normally overriden by user values */
55
56 /* video mode */
57 static char *mode_option __devinitdata = "640x480";
58 static int bpp __devinitdata = 8;
59
60 static int noaccel __devinitdata;
61
62 static int center;
63 static int stretch;
64
65 static int fp __devinitdata;
66 static int crt __devinitdata;
67
68 static int memsize __devinitdata;
69 static int memdiff __devinitdata;
70 static int nativex;
71
72 module_param(mode_option, charp, 0);
73 MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
74 module_param_named(mode, mode_option, charp, 0);
75 MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)");
76 module_param(bpp, int, 0);
77 module_param(center, int, 0);
78 module_param(stretch, int, 0);
79 module_param(noaccel, int, 0);
80 module_param(memsize, int, 0);
81 module_param(memdiff, int, 0);
82 module_param(nativex, int, 0);
83 module_param(fp, int, 0);
84 MODULE_PARM_DESC(fp, "Define if flatpanel is connected");
85 module_param(crt, int, 0);
86 MODULE_PARM_DESC(crt, "Define if CRT is connected");
87
88 static int is_oldclock(int id)
89 {
90         return  (id == TGUI9440) ||
91                 (id == TGUI9660) ||
92                 (id == CYBER9320);
93 }
94
95 static int is_oldprotect(int id)
96 {
97         return  (id == TGUI9440) ||
98                 (id == TGUI9660) ||
99                 (id == PROVIDIA9685) ||
100                 (id == CYBER9320) ||
101                 (id == CYBER9382) ||
102                 (id == CYBER9385);
103 }
104
105 static int is_blade(int id)
106 {
107         return  (id == BLADE3D) ||
108                 (id == CYBERBLADEE4) ||
109                 (id == CYBERBLADEi7) ||
110                 (id == CYBERBLADEi7D) ||
111                 (id == CYBERBLADEi1) ||
112                 (id == CYBERBLADEi1D) ||
113                 (id == CYBERBLADEAi1) ||
114                 (id == CYBERBLADEAi1D);
115 }
116
117 static int is_xp(int id)
118 {
119         return  (id == CYBERBLADEXPAi1) ||
120                 (id == CYBERBLADEXPm8) ||
121                 (id == CYBERBLADEXPm16);
122 }
123
124 static int is3Dchip(int id)
125 {
126         return ((id == BLADE3D) || (id == CYBERBLADEE4) ||
127                 (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) ||
128                 (id == CYBER9397) || (id == CYBER9397DVD) ||
129                 (id == CYBER9520) || (id == CYBER9525DVD) ||
130                 (id == IMAGE975) || (id == IMAGE985) ||
131                 (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) ||
132                 (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) ||
133                 (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) ||
134                 (id == CYBERBLADEXPAi1));
135 }
136
137 static int iscyber(int id)
138 {
139         switch (id) {
140         case CYBER9388:
141         case CYBER9382:
142         case CYBER9385:
143         case CYBER9397:
144         case CYBER9397DVD:
145         case CYBER9520:
146         case CYBER9525DVD:
147         case CYBERBLADEE4:
148         case CYBERBLADEi7D:
149         case CYBERBLADEi1:
150         case CYBERBLADEi1D:
151         case CYBERBLADEAi1:
152         case CYBERBLADEAi1D:
153         case CYBERBLADEXPAi1:
154                 return 1;
155
156         case CYBER9320:
157         case TGUI9660:
158         case PROVIDIA9685:
159         case IMAGE975:
160         case IMAGE985:
161         case BLADE3D:
162         case CYBERBLADEi7:      /* VIA MPV4 integrated version */
163
164         default:
165                 /* case CYBERBLDAEXPm8:  Strange */
166                 /* case CYBERBLDAEXPm16: Strange */
167                 return 0;
168         }
169 }
170
171 static inline void t_outb(struct tridentfb_par *p, u8 val, u16 reg)
172 {
173         fb_writeb(val, p->io_virt + reg);
174 }
175
176 static inline u8 t_inb(struct tridentfb_par *p, u16 reg)
177 {
178         return fb_readb(p->io_virt + reg);
179 }
180
181 static inline void writemmr(struct tridentfb_par *par, u16 r, u32 v)
182 {
183         fb_writel(v, par->io_virt + r);
184 }
185
186 static inline u32 readmmr(struct tridentfb_par *par, u16 r)
187 {
188         return fb_readl(par->io_virt + r);
189 }
190
191 /*
192  * Blade specific acceleration.
193  */
194
195 #define point(x, y) ((y) << 16 | (x))
196 #define STA     0x2120
197 #define CMD     0x2144
198 #define ROP     0x2148
199 #define CLR     0x2160
200 #define SR1     0x2100
201 #define SR2     0x2104
202 #define DR1     0x2108
203 #define DR2     0x210C
204
205 #define ROP_S   0xCC
206
207 static void blade_init_accel(struct tridentfb_par *par, int pitch, int bpp)
208 {
209         int v1 = (pitch >> 3) << 20;
210         int tmp = 0, v2;
211         switch (bpp) {
212         case 8:
213                 tmp = 0;
214                 break;
215         case 15:
216                 tmp = 5;
217                 break;
218         case 16:
219                 tmp = 1;
220                 break;
221         case 24:
222         case 32:
223                 tmp = 2;
224                 break;
225         }
226         v2 = v1 | (tmp << 29);
227         writemmr(par, 0x21C0, v2);
228         writemmr(par, 0x21C4, v2);
229         writemmr(par, 0x21B8, v2);
230         writemmr(par, 0x21BC, v2);
231         writemmr(par, 0x21D0, v1);
232         writemmr(par, 0x21D4, v1);
233         writemmr(par, 0x21C8, v1);
234         writemmr(par, 0x21CC, v1);
235         writemmr(par, 0x216C, 0);
236 }
237
238 static void blade_wait_engine(struct tridentfb_par *par)
239 {
240         while (readmmr(par, STA) & 0xFA800000) ;
241 }
242
243 static void blade_fill_rect(struct tridentfb_par *par,
244                             u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
245 {
246         writemmr(par, CLR, c);
247         writemmr(par, ROP, rop ? 0x66 : ROP_S);
248         writemmr(par, CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
249
250         writemmr(par, DR1, point(x, y));
251         writemmr(par, DR2, point(x + w - 1, y + h - 1));
252 }
253
254 static void blade_copy_rect(struct tridentfb_par *par,
255                             u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
256 {
257         u32 s1, s2, d1, d2;
258         int direction = 2;
259         s1 = point(x1, y1);
260         s2 = point(x1 + w - 1, y1 + h - 1);
261         d1 = point(x2, y2);
262         d2 = point(x2 + w - 1, y2 + h - 1);
263
264         if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
265                 direction = 0;
266
267         writemmr(par, ROP, ROP_S);
268         writemmr(par, CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction);
269
270         writemmr(par, SR1, direction ? s2 : s1);
271         writemmr(par, SR2, direction ? s1 : s2);
272         writemmr(par, DR1, direction ? d2 : d1);
273         writemmr(par, DR2, direction ? d1 : d2);
274 }
275
276 /*
277  * BladeXP specific acceleration functions
278  */
279
280 #define ROP_P 0xF0
281 #define masked_point(x, y) ((y & 0xffff)<<16|(x & 0xffff))
282
283 static void xp_init_accel(struct tridentfb_par *par, int pitch, int bpp)
284 {
285         int tmp = 0, v1;
286         unsigned char x = 0;
287
288         switch (bpp) {
289         case 8:
290                 x = 0;
291                 break;
292         case 16:
293                 x = 1;
294                 break;
295         case 24:
296                 x = 3;
297                 break;
298         case 32:
299                 x = 2;
300                 break;
301         }
302
303         switch (pitch << (bpp >> 3)) {
304         case 8192:
305         case 512:
306                 x |= 0x00;
307                 break;
308         case 1024:
309                 x |= 0x04;
310                 break;
311         case 2048:
312                 x |= 0x08;
313                 break;
314         case 4096:
315                 x |= 0x0C;
316                 break;
317         }
318
319         t_outb(par, x, 0x2125);
320
321         eng_oper = x | 0x40;
322
323         switch (bpp) {
324         case 8:
325                 tmp = 18;
326                 break;
327         case 15:
328         case 16:
329                 tmp = 19;
330                 break;
331         case 24:
332         case 32:
333                 tmp = 20;
334                 break;
335         }
336
337         v1 = pitch << tmp;
338
339         writemmr(par, 0x2154, v1);
340         writemmr(par, 0x2150, v1);
341         t_outb(par, 3, 0x2126);
342 }
343
344 static void xp_wait_engine(struct tridentfb_par *par)
345 {
346         int busy;
347         int count, timeout;
348
349         count = 0;
350         timeout = 0;
351         for (;;) {
352                 busy = t_inb(par, STA) & 0x80;
353                 if (busy != 0x80)
354                         return;
355                 count++;
356                 if (count == 10000000) {
357                         /* Timeout */
358                         count = 9990000;
359                         timeout++;
360                         if (timeout == 8) {
361                                 /* Reset engine */
362                                 t_outb(par, 0x00, 0x2120);
363                                 return;
364                         }
365                 }
366         }
367 }
368
369 static void xp_fill_rect(struct tridentfb_par *par,
370                          u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
371 {
372         writemmr(par, 0x2127, ROP_P);
373         writemmr(par, 0x2158, c);
374         writemmr(par, 0x2128, 0x4000);
375         writemmr(par, 0x2140, masked_point(h, w));
376         writemmr(par, 0x2138, masked_point(y, x));
377         t_outb(par, 0x01, 0x2124);
378         t_outb(par, eng_oper, 0x2125);
379 }
380
381 static void xp_copy_rect(struct tridentfb_par *par,
382                          u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
383 {
384         int direction;
385         u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
386
387         direction = 0x0004;
388
389         if ((x1 < x2) && (y1 == y2)) {
390                 direction |= 0x0200;
391                 x1_tmp = x1 + w - 1;
392                 x2_tmp = x2 + w - 1;
393         } else {
394                 x1_tmp = x1;
395                 x2_tmp = x2;
396         }
397
398         if (y1 < y2) {
399                 direction |= 0x0100;
400                 y1_tmp = y1 + h - 1;
401                 y2_tmp = y2 + h - 1;
402         } else {
403                 y1_tmp = y1;
404                 y2_tmp = y2;
405         }
406
407         writemmr(par, 0x2128, direction);
408         t_outb(par, ROP_S, 0x2127);
409         writemmr(par, 0x213C, masked_point(y1_tmp, x1_tmp));
410         writemmr(par, 0x2138, masked_point(y2_tmp, x2_tmp));
411         writemmr(par, 0x2140, masked_point(h, w));
412         t_outb(par, 0x01, 0x2124);
413 }
414
415 /*
416  * Image specific acceleration functions
417  */
418 static void image_init_accel(struct tridentfb_par *par, int pitch, int bpp)
419 {
420         int tmp = 0;
421         switch (bpp) {
422         case 8:
423                 tmp = 0;
424                 break;
425         case 15:
426                 tmp = 5;
427                 break;
428         case 16:
429                 tmp = 1;
430                 break;
431         case 24:
432         case 32:
433                 tmp = 2;
434                 break;
435         }
436         writemmr(par, 0x2120, 0xF0000000);
437         writemmr(par, 0x2120, 0x40000000 | tmp);
438         writemmr(par, 0x2120, 0x80000000);
439         writemmr(par, 0x2144, 0x00000000);
440         writemmr(par, 0x2148, 0x00000000);
441         writemmr(par, 0x2150, 0x00000000);
442         writemmr(par, 0x2154, 0x00000000);
443         writemmr(par, 0x2120, 0x60000000 | (pitch << 16) | pitch);
444         writemmr(par, 0x216C, 0x00000000);
445         writemmr(par, 0x2170, 0x00000000);
446         writemmr(par, 0x217C, 0x00000000);
447         writemmr(par, 0x2120, 0x10000000);
448         writemmr(par, 0x2130, (2047 << 16) | 2047);
449 }
450
451 static void image_wait_engine(struct tridentfb_par *par)
452 {
453         while (readmmr(par, 0x2164) & 0xF0000000) ;
454 }
455
456 static void image_fill_rect(struct tridentfb_par *par,
457                             u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
458 {
459         writemmr(par, 0x2120, 0x80000000);
460         writemmr(par, 0x2120, 0x90000000 | ROP_S);
461
462         writemmr(par, 0x2144, c);
463
464         writemmr(par, DR1, point(x, y));
465         writemmr(par, DR2, point(x + w - 1, y + h - 1));
466
467         writemmr(par, 0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9);
468 }
469
470 static void image_copy_rect(struct tridentfb_par *par,
471                             u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
472 {
473         u32 s1, s2, d1, d2;
474         int direction = 2;
475         s1 = point(x1, y1);
476         s2 = point(x1 + w - 1, y1 + h - 1);
477         d1 = point(x2, y2);
478         d2 = point(x2 + w - 1, y2 + h - 1);
479
480         if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
481                 direction = 0;
482
483         writemmr(par, 0x2120, 0x80000000);
484         writemmr(par, 0x2120, 0x90000000 | ROP_S);
485
486         writemmr(par, SR1, direction ? s2 : s1);
487         writemmr(par, SR2, direction ? s1 : s2);
488         writemmr(par, DR1, direction ? d2 : d1);
489         writemmr(par, DR2, direction ? d1 : d2);
490         writemmr(par, 0x2124,
491                  0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction);
492 }
493
494 /*
495  * TGUI 9440/96XX acceleration
496  */
497
498 static void tgui_init_accel(struct tridentfb_par *par, int pitch, int bpp)
499 {
500         unsigned char x = 0;
501
502         /* disable clipping */
503         writemmr(par, 0x2148, 0);
504         writemmr(par, 0x214C, point(4095, 2047));
505
506         switch (bpp) {
507         case 8:
508                 x = 0;
509                 break;
510         case 16:
511                 x = 1;
512                 break;
513         case 24:
514                 x = 3;
515                 break;
516         case 32:
517                 x = 2;
518                 break;
519         }
520
521         switch ((pitch * bpp) / 8) {
522         case 8192:
523         case 512:
524                 x |= 0x00;
525                 break;
526         case 1024:
527                 x |= 0x04;
528                 break;
529         case 2048:
530                 x |= 0x08;
531                 break;
532         case 4096:
533                 x |= 0x0C;
534                 break;
535         }
536
537         fb_writew(x, par->io_virt + 0x2122);
538 }
539
540 static void tgui_fill_rect(struct tridentfb_par *par,
541                            u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
542 {
543         t_outb(par, ROP_P, 0x2127);
544         writemmr(par, 0x212c, c);
545         writemmr(par, 0x2128, 0x4020);
546         writemmr(par, 0x2140, point(w - 1, h - 1));
547         writemmr(par, 0x2138, point(x, y));
548         t_outb(par, 1, 0x2124);
549 }
550
551 static void tgui_copy_rect(struct tridentfb_par *par,
552                            u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
553 {
554         int flags = 0;
555         u16 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
556
557         if ((x1 < x2) && (y1 == y2)) {
558                 flags |= 0x0200;
559                 x1_tmp = x1 + w - 1;
560                 x2_tmp = x2 + w - 1;
561         } else {
562                 x1_tmp = x1;
563                 x2_tmp = x2;
564         }
565
566         if (y1 < y2) {
567                 flags |= 0x0100;
568                 y1_tmp = y1 + h - 1;
569                 y2_tmp = y2 + h - 1;
570         } else {
571                 y1_tmp = y1;
572                 y2_tmp = y2;
573         }
574
575         writemmr(par, 0x2128, 0x4 | flags);
576         t_outb(par, ROP_S, 0x2127);
577         writemmr(par, 0x213C, point(x1_tmp, y1_tmp));
578         writemmr(par, 0x2138, point(x2_tmp, y2_tmp));
579         writemmr(par, 0x2140, point(w - 1, h - 1));
580         t_outb(par, 1, 0x2124);
581 }
582
583 /*
584  * Accel functions called by the upper layers
585  */
586 #ifdef CONFIG_FB_TRIDENT_ACCEL
587 static void tridentfb_fillrect(struct fb_info *info,
588                                const struct fb_fillrect *fr)
589 {
590         struct tridentfb_par *par = info->par;
591         int bpp = info->var.bits_per_pixel;
592         int col = 0;
593
594         switch (bpp) {
595         default:
596         case 8:
597                 col |= fr->color;
598                 col |= col << 8;
599                 col |= col << 16;
600                 break;
601         case 16:
602                 col = ((u32 *)(info->pseudo_palette))[fr->color];
603                 break;
604         case 32:
605                 col = ((u32 *)(info->pseudo_palette))[fr->color];
606                 break;
607         }
608
609         par->fill_rect(par, fr->dx, fr->dy, fr->width,
610                        fr->height, col, fr->rop);
611         par->wait_engine(par);
612 }
613 static void tridentfb_copyarea(struct fb_info *info,
614                                const struct fb_copyarea *ca)
615 {
616         struct tridentfb_par *par = info->par;
617
618         par->copy_rect(par, ca->sx, ca->sy, ca->dx, ca->dy,
619                        ca->width, ca->height);
620         par->wait_engine(par);
621 }
622 #endif /* CONFIG_FB_TRIDENT_ACCEL */
623
624 /*
625  * Hardware access functions
626  */
627
628 static inline unsigned char read3X4(struct tridentfb_par *par, int reg)
629 {
630         return vga_mm_rcrt(par->io_virt, reg);
631 }
632
633 static inline void write3X4(struct tridentfb_par *par, int reg,
634                             unsigned char val)
635 {
636         vga_mm_wcrt(par->io_virt, reg, val);
637 }
638
639 static inline unsigned char read3CE(struct tridentfb_par *par,
640                                     unsigned char reg)
641 {
642         return vga_mm_rgfx(par->io_virt, reg);
643 }
644
645 static inline void writeAttr(struct tridentfb_par *par, int reg,
646                              unsigned char val)
647 {
648         fb_readb(par->io_virt + VGA_IS1_RC);    /* flip-flop to index */
649         vga_mm_wattr(par->io_virt, reg, val);
650 }
651
652 static inline void write3CE(struct tridentfb_par *par, int reg,
653                             unsigned char val)
654 {
655         vga_mm_wgfx(par->io_virt, reg, val);
656 }
657
658 static void enable_mmio(void)
659 {
660         /* Goto New Mode */
661         vga_io_rseq(0x0B);
662
663         /* Unprotect registers */
664         vga_io_wseq(NewMode1, 0x80);
665
666         /* Enable MMIO */
667         outb(PCIReg, 0x3D4);
668         outb(inb(0x3D5) | 0x01, 0x3D5);
669 }
670
671 static void disable_mmio(struct tridentfb_par *par)
672 {
673         /* Goto New Mode */
674         vga_mm_rseq(par->io_virt, 0x0B);
675
676         /* Unprotect registers */
677         vga_mm_wseq(par->io_virt, NewMode1, 0x80);
678
679         /* Disable MMIO */
680         t_outb(par, PCIReg, 0x3D4);
681         t_outb(par, t_inb(par, 0x3D5) & ~0x01, 0x3D5);
682 }
683
684 static void crtc_unlock(struct tridentfb_par *par)
685 {
686         write3X4(par, VGA_CRTC_V_SYNC_END,
687                  read3X4(par, VGA_CRTC_V_SYNC_END) & 0x7F);
688 }
689
690 /*  Return flat panel's maximum x resolution */
691 static int __devinit get_nativex(struct tridentfb_par *par)
692 {
693         int x, y, tmp;
694
695         if (nativex)
696                 return nativex;
697
698         tmp = (read3CE(par, VertStretch) >> 4) & 3;
699
700         switch (tmp) {
701         case 0:
702                 x = 1280; y = 1024;
703                 break;
704         case 2:
705                 x = 1024; y = 768;
706                 break;
707         case 3:
708                 x = 800; y = 600;
709                 break;
710         case 4:
711                 x = 1400; y = 1050;
712                 break;
713         case 1:
714         default:
715                 x = 640;  y = 480;
716                 break;
717         }
718
719         output("%dx%d flat panel found\n", x, y);
720         return x;
721 }
722
723 /* Set pitch */
724 static void set_lwidth(struct tridentfb_par *par, int width)
725 {
726         write3X4(par, VGA_CRTC_OFFSET, width & 0xFF);
727         write3X4(par, AddColReg,
728                  (read3X4(par, AddColReg) & 0xCF) | ((width & 0x300) >> 4));
729 }
730
731 /* For resolutions smaller than FP resolution stretch */
732 static void screen_stretch(struct tridentfb_par *par)
733 {
734         if (par->chip_id != CYBERBLADEXPAi1)
735                 write3CE(par, BiosReg, 0);
736         else
737                 write3CE(par, BiosReg, 8);
738         write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 1);
739         write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 1);
740 }
741
742 /* For resolutions smaller than FP resolution center */
743 static void screen_center(struct tridentfb_par *par)
744 {
745         write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 0x80);
746         write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 0x80);
747 }
748
749 /* Address of first shown pixel in display memory */
750 static void set_screen_start(struct tridentfb_par *par, int base)
751 {
752         u8 tmp;
753         write3X4(par, VGA_CRTC_START_LO, base & 0xFF);
754         write3X4(par, VGA_CRTC_START_HI, (base & 0xFF00) >> 8);
755         tmp = read3X4(par, CRTCModuleTest) & 0xDF;
756         write3X4(par, CRTCModuleTest, tmp | ((base & 0x10000) >> 11));
757         tmp = read3X4(par, CRTHiOrd) & 0xF8;
758         write3X4(par, CRTHiOrd, tmp | ((base & 0xE0000) >> 17));
759 }
760
761 /* Set dotclock frequency */
762 static void set_vclk(struct tridentfb_par *par, unsigned long freq)
763 {
764         int m, n, k;
765         unsigned long fi, d, di;
766         unsigned char best_m = 0, best_n = 0, best_k = 0;
767         unsigned char hi, lo;
768
769         d = 20000;
770         for (k = 1; k >= 0; k--)
771                 for (m = 0; m < 32; m++)
772                         for (n = 0; n < 122; n++) {
773                                 fi = ((14318l * (n + 8)) / (m + 2)) >> k;
774                                 if ((di = abs(fi - freq)) < d) {
775                                         d = di;
776                                         best_n = n;
777                                         best_m = m;
778                                         best_k = k;
779                                 }
780                                 if (fi > freq)
781                                         break;
782                         }
783
784         if (is_oldclock(par->chip_id)) {
785                 lo = best_n | (best_m << 7);
786                 hi = (best_m >> 1) | (best_k << 4);
787         } else {
788                 lo = best_n;
789                 hi = best_m | (best_k << 6);
790         }
791
792         if (is3Dchip(par->chip_id)) {
793                 vga_mm_wseq(par->io_virt, ClockHigh, hi);
794                 vga_mm_wseq(par->io_virt, ClockLow, lo);
795         } else {
796                 t_outb(par, lo, 0x43C8);
797                 t_outb(par, hi, 0x43C9);
798         }
799         debug("VCLK = %X %X\n", hi, lo);
800 }
801
802 /* Set number of lines for flat panels*/
803 static void set_number_of_lines(struct tridentfb_par *par, int lines)
804 {
805         int tmp = read3CE(par, CyberEnhance) & 0x8F;
806         if (lines > 1024)
807                 tmp |= 0x50;
808         else if (lines > 768)
809                 tmp |= 0x30;
810         else if (lines > 600)
811                 tmp |= 0x20;
812         else if (lines > 480)
813                 tmp |= 0x10;
814         write3CE(par, CyberEnhance, tmp);
815 }
816
817 /*
818  * If we see that FP is active we assume we have one.
819  * Otherwise we have a CRT display. User can override.
820  */
821 static int __devinit is_flatpanel(struct tridentfb_par *par)
822 {
823         if (fp)
824                 return 1;
825         if (crt || !iscyber(par->chip_id))
826                 return 0;
827         return (read3CE(par, FPConfig) & 0x10) ? 1 : 0;
828 }
829
830 /* Try detecting the video memory size */
831 static unsigned int __devinit get_memsize(struct tridentfb_par *par)
832 {
833         unsigned char tmp, tmp2;
834         unsigned int k;
835
836         /* If memory size provided by user */
837         if (memsize)
838                 k = memsize * Kb;
839         else
840                 switch (par->chip_id) {
841                 case CYBER9525DVD:
842                         k = 2560 * Kb;
843                         break;
844                 default:
845                         tmp = read3X4(par, SPR) & 0x0F;
846                         switch (tmp) {
847
848                         case 0x01:
849                                 k = 512 * Kb;
850                                 break;
851                         case 0x02:
852                                 k = 6 * Mb;     /* XP */
853                                 break;
854                         case 0x03:
855                                 k = 1 * Mb;
856                                 break;
857                         case 0x04:
858                                 k = 8 * Mb;
859                                 break;
860                         case 0x06:
861                                 k = 10 * Mb;    /* XP */
862                                 break;
863                         case 0x07:
864                                 k = 2 * Mb;
865                                 break;
866                         case 0x08:
867                                 k = 12 * Mb;    /* XP */
868                                 break;
869                         case 0x0A:
870                                 k = 14 * Mb;    /* XP */
871                                 break;
872                         case 0x0C:
873                                 k = 16 * Mb;    /* XP */
874                                 break;
875                         case 0x0E:              /* XP */
876
877                                 tmp2 = vga_mm_rseq(par->io_virt, 0xC1);
878                                 switch (tmp2) {
879                                 case 0x00:
880                                         k = 20 * Mb;
881                                         break;
882                                 case 0x01:
883                                         k = 24 * Mb;
884                                         break;
885                                 case 0x10:
886                                         k = 28 * Mb;
887                                         break;
888                                 case 0x11:
889                                         k = 32 * Mb;
890                                         break;
891                                 default:
892                                         k = 1 * Mb;
893                                         break;
894                                 }
895                                 break;
896
897                         case 0x0F:
898                                 k = 4 * Mb;
899                                 break;
900                         default:
901                                 k = 1 * Mb;
902                                 break;
903                         }
904                 }
905
906         k -= memdiff * Kb;
907         output("framebuffer size = %d Kb\n", k / Kb);
908         return k;
909 }
910
911 /* See if we can handle the video mode described in var */
912 static int tridentfb_check_var(struct fb_var_screeninfo *var,
913                                struct fb_info *info)
914 {
915         struct tridentfb_par *par = info->par;
916         int bpp = var->bits_per_pixel;
917         int line_length;
918         int ramdac = 230000; /* 230MHz for most 3D chips */
919         debug("enter\n");
920
921         /* check color depth */
922         if (bpp == 24)
923                 bpp = var->bits_per_pixel = 32;
924         if (par->chip_id == TGUI9440 && bpp == 32)
925                 return -EINVAL;
926         /* check whether resolution fits on panel and in memory */
927         if (par->flatpanel && nativex && var->xres > nativex)
928                 return -EINVAL;
929         /* various resolution checks */
930         var->xres = (var->xres + 7) & ~0x7;
931         if (var->xres != var->xres_virtual)
932                 var->xres_virtual = var->xres;
933         line_length = var->xres_virtual * bpp / 8;
934 #ifdef CONFIG_FB_TRIDENT_ACCEL
935         if (!is3Dchip(par->chip_id)) {
936                 /* acceleration requires line length to be power of 2 */
937                 if (line_length <= 512)
938                         var->xres_virtual = 512 * 8 / bpp;
939                 else if (line_length <= 1024)
940                         var->xres_virtual = 1024 * 8 / bpp;
941                 else if (line_length <= 2048)
942                         var->xres_virtual = 2048 * 8 / bpp;
943                 else if (line_length <= 4096)
944                         var->xres_virtual = 4096 * 8 / bpp;
945                 else if (line_length <= 8192)
946                         var->xres_virtual = 8192 * 8 / bpp;
947
948                 line_length = var->xres_virtual * bpp / 8;
949         }
950 #endif
951         if (var->yres > var->yres_virtual)
952                 var->yres_virtual = var->yres;
953         if (line_length * var->yres_virtual > info->fix.smem_len)
954                 return -EINVAL;
955
956         switch (bpp) {
957         case 8:
958                 var->red.offset = 0;
959                 var->green.offset = 0;
960                 var->blue.offset = 0;
961                 var->red.length = 6;
962                 var->green.length = 6;
963                 var->blue.length = 6;
964                 break;
965         case 16:
966                 var->red.offset = 11;
967                 var->green.offset = 5;
968                 var->blue.offset = 0;
969                 var->red.length = 5;
970                 var->green.length = 6;
971                 var->blue.length = 5;
972                 break;
973         case 32:
974                 var->red.offset = 16;
975                 var->green.offset = 8;
976                 var->blue.offset = 0;
977                 var->red.length = 8;
978                 var->green.length = 8;
979                 var->blue.length = 8;
980                 break;
981         default:
982                 return -EINVAL;
983         }
984
985         if (is_xp(par->chip_id))
986                 ramdac = 350000;
987
988         switch (par->chip_id) {
989         case TGUI9440:
990                 ramdac = (bpp >= 16) ? 45000 : 90000;
991                 break;
992         case CYBER9320:
993         case TGUI9660:
994                 ramdac = 135000;
995                 break;
996         case PROVIDIA9685:
997         case CYBER9388:
998         case CYBER9382:
999         case CYBER9385:
1000                 ramdac = 170000;
1001                 break;
1002         }
1003
1004         /* The clock is doubled for 32 bpp */
1005         if (bpp == 32)
1006                 ramdac /= 2;
1007
1008         if (PICOS2KHZ(var->pixclock) > ramdac)
1009                 return -EINVAL;
1010
1011         debug("exit\n");
1012
1013         return 0;
1014
1015 }
1016
1017 /* Pan the display */
1018 static int tridentfb_pan_display(struct fb_var_screeninfo *var,
1019                                  struct fb_info *info)
1020 {
1021         struct tridentfb_par *par = info->par;
1022         unsigned int offset;
1023
1024         debug("enter\n");
1025         offset = (var->xoffset + (var->yoffset * var->xres_virtual))
1026                 * var->bits_per_pixel / 32;
1027         info->var.xoffset = var->xoffset;
1028         info->var.yoffset = var->yoffset;
1029         set_screen_start(par, offset);
1030         debug("exit\n");
1031         return 0;
1032 }
1033
1034 static void shadowmode_on(struct tridentfb_par *par)
1035 {
1036         write3CE(par, CyberControl, read3CE(par, CyberControl) | 0x81);
1037 }
1038
1039 static void shadowmode_off(struct tridentfb_par *par)
1040 {
1041         write3CE(par, CyberControl, read3CE(par, CyberControl) & 0x7E);
1042 }
1043
1044 /* Set the hardware to the requested video mode */
1045 static int tridentfb_set_par(struct fb_info *info)
1046 {
1047         struct tridentfb_par *par = (struct tridentfb_par *)(info->par);
1048         u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend;
1049         u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend;
1050         struct fb_var_screeninfo *var = &info->var;
1051         int bpp = var->bits_per_pixel;
1052         unsigned char tmp;
1053         unsigned long vclk;
1054
1055         debug("enter\n");
1056         hdispend = var->xres / 8 - 1;
1057         hsyncstart = (var->xres + var->right_margin) / 8 - 1;
1058         hsyncend = (var->xres + var->right_margin + var->hsync_len) / 8 - 1;
1059         htotal = (var->xres + var->left_margin + var->right_margin +
1060                   var->hsync_len) / 8 - 5;
1061         hblankstart = hdispend + 1;
1062         hblankend = htotal + 3;
1063
1064         vdispend = var->yres - 1;
1065         vsyncstart = var->yres + var->lower_margin;
1066         vsyncend = vsyncstart + var->vsync_len;
1067         vtotal = var->upper_margin + vsyncend - 2;
1068         vblankstart = vdispend + 1;
1069         vblankend = vtotal;
1070
1071         crtc_unlock(par);
1072         write3CE(par, CyberControl, 8);
1073
1074         if (par->flatpanel && var->xres < nativex) {
1075                 /*
1076                  * on flat panels with native size larger
1077                  * than requested resolution decide whether
1078                  * we stretch or center
1079                  */
1080                 t_outb(par, 0xEB, VGA_MIS_W);
1081
1082                 shadowmode_on(par);
1083
1084                 if (center)
1085                         screen_center(par);
1086                 else if (stretch)
1087                         screen_stretch(par);
1088
1089         } else {
1090                 t_outb(par, 0x2B, VGA_MIS_W);
1091                 write3CE(par, CyberControl, 8);
1092         }
1093
1094         /* vertical timing values */
1095         write3X4(par, VGA_CRTC_V_TOTAL, vtotal & 0xFF);
1096         write3X4(par, VGA_CRTC_V_DISP_END, vdispend & 0xFF);
1097         write3X4(par, VGA_CRTC_V_SYNC_START, vsyncstart & 0xFF);
1098         write3X4(par, VGA_CRTC_V_SYNC_END, (vsyncend & 0x0F));
1099         write3X4(par, VGA_CRTC_V_BLANK_START, vblankstart & 0xFF);
1100         write3X4(par, VGA_CRTC_V_BLANK_END, vblankend & 0xFF);
1101
1102         /* horizontal timing values */
1103         write3X4(par, VGA_CRTC_H_TOTAL, htotal & 0xFF);
1104         write3X4(par, VGA_CRTC_H_DISP, hdispend & 0xFF);
1105         write3X4(par, VGA_CRTC_H_SYNC_START, hsyncstart & 0xFF);
1106         write3X4(par, VGA_CRTC_H_SYNC_END,
1107                  (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
1108         write3X4(par, VGA_CRTC_H_BLANK_START, hblankstart & 0xFF);
1109         write3X4(par, VGA_CRTC_H_BLANK_END, hblankend & 0x1F);
1110
1111         /* higher bits of vertical timing values */
1112         tmp = 0x10;
1113         if (vtotal & 0x100) tmp |= 0x01;
1114         if (vdispend & 0x100) tmp |= 0x02;
1115         if (vsyncstart & 0x100) tmp |= 0x04;
1116         if (vblankstart & 0x100) tmp |= 0x08;
1117
1118         if (vtotal & 0x200) tmp |= 0x20;
1119         if (vdispend & 0x200) tmp |= 0x40;
1120         if (vsyncstart & 0x200) tmp |= 0x80;
1121         write3X4(par, VGA_CRTC_OVERFLOW, tmp);
1122
1123         tmp = read3X4(par, CRTHiOrd) & 0x07;
1124         tmp |= 0x08;    /* line compare bit 10 */
1125         if (vtotal & 0x400) tmp |= 0x80;
1126         if (vblankstart & 0x400) tmp |= 0x40;
1127         if (vsyncstart & 0x400) tmp |= 0x20;
1128         if (vdispend & 0x400) tmp |= 0x10;
1129         write3X4(par, CRTHiOrd, tmp);
1130
1131         tmp = (htotal >> 8) & 0x01;
1132         tmp |= (hdispend >> 7) & 0x02;
1133         tmp |= (hsyncstart >> 5) & 0x08;
1134         tmp |= (hblankstart >> 4) & 0x10;
1135         write3X4(par, HorizOverflow, tmp);
1136
1137         tmp = 0x40;
1138         if (vblankstart & 0x200) tmp |= 0x20;
1139 //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80;  /* double scan for 200 line modes */
1140         write3X4(par, VGA_CRTC_MAX_SCAN, tmp);
1141
1142         write3X4(par, VGA_CRTC_LINE_COMPARE, 0xFF);
1143         write3X4(par, VGA_CRTC_PRESET_ROW, 0);
1144         write3X4(par, VGA_CRTC_MODE, 0xC3);
1145
1146         write3X4(par, LinearAddReg, 0x20);      /* enable linear addressing */
1147
1148         tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80;
1149         /* enable access extended memory */
1150         write3X4(par, CRTCModuleTest, tmp);
1151
1152         /* enable GE for text acceleration */
1153         write3X4(par, GraphEngReg, 0x80);
1154
1155 #ifdef CONFIG_FB_TRIDENT_ACCEL
1156         par->init_accel(par, info->var.xres_virtual, bpp);
1157 #endif
1158
1159         switch (bpp) {
1160         case 8:
1161                 tmp = 0x00;
1162                 break;
1163         case 16:
1164                 tmp = 0x05;
1165                 break;
1166         case 24:
1167                 tmp = 0x29;
1168                 break;
1169         case 32:
1170                 tmp = 0x09;
1171                 break;
1172         }
1173
1174         write3X4(par, PixelBusReg, tmp);
1175
1176         tmp = read3X4(par, DRAMControl);
1177         if (!is_oldprotect(par->chip_id))
1178                 tmp |= 0x10;
1179         if (iscyber(par->chip_id))
1180                 tmp |= 0x20;
1181         write3X4(par, DRAMControl, tmp);        /* both IO, linear enable */
1182
1183         write3X4(par, InterfaceSel, read3X4(par, InterfaceSel) | 0x40);
1184         if (!is_xp(par->chip_id))
1185                 write3X4(par, Performance, read3X4(par, Performance) | 0x10);
1186         /* MMIO & PCI read and write burst enable */
1187         if (par->chip_id != TGUI9440)
1188                 write3X4(par, PCIReg, read3X4(par, PCIReg) | 0x06);
1189
1190         vga_mm_wseq(par->io_virt, 0, 3);
1191         vga_mm_wseq(par->io_virt, 1, 1); /* set char clock 8 dots wide */
1192         /* enable 4 maps because needed in chain4 mode */
1193         vga_mm_wseq(par->io_virt, 2, 0x0F);
1194         vga_mm_wseq(par->io_virt, 3, 0);
1195         vga_mm_wseq(par->io_virt, 4, 0x0E); /* memory mode enable bitmaps ?? */
1196
1197         /* convert from picoseconds to kHz */
1198         vclk = PICOS2KHZ(info->var.pixclock);
1199
1200         /* divide clock by 2 if 32bpp chain4 mode display and CPU path */
1201         tmp = read3CE(par, MiscExtFunc) & 0xF0;
1202         if (bpp == 32 || (par->chip_id == TGUI9440 && bpp == 16)) {
1203                 tmp |= 8;
1204                 vclk *= 2;
1205         }
1206         set_vclk(par, vclk);
1207         write3CE(par, MiscExtFunc, tmp | 0x12);
1208         write3CE(par, 0x5, 0x40);       /* no CGA compat, allow 256 col */
1209         write3CE(par, 0x6, 0x05);       /* graphics mode */
1210         write3CE(par, 0x7, 0x0F);       /* planes? */
1211
1212         if (par->chip_id == CYBERBLADEXPAi1) {
1213                 /* This fixes snow-effect in 32 bpp */
1214                 write3X4(par, VGA_CRTC_H_SYNC_START, 0x84);
1215         }
1216
1217         /* graphics mode and support 256 color modes */
1218         writeAttr(par, 0x10, 0x41);
1219         writeAttr(par, 0x12, 0x0F);     /* planes */
1220         writeAttr(par, 0x13, 0);        /* horizontal pel panning */
1221
1222         /* colors */
1223         for (tmp = 0; tmp < 0x10; tmp++)
1224                 writeAttr(par, tmp, tmp);
1225         fb_readb(par->io_virt + VGA_IS1_RC);    /* flip-flop to index */
1226         t_outb(par, 0x20, VGA_ATT_W);           /* enable attr */
1227
1228         switch (bpp) {
1229         case 8:
1230                 tmp = 0;
1231                 break;
1232         case 15:
1233                 tmp = 0x10;
1234                 break;
1235         case 16:
1236                 tmp = 0x30;
1237                 break;
1238         case 24:
1239         case 32:
1240                 tmp = 0xD0;
1241                 break;
1242         }
1243
1244         t_inb(par, VGA_PEL_IW);
1245         t_inb(par, VGA_PEL_MSK);
1246         t_inb(par, VGA_PEL_MSK);
1247         t_inb(par, VGA_PEL_MSK);
1248         t_inb(par, VGA_PEL_MSK);
1249         t_outb(par, tmp, VGA_PEL_MSK);
1250         t_inb(par, VGA_PEL_IW);
1251
1252         if (par->flatpanel)
1253                 set_number_of_lines(par, info->var.yres);
1254         info->fix.line_length = info->var.xres_virtual * bpp / 8;
1255         set_lwidth(par, info->fix.line_length / 8);
1256         info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1257         info->cmap.len = (bpp == 8) ? 256 : 16;
1258         debug("exit\n");
1259         return 0;
1260 }
1261
1262 /* Set one color register */
1263 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1264                                unsigned blue, unsigned transp,
1265                                struct fb_info *info)
1266 {
1267         int bpp = info->var.bits_per_pixel;
1268         struct tridentfb_par *par = info->par;
1269
1270         if (regno >= info->cmap.len)
1271                 return 1;
1272
1273         if (bpp == 8) {
1274                 t_outb(par, 0xFF, VGA_PEL_MSK);
1275                 t_outb(par, regno, VGA_PEL_IW);
1276
1277                 t_outb(par, red >> 10, VGA_PEL_D);
1278                 t_outb(par, green >> 10, VGA_PEL_D);
1279                 t_outb(par, blue >> 10, VGA_PEL_D);
1280
1281         } else if (regno < 16) {
1282                 if (bpp == 16) {        /* RGB 565 */
1283                         u32 col;
1284
1285                         col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
1286                                 ((blue & 0xF800) >> 11);
1287                         col |= col << 16;
1288                         ((u32 *)(info->pseudo_palette))[regno] = col;
1289                 } else if (bpp == 32)           /* ARGB 8888 */
1290                         ((u32*)info->pseudo_palette)[regno] =
1291                                 ((transp & 0xFF00) << 16)       |
1292                                 ((red & 0xFF00) << 8)           |
1293                                 ((green & 0xFF00))              |
1294                                 ((blue & 0xFF00) >> 8);
1295         }
1296
1297 /*      debug("exit\n"); */
1298         return 0;
1299 }
1300
1301 /* Try blanking the screen.For flat panels it does nothing */
1302 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1303 {
1304         unsigned char PMCont, DPMSCont;
1305         struct tridentfb_par *par = info->par;
1306
1307         debug("enter\n");
1308         if (par->flatpanel)
1309                 return 0;
1310         t_outb(par, 0x04, 0x83C8); /* Read DPMS Control */
1311         PMCont = t_inb(par, 0x83C6) & 0xFC;
1312         DPMSCont = read3CE(par, PowerStatus) & 0xFC;
1313         switch (blank_mode) {
1314         case FB_BLANK_UNBLANK:
1315                 /* Screen: On, HSync: On, VSync: On */
1316         case FB_BLANK_NORMAL:
1317                 /* Screen: Off, HSync: On, VSync: On */
1318                 PMCont |= 0x03;
1319                 DPMSCont |= 0x00;
1320                 break;
1321         case FB_BLANK_HSYNC_SUSPEND:
1322                 /* Screen: Off, HSync: Off, VSync: On */
1323                 PMCont |= 0x02;
1324                 DPMSCont |= 0x01;
1325                 break;
1326         case FB_BLANK_VSYNC_SUSPEND:
1327                 /* Screen: Off, HSync: On, VSync: Off */
1328                 PMCont |= 0x02;
1329                 DPMSCont |= 0x02;
1330                 break;
1331         case FB_BLANK_POWERDOWN:
1332                 /* Screen: Off, HSync: Off, VSync: Off */
1333                 PMCont |= 0x00;
1334                 DPMSCont |= 0x03;
1335                 break;
1336         }
1337
1338         write3CE(par, PowerStatus, DPMSCont);
1339         t_outb(par, 4, 0x83C8);
1340         t_outb(par, PMCont, 0x83C6);
1341
1342         debug("exit\n");
1343
1344         /* let fbcon do a softblank for us */
1345         return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1346 }
1347
1348 static struct fb_ops tridentfb_ops = {
1349         .owner = THIS_MODULE,
1350         .fb_setcolreg = tridentfb_setcolreg,
1351         .fb_pan_display = tridentfb_pan_display,
1352         .fb_blank = tridentfb_blank,
1353         .fb_check_var = tridentfb_check_var,
1354         .fb_set_par = tridentfb_set_par,
1355 #ifdef CONFIG_FB_TRIDENT_ACCEL
1356         .fb_fillrect = tridentfb_fillrect,
1357         .fb_copyarea = tridentfb_copyarea,
1358         .fb_imageblit = cfb_imageblit,
1359 #endif
1360 };
1361
1362 static int __devinit trident_pci_probe(struct pci_dev *dev,
1363                                        const struct pci_device_id *id)
1364 {
1365         int err;
1366         unsigned char revision;
1367         struct fb_info *info;
1368         struct tridentfb_par *default_par;
1369         int defaultaccel;
1370         int chip3D;
1371         int chip_id;
1372
1373         err = pci_enable_device(dev);
1374         if (err)
1375                 return err;
1376
1377         info = framebuffer_alloc(sizeof(struct tridentfb_par), &dev->dev);
1378         if (!info)
1379                 return -ENOMEM;
1380         default_par = info->par;
1381
1382         chip_id = id->device;
1383
1384         if (chip_id == CYBERBLADEi1)
1385                 output("*** Please do use cyblafb, Cyberblade/i1 support "
1386                        "will soon be removed from tridentfb!\n");
1387
1388
1389         /* If PCI id is 0x9660 then further detect chip type */
1390
1391         if (chip_id == TGUI9660) {
1392                 revision = vga_io_rseq(RevisionID);
1393
1394                 switch (revision) {
1395                 case 0x21:
1396                         chip_id = PROVIDIA9685;
1397                         break;
1398                 case 0x22:
1399                 case 0x23:
1400                         chip_id = CYBER9397;
1401                         break;
1402                 case 0x2A:
1403                         chip_id = CYBER9397DVD;
1404                         break;
1405                 case 0x30:
1406                 case 0x33:
1407                 case 0x34:
1408                 case 0x35:
1409                 case 0x38:
1410                 case 0x3A:
1411                 case 0xB3:
1412                         chip_id = CYBER9385;
1413                         break;
1414                 case 0x40 ... 0x43:
1415                         chip_id = CYBER9382;
1416                         break;
1417                 case 0x4A:
1418                         chip_id = CYBER9388;
1419                         break;
1420                 default:
1421                         break;
1422                 }
1423         }
1424
1425         chip3D = is3Dchip(chip_id);
1426
1427         if (is_xp(chip_id)) {
1428                 default_par->init_accel = xp_init_accel;
1429                 default_par->wait_engine = xp_wait_engine;
1430                 default_par->fill_rect = xp_fill_rect;
1431                 default_par->copy_rect = xp_copy_rect;
1432         } else if (is_blade(chip_id)) {
1433                 default_par->init_accel = blade_init_accel;
1434                 default_par->wait_engine = blade_wait_engine;
1435                 default_par->fill_rect = blade_fill_rect;
1436                 default_par->copy_rect = blade_copy_rect;
1437         } else if (chip3D) {                    /* 3DImage family left */
1438                 default_par->init_accel = image_init_accel;
1439                 default_par->wait_engine = image_wait_engine;
1440                 default_par->fill_rect = image_fill_rect;
1441                 default_par->copy_rect = image_copy_rect;
1442         } else {                                /* TGUI 9440/96XX family */
1443                 default_par->init_accel = tgui_init_accel;
1444                 default_par->wait_engine = xp_wait_engine;
1445                 default_par->fill_rect = tgui_fill_rect;
1446                 default_par->copy_rect = tgui_copy_rect;
1447         }
1448
1449         default_par->chip_id = chip_id;
1450
1451         /* acceleration is on by default for 3D chips */
1452         defaultaccel = chip3D && !noaccel;
1453
1454         /* setup MMIO region */
1455         tridentfb_fix.mmio_start = pci_resource_start(dev, 1);
1456         tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000;
1457
1458         if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1459                 debug("request_region failed!\n");
1460                 framebuffer_release(info);
1461                 return -1;
1462         }
1463
1464         default_par->io_virt = ioremap_nocache(tridentfb_fix.mmio_start,
1465                                                tridentfb_fix.mmio_len);
1466
1467         if (!default_par->io_virt) {
1468                 debug("ioremap failed\n");
1469                 err = -1;
1470                 goto out_unmap1;
1471         }
1472
1473         enable_mmio();
1474
1475         /* setup framebuffer memory */
1476         tridentfb_fix.smem_start = pci_resource_start(dev, 0);
1477         tridentfb_fix.smem_len = get_memsize(default_par);
1478
1479         if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1480                 debug("request_mem_region failed!\n");
1481                 disable_mmio(info->par);
1482                 err = -1;
1483                 goto out_unmap1;
1484         }
1485
1486         info->screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1487                                             tridentfb_fix.smem_len);
1488
1489         if (!info->screen_base) {
1490                 debug("ioremap failed\n");
1491                 err = -1;
1492                 goto out_unmap2;
1493         }
1494
1495         output("%s board found\n", pci_name(dev));
1496         default_par->flatpanel = is_flatpanel(default_par);
1497
1498         if (default_par->flatpanel)
1499                 nativex = get_nativex(default_par);
1500
1501         info->fix = tridentfb_fix;
1502         info->fbops = &tridentfb_ops;
1503         info->pseudo_palette = default_par->pseudo_pal;
1504
1505         info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1506 #ifdef CONFIG_FB_TRIDENT_ACCEL
1507         info->flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1508 #endif
1509         if (!fb_find_mode(&info->var, info,
1510                           mode_option, NULL, 0, NULL, bpp)) {
1511                 err = -EINVAL;
1512                 goto out_unmap2;
1513         }
1514         err = fb_alloc_cmap(&info->cmap, 256, 0);
1515         if (err < 0)
1516                 goto out_unmap2;
1517
1518         if (defaultaccel && default_par->init_accel)
1519                 info->var.accel_flags |= FB_ACCELF_TEXT;
1520         else
1521                 info->var.accel_flags &= ~FB_ACCELF_TEXT;
1522         info->var.activate |= FB_ACTIVATE_NOW;
1523         info->device = &dev->dev;
1524         if (register_framebuffer(info) < 0) {
1525                 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1526                 fb_dealloc_cmap(&info->cmap);
1527                 err = -EINVAL;
1528                 goto out_unmap2;
1529         }
1530         output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1531            info->node, info->fix.id, info->var.xres,
1532            info->var.yres, info->var.bits_per_pixel);
1533
1534         pci_set_drvdata(dev, info);
1535         return 0;
1536
1537 out_unmap2:
1538         if (info->screen_base)
1539                 iounmap(info->screen_base);
1540         release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1541         disable_mmio(info->par);
1542 out_unmap1:
1543         if (default_par->io_virt)
1544                 iounmap(default_par->io_virt);
1545         release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1546         framebuffer_release(info);
1547         return err;
1548 }
1549
1550 static void __devexit trident_pci_remove(struct pci_dev *dev)
1551 {
1552         struct fb_info *info = pci_get_drvdata(dev);
1553         struct tridentfb_par *par = info->par;
1554
1555         unregister_framebuffer(info);
1556         iounmap(par->io_virt);
1557         iounmap(info->screen_base);
1558         release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1559         release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1560         pci_set_drvdata(dev, NULL);
1561         framebuffer_release(info);
1562 }
1563
1564 /* List of boards that we are trying to support */
1565 static struct pci_device_id trident_devices[] = {
1566         {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1567         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1568         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1569         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1570         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1571         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1572         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1573         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1574         {PCI_VENDOR_ID_TRIDENT, TGUI9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1575         {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1576         {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1577         {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1578         {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1579         {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1580         {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1581         {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1582         {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1583         {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1584         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1585         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1586         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1587         {0,}
1588 };
1589
1590 MODULE_DEVICE_TABLE(pci, trident_devices);
1591
1592 static struct pci_driver tridentfb_pci_driver = {
1593         .name = "tridentfb",
1594         .id_table = trident_devices,
1595         .probe = trident_pci_probe,
1596         .remove = __devexit_p(trident_pci_remove)
1597 };
1598
1599 /*
1600  * Parse user specified options (`video=trident:')
1601  * example:
1602  *      video=trident:800x600,bpp=16,noaccel
1603  */
1604 #ifndef MODULE
1605 static int __init tridentfb_setup(char *options)
1606 {
1607         char *opt;
1608         if (!options || !*options)
1609                 return 0;
1610         while ((opt = strsep(&options, ",")) != NULL) {
1611                 if (!*opt)
1612                         continue;
1613                 if (!strncmp(opt, "noaccel", 7))
1614                         noaccel = 1;
1615                 else if (!strncmp(opt, "fp", 2))
1616                         fp = 1;
1617                 else if (!strncmp(opt, "crt", 3))
1618                         fp = 0;
1619                 else if (!strncmp(opt, "bpp=", 4))
1620                         bpp = simple_strtoul(opt + 4, NULL, 0);
1621                 else if (!strncmp(opt, "center", 6))
1622                         center = 1;
1623                 else if (!strncmp(opt, "stretch", 7))
1624                         stretch = 1;
1625                 else if (!strncmp(opt, "memsize=", 8))
1626                         memsize = simple_strtoul(opt + 8, NULL, 0);
1627                 else if (!strncmp(opt, "memdiff=", 8))
1628                         memdiff = simple_strtoul(opt + 8, NULL, 0);
1629                 else if (!strncmp(opt, "nativex=", 8))
1630                         nativex = simple_strtoul(opt + 8, NULL, 0);
1631                 else
1632                         mode_option = opt;
1633         }
1634         return 0;
1635 }
1636 #endif
1637
1638 static int __init tridentfb_init(void)
1639 {
1640 #ifndef MODULE
1641         char *option = NULL;
1642
1643         if (fb_get_options("tridentfb", &option))
1644                 return -ENODEV;
1645         tridentfb_setup(option);
1646 #endif
1647         output("Trident framebuffer %s initializing\n", VERSION);
1648         return pci_register_driver(&tridentfb_pci_driver);
1649 }
1650
1651 static void __exit tridentfb_exit(void)
1652 {
1653         pci_unregister_driver(&tridentfb_pci_driver);
1654 }
1655
1656 module_init(tridentfb_init);
1657 module_exit(tridentfb_exit);
1658
1659 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1660 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1661 MODULE_LICENSE("GPL");
1662