Merge branch 'upstream'
[sfrench/cifs-2.6.git] / drivers / video / cyblafb.c
1 /*
2  * Frame buffer driver for Trident Cyberblade/i1 graphics core
3  *
4  * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de>
5  *
6  * CREDITS:
7  *      tridentfb.c by Jani Monoses
8  *      see files above for further credits
9  *
10  */
11
12 #define CYBLAFB_DEBUG 0
13 #define CYBLAFB_KD_GRAPHICS_QUIRK 1
14
15 #define CYBLAFB_PIXMAPSIZE 8192
16
17 #include <linux/config.h>
18 #include <linux/module.h>
19 #include <linux/string.h>
20 #include <linux/fb.h>
21 #include <linux/init.h>
22 #include <linux/pci.h>
23 #include <asm/types.h>
24 #include <video/cyblafb.h>
25
26 #define VERSION "0.62"
27
28 struct cyblafb_par {
29         u32 pseudo_pal[16];
30         struct fb_ops ops;
31 };
32
33 static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
34         .id = "CyBla",
35         .type = FB_TYPE_PACKED_PIXELS,
36         .xpanstep = 1,
37         .ypanstep = 1,
38         .ywrapstep = 1,
39         .visual = FB_VISUAL_PSEUDOCOLOR,
40         .accel = FB_ACCEL_NONE,
41 };
42
43 static char *mode __devinitdata = NULL;
44 static int bpp __devinitdata = 8;
45 static int ref __devinitdata = 75;
46 static int fp __devinitdata;
47 static int crt __devinitdata;
48 static int memsize __devinitdata;
49
50 static int basestride;
51 static int vesafb;
52 static int nativex;
53 static int center;
54 static int stretch;
55 static int pciwb = 1;
56 static int pcirb = 1;
57 static int pciwr = 1;
58 static int pcirr = 1;
59 static int disabled;
60 static int verbosity;
61 static int displaytype;
62
63 static void __iomem *io_virt;   // iospace virtual memory address
64
65 module_param(mode, charp, 0);
66 module_param(bpp, int, 0);
67 module_param(ref, int, 0);
68 module_param(fp, int, 0);
69 module_param(crt, int, 0);
70 module_param(nativex, int, 0);
71 module_param(center, int, 0);
72 module_param(stretch, int, 0);
73 module_param(pciwb, int, 0);
74 module_param(pcirb, int, 0);
75 module_param(pciwr, int, 0);
76 module_param(pcirr, int, 0);
77 module_param(memsize, int, 0);
78 module_param(verbosity, int, 0);
79
80 //=========================================
81 //
82 // Well, we have to fix the upper layers.
83 // Until this has been done, we work around
84 // the bugs.
85 //
86 //=========================================
87
88 #if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
89         if (disabled) { \
90                 printk("********\n");\
91                 dump_stack();\
92                 return val;\
93         }
94
95 #elif CYBLAFB_KD_GRAPHICS_QUIRK
96 #define KD_GRAPHICS_RETURN(val)\
97         if (disabled) {\
98                 return val;\
99         }
100 #else
101 #define KD_GRAPHICS_RETURN(val)
102 #endif
103
104 //=========================================
105 //
106 // Port access macros for memory mapped io
107 //
108 //=========================================
109
110 #define out8(r, v) writeb(v, io_virt + r)
111 #define out32(r, v) writel(v, io_virt + r)
112 #define in8(r) readb(io_virt + r)
113 #define in32(r) readl(io_virt + r)
114
115 //======================================
116 //
117 // Hardware access inline functions
118 //
119 //======================================
120
121 static inline u8 read3X4(u32 reg)
122 {
123         out8(0x3D4, reg);
124         return in8(0x3D5);
125 }
126
127 static inline u8 read3C4(u32 reg)
128 {
129         out8(0x3C4, reg);
130         return in8(0x3C5);
131 }
132
133 static inline u8 read3CE(u32 reg)
134 {
135         out8(0x3CE, reg);
136         return in8(0x3CF);
137 }
138
139 static inline void write3X4(u32 reg, u8 val)
140 {
141         out8(0x3D4, reg);
142         out8(0x3D5, val);
143 }
144
145 static inline void write3C4(u32 reg, u8 val)
146 {
147         out8(0x3C4, reg);
148         out8(0x3C5, val);
149 }
150
151 static inline void write3CE(u32 reg, u8 val)
152 {
153         out8(0x3CE, reg);
154         out8(0x3CF, val);
155 }
156
157 static inline void write3C0(u32 reg, u8 val)
158 {
159         in8(0x3DA);             // read to reset index
160         out8(0x3C0, reg);
161         out8(0x3C0, val);
162 }
163
164 //=================================================
165 //
166 // Enable memory mapped io and unprotect registers
167 //
168 //=================================================
169
170 static void enable_mmio(void)
171 {
172         u8 tmp;
173
174         outb(0x0B, 0x3C4);
175         inb(0x3C5);             // Set NEW mode
176         outb(SR0E, 0x3C4);      // write enable a lot of extended ports
177         outb(0x80, 0x3C5);
178
179         outb(SR11, 0x3C4);      // write enable those extended ports that
180         outb(0x87, 0x3C5);      // are not affected by SR0E_New
181
182         outb(CR1E, 0x3d4);      // clear write protect bit for port 0x3c2
183         tmp = inb(0x3d5) & 0xBF;
184         outb(CR1E, 0x3d4);
185         outb(tmp, 0x3d5);
186
187         outb(CR39, 0x3D4);
188         outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
189 }
190
191 //=================================================
192 //
193 // Set pixel clock VCLK1
194 // - multipliers set elswhere
195 // - freq in units of 0.01 MHz
196 //
197 // Hardware bug: SR18 >= 250 is broken for the
198 //               cyberblade/i1
199 //
200 //=================================================
201
202 static void set_vclk(struct cyblafb_par *par, int freq)
203 {
204         u32 m, n, k;
205         int f, fi, d, di;
206         u8 lo = 0, hi = 0;
207
208         d = 2000;
209         k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
210         for (m = 0; m < 64; m++)
211                 for (n = 0; n < 250; n++) {
212                         fi = (int)(((5864727 * (n + 8)) /
213                                     ((m + 2) * (1 << k))) >> 12);
214                         if ((di = abs(fi - freq)) < d) {
215                                 d = di;
216                                 f = fi;
217                                 lo = (u8) n;
218                                 hi = (u8) ((k << 6) | m);
219                         }
220                 }
221         write3C4(SR19, hi);
222         write3C4(SR18, lo);
223         if (verbosity > 0)
224                 output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
225                        freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);
226 }
227
228 //================================================
229 //
230 // Cyberblade specific Graphics Engine (GE) setup
231 //
232 //================================================
233
234 static void cyblafb_setup_GE(int pitch, int bpp)
235 {
236         KD_GRAPHICS_RETURN();
237
238         switch (bpp) {
239         case 8:
240                 basestride = ((pitch >> 3) << 20) | (0 << 29);
241                 break;
242         case 15:
243                 basestride = ((pitch >> 3) << 20) | (5 << 29);
244                 break;
245         case 16:
246                 basestride = ((pitch >> 3) << 20) | (1 << 29);
247                 break;
248         case 24:
249         case 32:
250                 basestride = ((pitch >> 3) << 20) | (2 << 29);
251                 break;
252         }
253
254         write3X4(CR36, 0x90);   // reset GE
255         write3X4(CR36, 0x80);   // enable GE
256         out32(GE24, 1 << 7);    // reset all GE pointers by toggling
257         out32(GE24, 0);         //   d7 of GE24
258         write3X4(CR2D, 0x00);   // GE Timinigs, no delays
259         out32(GE6C, 0);         // Pattern and Style, p 129, ok
260 }
261
262 //=====================================================================
263 //
264 // Cyberblade specific syncing
265 //
266 //   A timeout might be caused by disabled mmio.
267 //   Cause:
268 //     - bit CR39 & 1 == 0 upon return, X trident driver bug
269 //     - kdm bug (KD_GRAPHICS not set on first switch)
270 //     - kernel design flaw (it believes in the correctness
271 //       of kdm/X
272 //   First we try to sync ignoring that problem, as most of the
273 //   time that will succeed immediately and the enable_mmio()
274 //   would only degrade performance.
275 //
276 //=====================================================================
277
278 static int cyblafb_sync(struct fb_info *info)
279 {
280         u32 status, i = 100000;
281
282         KD_GRAPHICS_RETURN(0);
283
284         while (((status = in32(GE20)) & 0xFe800000) && i != 0)
285                 i--;
286
287         if (i == 0) {
288                 enable_mmio();
289                 i = 1000000;
290                 while (((status = in32(GE20)) & 0xFA800000) && i != 0)
291                         i--;
292                 if (i == 0) {
293                         output("GE Timeout, status: %x\n", status);
294                         if (status & 0x80000000)
295                                 output("Bresenham Engine : Busy\n");
296                         if (status & 0x40000000)
297                                 output("Setup Engine     : Busy\n");
298                         if (status & 0x20000000)
299                                 output("SP / DPE         : Busy\n");
300                         if (status & 0x10000000)
301                                 output("Memory Interface : Busy\n");
302                         if (status & 0x08000000)
303                                 output("Com Lst Proc     : Busy\n");
304                         if (status & 0x04000000)
305                                 output("Block Write      : Busy\n");
306                         if (status & 0x02000000)
307                                 output("Command Buffer   : Full\n");
308                         if (status & 0x01000000)
309                                 output("RESERVED         : Busy\n");
310                         if (status & 0x00800000)
311                                 output("PCI Write Buffer : Busy\n");
312                         cyblafb_setup_GE(info->var.xres,
313                                          info->var.bits_per_pixel);
314                 }
315         }
316
317         return 0;
318 }
319
320 //==============================
321 //
322 // Cyberblade specific fillrect
323 //
324 //==============================
325
326 static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
327 {
328         u32 bpp = info->var.bits_per_pixel, col, desty, height;
329
330         KD_GRAPHICS_RETURN();
331
332         switch (bpp) {
333         default:
334         case 8:
335                 col = fr->color;
336                 col |= col << 8;
337                 col |= col << 16;
338                 break;
339         case 16:
340                 col = ((u32 *) (info->pseudo_palette))[fr->color];
341                 col |= col << 16;
342                 break;
343         case 32:
344                 col = ((u32 *) (info->pseudo_palette))[fr->color];
345                 break;
346         }
347
348         desty = fr->dy;
349         height = fr->height;
350         while (height) {
351                 out32(GEB8, basestride | ((desty * info->var.xres_virtual *
352                                            bpp) >> 6));
353                 out32(GE60, col);
354                 out32(GE48, fr->rop ? 0x66 : ROP_S);
355                 out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
356                 out32(GE08, point(fr->dx, 0));
357                 out32(GE0C, point(fr->dx + fr->width - 1,
358                                   height > 4096 ? 4095 : height - 1));
359                 if (likely(height <= 4096))
360                         return;
361                 desty += 4096;
362                 height -= 4096;
363         }
364 }
365
366 //================================================
367 //
368 // Cyberblade specific copyarea
369 //
370 // This function silently assumes that it never
371 // will be called with width or height exceeding
372 // 4096.
373 //
374 //================================================
375
376 static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
377 {
378         u32 s1, s2, d1, d2, direction;
379
380         KD_GRAPHICS_RETURN();
381
382         s1 = point(ca->sx, 0);
383         s2 = point(ca->sx + ca->width - 1, ca->height - 1);
384         d1 = point(ca->dx, 0);
385         d2 = point(ca->dx + ca->width - 1, ca->height - 1);
386
387         if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
388                 direction = 0;
389         else
390                 direction = 2;
391
392         out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *
393                                    info->var.bits_per_pixel) >> 6));
394         out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *
395                                    info->var.bits_per_pixel) >> 6));
396         out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);
397         out32(GE00, direction ? s2 : s1);
398         out32(GE04, direction ? s1 : s2);
399         out32(GE08, direction ? d2 : d1);
400         out32(GE0C, direction ? d1 : d2);
401 }
402
403 //=======================================================================
404 //
405 // Cyberblade specific imageblit
406 //
407 // Accelerated for the most usual case, blitting 1 - bit deep
408 // character images. Everything else is passed to the generic imageblit
409 // unless it is so insane that it is better to printk an alert.
410 //
411 // Hardware bug: _Never_ blit across pixel column 2048, that will lock
412 // the system. We split those blit requests into three blitting
413 // operations.
414 //
415 //=======================================================================
416
417 static void cyblafb_imageblit(struct fb_info *info,
418                               const struct fb_image *image)
419 {
420         u32 fgcol, bgcol;
421         u32 *pd = (u32 *) image->data;
422         u32 bpp = info->var.bits_per_pixel;
423
424         KD_GRAPHICS_RETURN();
425
426         // Used only for drawing the penguine (image->depth > 1)
427         if (image->depth != 1) {
428                 cfb_imageblit(info, image);
429                 return;
430         }
431         // That should never happen, but it would be fatal
432         if (image->width == 0 || image->height == 0) {
433                 output("imageblit: width/height 0 detected\n");
434                 return;
435         }
436
437         if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
438             info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
439                 fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];
440                 bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];
441         } else {
442                 fgcol = image->fg_color;
443                 bgcol = image->bg_color;
444         }
445
446         switch (bpp) {
447         case 8:
448                 fgcol |= fgcol << 8;
449                 bgcol |= bgcol << 8;
450         case 16:
451                 fgcol |= fgcol << 16;
452                 bgcol |= bgcol << 16;
453         default:
454                 break;
455         }
456
457         out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *
458                                    bpp) >> 6));
459         out32(GE60, fgcol);
460         out32(GE64, bgcol);
461
462         if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {
463                 u32 dds = ((image->width + 31) >> 5) * image->height;
464                 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
465                 out32(GE08, point(image->dx, 0));
466                 out32(GE0C, point(image->dx + image->width - 1,
467                                   image->height - 1));
468                 while (dds--)
469                         out32(GE9C, *pd++);
470         } else {
471                 int i, j;
472                 u32 ddstotal = (image->width + 31) >> 5;
473                 u32 ddsleft = (2048 - image->dx + 31) >> 5;
474                 u32 skipleft = ddstotal - ddsleft;
475
476                 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
477                 out32(GE08, point(image->dx, 0));
478                 out32(GE0C, point(2048 - 1, image->height - 1));
479                 for (i = 0; i < image->height; i++) {
480                         for (j = 0; j < ddsleft; j++)
481                                 out32(GE9C, *pd++);
482                         pd += skipleft;
483                 }
484
485                 if (image->dx % 32) {
486                         out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
487                         out32(GE08, point(2048, 0));
488                         if (image->width > ddsleft << 5)
489                                 out32(GE0C, point(image->dx + (ddsleft << 5) -
490                                                   1, image->height - 1));
491                         else
492                                 out32(GE0C, point(image->dx + image->width - 1,
493                                                   image->height - 1));
494                         pd = ((u32 *) image->data) + ddstotal - skipleft - 1;
495                         for (i = 0; i < image->height; i++) {
496                                 out32(GE9C, swab32(swab32(*pd) << ((32 -
497                                             (image->dx & 31)) & 31)));
498                                 pd += ddstotal;
499                         }
500                 }
501
502                 if (skipleft) {
503                         out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
504                         out32(GE08, point(image->dx + (ddsleft << 5), 0));
505                         out32(GE0C, point(image->dx + image->width - 1,
506                                           image->height - 1));
507                         pd = (u32 *) image->data;
508                         for (i = 0; i < image->height; i++) {
509                                 pd += ddsleft;
510                                 for (j = 0; j < skipleft; j++)
511                                         out32(GE9C, *pd++);
512                         }
513                 }
514         }
515 }
516
517 //==========================================================
518 //
519 // Check if video mode is acceptable. We change var->??? if
520 // video mode is slightly off or return error otherwise.
521 // info->??? must not be changed!
522 //
523 //==========================================================
524
525 static int cyblafb_check_var(struct fb_var_screeninfo *var,
526                              struct fb_info *info)
527 {
528         int bpp = var->bits_per_pixel;
529
530         //
531         // we try to support 8, 16, 24 and 32 bpp modes,
532         // default to 8
533         //
534         // there is a 24 bpp mode, but for now we change requests to 32 bpp
535         // (This is what tridentfb does ... will be changed in the future)
536         //
537         //
538         if (bpp % 8 != 0 || bpp < 8 || bpp > 32)
539                 bpp = 8;
540         if (bpp == 24)
541                 bpp = var->bits_per_pixel = 32;
542
543         //
544         // interlaced modes are broken, fail if one is requested
545         //
546         if (var->vmode & FB_VMODE_INTERLACED)
547                 return -EINVAL;
548
549         //
550         // fail if requested resolution is higher than physical
551         // flatpanel resolution
552         //
553         if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
554                 return -EINVAL;
555
556         //
557         // we do not allow vclk to exceed 230 MHz. If the requested
558         // vclk is too high, we default to 200 MHz
559         //
560         if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)
561                 var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;
562
563         //
564         // enforce (h|v)sync_len limits
565         //
566         var->hsync_len &= ~7;
567         if(var->hsync_len > 248)
568                 var->hsync_len = 248;
569
570         var->vsync_len &= 15;
571
572         //
573         // Enforce horizontal and vertical hardware limits.
574         // 1600x1200 is mentioned as a maximum, but higher resolutions could
575         // work with slow refresh, small margins and short sync.
576         //
577         var->xres &= ~7;
578
579         if (((var->xres + var->left_margin + var->right_margin +
580                         var->hsync_len) > (bpp == 32 ? 2040 : 4088)) ||
581                         ((var->yres + var->upper_margin + var->lower_margin +
582                         var->vsync_len) > 2047))
583                 return -EINVAL;
584
585         if ((var->xres > 1600) || (var->yres > 1200))
586                 output("Mode %dx%d exceeds documented limits.\n",
587                                            var->xres, var->yres);
588         //
589         // try to be smart about (x|y)res_virtual problems.
590         //
591         if (var->xres > var->xres_virtual)
592                 var->xres_virtual = var->xres;
593         if (var->yres > var->yres_virtual)
594                 var->yres_virtual = var->yres;
595
596         if (bpp == 8 || bpp == 16) {
597                 if (var->xres_virtual > 4088)
598                         var->xres_virtual = 4088;
599         } else {
600                 if (var->xres_virtual > 2040)
601                         var->xres_virtual = 2040;
602         }
603         var->xres_virtual &= ~7;
604         while (var->xres_virtual * var->yres_virtual * bpp / 8 >
605                info->fix.smem_len) {
606                 if (var->yres_virtual > var->yres)
607                         var->yres_virtual--;
608                 else if (var->xres_virtual > var->xres)
609                         var->xres_virtual -= 8;
610                 else
611                         return -EINVAL;
612         }
613
614         switch (bpp) {
615         case 8:
616                 var->red.offset = 0;
617                 var->green.offset = 0;
618                 var->blue.offset = 0;
619                 var->red.length = 6;
620                 var->green.length = 6;
621                 var->blue.length = 6;
622                 break;
623         case 16:
624                 var->red.offset = 11;
625                 var->green.offset = 5;
626                 var->blue.offset = 0;
627                 var->red.length = 5;
628                 var->green.length = 6;
629                 var->blue.length = 5;
630                 break;
631         case 32:
632                 var->red.offset = 16;
633                 var->green.offset = 8;
634                 var->blue.offset = 0;
635                 var->red.length = 8;
636                 var->green.length = 8;
637                 var->blue.length = 8;
638                 break;
639         default:
640                 return -EINVAL;
641         }
642
643         return 0;
644 }
645
646 //=====================================================================
647 //
648 // Pan the display
649 //
650 // The datasheets defines crt start address to be 20 bits wide and
651 // to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
652 // CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
653 // it, so it is also safe to be used here. BTW: datasheet CR0E on page
654 // 90 really is CR1E, the real CRE is documented on page 72.
655 //
656 // BUT:
657 //
658 // As of internal version 0.60 we do not use vga panning any longer.
659 // Vga panning did not allow us the use of all available video memory
660 // and thus prevented ywrap scrolling. We do use the "right view"
661 // register now.
662 //
663 //
664 //=====================================================================
665
666 static int cyblafb_pan_display(struct fb_var_screeninfo *var,
667                                struct fb_info *info)
668 {
669         KD_GRAPHICS_RETURN(0);
670
671         info->var.xoffset = var->xoffset;
672         info->var.yoffset = var->yoffset;
673         out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset *
674                     var->xres_virtual)) * var->bits_per_pixel / 32));
675         return 0;
676 }
677
678 //============================================
679 //
680 // This will really help in case of a bug ...
681 // dump most gaphics core registers.
682 //
683 //============================================
684
685 static void regdump(struct cyblafb_par *par)
686 {
687         int i;
688
689         if (verbosity < 2)
690                 return;
691
692         printk("\n");
693         for (i = 0; i <= 0xff; i++) {
694                 outb(i, 0x3d4);
695                 printk("CR%02x=%02x ", i, inb(0x3d5));
696                 if (i % 16 == 15)
697                         printk("\n");
698         }
699
700         outb(0x30, 0x3ce);
701         outb(inb(0x3cf) | 0x40, 0x3cf);
702         for (i = 0; i <= 0x1f; i++) {
703                 if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11
704                     || i == 0x16) {
705                         outb(i, 0x3d4);
706                         printk("CR%02x=%02x ", i, inb(0x3d5));
707                 } else
708                         printk("------- ");
709                 if (i % 16 == 15)
710                         printk("\n");
711         }
712         outb(0x30, 0x3ce);
713         outb(inb(0x3cf) & 0xbf, 0x3cf);
714
715         printk("\n");
716         for (i = 0; i <= 0x7f; i++) {
717                 outb(i, 0x3ce);
718                 printk("GR%02x=%02x ", i, inb(0x3cf));
719                 if (i % 16 == 15)
720                         printk("\n");
721         }
722
723         printk("\n");
724         for (i = 0; i <= 0xff; i++) {
725                 outb(i, 0x3c4);
726                 printk("SR%02x=%02x ", i, inb(0x3c5));
727                 if (i % 16 == 15)
728                         printk("\n");
729         }
730
731         printk("\n");
732         for (i = 0; i <= 0x1F; i++) {
733                 inb(0x3da);     // next access is index!
734                 outb(i, 0x3c0);
735                 printk("AR%02x=%02x ", i, inb(0x3c1));
736                 if (i % 16 == 15)
737                         printk("\n");
738         }
739         printk("\n");
740
741         inb(0x3DA);             // reset internal flag to 3c0 index
742         outb(0x20, 0x3C0);      // enable attr
743
744         return;
745 }
746
747 //=======================================================================
748 //
749 // Save State
750 //
751 // This function is called while a switch to KD_TEXT is in progress,
752 // before any of the other functions are called.
753 //
754 //=======================================================================
755
756 static void cyblafb_save_state(struct fb_info *info)
757 {
758         struct cyblafb_par *par = info->par;
759         if (verbosity > 0)
760                 output("Switching to KD_TEXT\n");
761         disabled = 0;
762         regdump(par);
763         enable_mmio();
764         return;
765 }
766
767 //=======================================================================
768 //
769 // Restore State
770 //
771 // This function is called while a switch to KD_GRAPHICS is in progress,
772 // We have to turn on vga style panning registers again because the
773 // trident driver of X does not know about GE10.
774 //
775 //=======================================================================
776
777 static void cyblafb_restore_state(struct fb_info *info)
778 {
779         if (verbosity > 0)
780                 output("Switching to KD_GRAPHICS\n");
781         out32(GE10, 0);
782         disabled = 1;
783         return;
784 }
785
786 //======================================
787 //
788 // Set hardware to requested video mode
789 //
790 //======================================
791
792 static int cyblafb_set_par(struct fb_info *info)
793 {
794         struct cyblafb_par *par = info->par;
795         u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart,
796             hblankend, preendfetch, vtotal, vdispend, vsyncstart,
797             vsyncend, vblankstart, vblankend;
798         struct fb_var_screeninfo *var = &info->var;
799         int bpp = var->bits_per_pixel;
800         int i;
801
802         KD_GRAPHICS_RETURN(0);
803
804         if (verbosity > 0)
805                 output("Switching to new mode: "
806                        "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
807                        var->xres, var->yres, var->xres_virtual,
808                        var->yres_virtual, var->bits_per_pixel, var->pixclock,
809                        var->left_margin, var->right_margin, var->upper_margin,
810                        var->lower_margin, var->hsync_len, var->vsync_len);
811
812         htotal = (var->xres + var->left_margin + var->right_margin +
813                   var->hsync_len) / 8 - 5;
814         hdispend = var->xres / 8 - 1;
815         hsyncstart = (var->xres + var->right_margin) / 8;
816         hsyncend = var->hsync_len / 8;
817         hblankstart = hdispend + 1;
818         hblankend = htotal + 3; // should be htotal + 5, bios does it this way
819         preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3);
820
821         vtotal = var->yres + var->upper_margin + var->lower_margin +
822                                                         var->vsync_len - 2;
823         vdispend = var->yres - 1;
824         vsyncstart = var->yres + var->lower_margin;
825         vblankstart = var->yres;
826         vblankend = vtotal; // should be vtotal + 2, but bios does it this way
827         vsyncend = var->vsync_len;
828
829         enable_mmio();          // necessary! ... check X ...
830
831         write3X4(CR11, read3X4(CR11) & 0x7F);   // unlock cr00 .. cr07
832
833         write3CE(GR30, 8);
834
835         if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
836
837                 // stretch or center ?
838
839                 out8(0x3C2, 0xEB);
840
841                 write3CE(GR30, read3CE(GR30) | 0x81);   // shadow mode on
842
843                 if (center) {
844                         write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80);
845                         write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80);
846                 } else if (stretch) {
847                         write3CE(GR5D, 0);
848                         write3CE(GR52, (read3CE(GR52) & 0x7C) | 1);
849                         write3CE(GR53, (read3CE(GR53) & 0x7C) | 1);
850                 }
851
852         } else {
853                 out8(0x3C2, 0x2B);
854                 write3CE(GR30, 8);
855         }
856
857         //
858         // Setup CRxx regs
859         //
860
861         write3X4(CR00, htotal & 0xFF);
862         write3X4(CR01, hdispend & 0xFF);
863         write3X4(CR02, hblankstart & 0xFF);
864         write3X4(CR03, hblankend & 0x1F);
865         write3X4(CR04, hsyncstart & 0xFF);
866         write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
867         write3X4(CR06, vtotal & 0xFF);
868         write3X4(CR07, (vtotal & 0x100) >> 8 |
869                        (vdispend & 0x100) >> 7 |
870                        (vsyncstart & 0x100) >> 6 |
871                        (vblankstart & 0x100) >> 5 |
872                        0x10 |
873                        (vtotal & 0x200) >> 4 |
874                        (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2);
875         write3X4(CR08, 0);
876         write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 |      // FIX !!!
877                        ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
878         write3X4(CR0A, 0);      // Init to some reasonable default
879         write3X4(CR0B, 0);      // Init to some reasonable default
880         write3X4(CR0C, 0);      // Offset 0
881         write3X4(CR0D, 0);      // Offset 0
882         write3X4(CR0E, 0);      // Init to some reasonable default
883         write3X4(CR0F, 0);      // Init to some reasonable default
884         write3X4(CR10, vsyncstart & 0xFF);
885         write3X4(CR11, (vsyncend & 0x0F));
886         write3X4(CR12, vdispend & 0xFF);
887         write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF);
888         write3X4(CR14, 0x40);   // double word mode
889         write3X4(CR15, vblankstart & 0xFF);
890         write3X4(CR16, vblankend & 0xFF);
891         write3X4(CR17, 0xE3);
892         write3X4(CR18, 0xFF);
893         //       CR19: needed for interlaced modes ... ignore it for now
894         write3X4(CR1A, 0x07);   // Arbitration Control Counter 1
895         write3X4(CR1B, 0x07);   // Arbitration Control Counter 2
896         write3X4(CR1C, 0x07);   // Arbitration Control Counter 3
897         write3X4(CR1D, 0x00);   // Don't know, doesn't hurt ; -)
898         write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
899         //       CR1F: do not set, contains BIOS info about memsize
900         write3X4(CR20, 0x20);   // enabe wr buf, disable 16bit planar mode
901         write3X4(CR21, 0x20);   // enable linear memory access
902         //       CR22: RO cpu latch readback
903         //       CR23: ???
904         //       CR24: RO AR flag state
905         //       CR25: RAMDAC rw timing, pclk buffer tristate control ????
906         //       CR26: ???
907         write3X4(CR27, (vdispend & 0x400) >> 6 |
908                        (vsyncstart & 0x400) >> 5 |
909                        (vblankstart & 0x400) >> 4 |
910                        (vtotal & 0x400) >> 3 |
911                        0x8);
912         //       CR28: ???
913         write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual *
914                         bpp) / (4 * 16)) & 0x300) >> 4));
915         write3X4(CR2A, read3X4(CR2A) | 0x40);
916         write3X4(CR2B, (htotal & 0x100) >> 8 |
917                        (hdispend & 0x100) >> 7 |
918                        // (0x00 & 0x100) >> 6 |   hinterlace para bit 8 ???
919                        (hsyncstart & 0x100) >> 5 |
920                        (hblankstart & 0x100) >> 4);
921         //       CR2C: ???
922         //       CR2D: initialized in cyblafb_setup_GE()
923         write3X4(CR2F, 0x92);   // conservative, better signal quality
924         //       CR30: reserved
925         //       CR31: reserved
926         //       CR32: reserved
927         //       CR33: reserved
928         //       CR34: disabled in CR36
929         //       CR35: disabled in CR36
930         //       CR36: initialized in cyblafb_setup_GE
931         //       CR37: i2c, ignore for now
932         write3X4(CR38, (bpp == 8) ? 0x00 :      //
933                        (bpp == 16) ? 0x05 :     // highcolor
934                        (bpp == 24) ? 0x29 :     // packed 24bit truecolor
935                        (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
936         write3X4(CR39, 0x01 |   // MMIO enable
937                        (pcirb ? 0x02 : 0) |     // pci read burst enable
938                        (pciwb ? 0x04 : 0));     // pci write burst enable
939         write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
940                        (pcirr ? 0x40 : 0) |     // pci read retry enable
941                        (pciwr ? 0x80 : 0));     // pci write retry enable
942         write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2
943                                             : 0);
944         write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
945         write3X4(CR58, 0x82);   // Bios does this .... don't know more
946         //
947         // Setup SRxx regs
948         //
949         write3C4(SR00, 3);
950         write3C4(SR01, 1);      //set char clock 8 dots wide
951         write3C4(SR02, 0x0F);   //enable 4 maps needed in chain4 mode
952         write3C4(SR03, 0);      //no character map select
953         write3C4(SR04, 0x0E);   //memory mode: ext mem, even, chain4
954
955         out8(0x3C4, 0x0b);
956         in8(0x3C5);             // Set NEW mode
957         write3C4(SR0D, 0x00);   // test ... check
958
959         set_vclk(par, (bpp == 32 ? 200000000 : 100000000)
960                                         / info->var.pixclock);  //SR18, SR19
961
962         //
963         // Setup GRxx regs
964         //
965         write3CE(GR00, 0x00);   // test ... check
966         write3CE(GR01, 0x00);   // test ... check
967         write3CE(GR02, 0x00);   // test ... check
968         write3CE(GR03, 0x00);   // test ... check
969         write3CE(GR04, 0x00);   // test ... check
970         write3CE(GR05, 0x40);   // no CGA compat, allow 256 col
971         write3CE(GR06, 0x05);   // graphics mode
972         write3CE(GR07, 0x0F);   // planes?
973         write3CE(GR08, 0xFF);   // test ... check
974         write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
975         write3CE(GR20, 0xC0);   // test ... check
976         write3CE(GR2F, 0xA0);   // PCLK = VCLK, no skew,
977
978         //
979         // Setup ARxx regs
980         //
981         for (i = 0; i < 0x10; i++)      // set AR00 .. AR0f
982                 write3C0(i, i);
983         write3C0(AR10, 0x41);   // graphics mode and support 256 color modes
984         write3C0(AR12, 0x0F);   // planes
985         write3C0(AR13, 0);      // horizontal pel panning
986         in8(0x3DA);             // reset internal flag to 3c0 index
987         out8(0x3C0, 0x20);      // enable attr
988
989         //
990         // Setup hidden RAMDAC command register
991         //
992         in8(0x3C8);             // these reads are
993         in8(0x3C6);             // necessary to
994         in8(0x3C6);             // unmask the RAMDAC
995         in8(0x3C6);             // command reg, otherwise
996         in8(0x3C6);             // we would write the pixelmask reg!
997         out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors
998              (bpp == 15) ? 0x10 :       //
999              (bpp == 16) ? 0x30 :       // hicolor
1000              (bpp == 24) ? 0xD0 :       // truecolor
1001              (bpp == 32) ? 0xD0 : 0);   // truecolor
1002         in8(0x3C8);
1003
1004         //
1005         // GR31 is not mentioned in the datasheet
1006         //
1007         if (displaytype == DISPLAY_FP)
1008                 write3CE(GR31, (read3CE(GR31) & 0x8F) |
1009                          ((info->var.yres > 1024) ? 0x50 :
1010                           (info->var.yres > 768) ? 0x30 :
1011                           (info->var.yres > 600) ? 0x20 :
1012                           (info->var.yres > 480) ? 0x10 : 0));
1013
1014         info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
1015                                       : FB_VISUAL_TRUECOLOR;
1016         info->fix.line_length = info->var.xres_virtual * (bpp >> 3);
1017         info->cmap.len = (bpp == 8) ? 256 : 16;
1018
1019         //
1020         // init acceleration engine
1021         //
1022         cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel);
1023
1024         //
1025         // Set/clear flags to allow proper scroll mode selection.
1026         //
1027         if (var->xres == var->xres_virtual)
1028                 info->flags &= ~FBINFO_HWACCEL_XPAN;
1029         else
1030                 info->flags |= FBINFO_HWACCEL_XPAN;
1031
1032         if (var->yres == var->yres_virtual)
1033                 info->flags &= ~FBINFO_HWACCEL_YPAN;
1034         else
1035                 info->flags |= FBINFO_HWACCEL_YPAN;
1036
1037         if (info->fix.smem_len !=
1038             var->xres_virtual * var->yres_virtual * bpp / 8)
1039                 info->flags &= ~FBINFO_HWACCEL_YWRAP;
1040         else
1041                 info->flags |= FBINFO_HWACCEL_YWRAP;
1042
1043         regdump(par);
1044
1045         return 0;
1046 }
1047
1048 //========================
1049 //
1050 // Set one color register
1051 //
1052 //========================
1053
1054 static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
1055                              unsigned blue, unsigned transp,
1056                              struct fb_info *info)
1057 {
1058         int bpp = info->var.bits_per_pixel;
1059
1060         KD_GRAPHICS_RETURN(0);
1061
1062         if (regno >= info->cmap.len)
1063                 return 1;
1064
1065         if (bpp == 8) {
1066                 out8(0x3C6, 0xFF);
1067                 out8(0x3C8, regno);
1068                 out8(0x3C9, red >> 10);
1069                 out8(0x3C9, green >> 10);
1070                 out8(0x3C9, blue >> 10);
1071
1072         } else if (bpp == 16)   // RGB 565
1073                 ((u32 *) info->pseudo_palette)[regno] =
1074                     (red & 0xF800) |
1075                     ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
1076         else if (bpp == 32)     // ARGB 8888
1077                 ((u32 *) info->pseudo_palette)[regno] =
1078                     ((transp & 0xFF00) << 16) |
1079                     ((red & 0xFF00) << 8) |
1080                     ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
1081
1082         return 0;
1083 }
1084
1085 //==========================================================
1086 //
1087 // Try blanking the screen. For flat panels it does nothing
1088 //
1089 //==========================================================
1090
1091 static int cyblafb_blank(int blank_mode, struct fb_info *info)
1092 {
1093         unsigned char PMCont, DPMSCont;
1094
1095         KD_GRAPHICS_RETURN(0);
1096
1097         if (displaytype == DISPLAY_FP)
1098                 return 0;
1099
1100         out8(0x83C8, 0x04);     // DPMS Control
1101         PMCont = in8(0x83C6) & 0xFC;
1102
1103         DPMSCont = read3CE(GR23) & 0xFC;
1104
1105         switch (blank_mode) {
1106         case FB_BLANK_UNBLANK:  // Screen: On, HSync: On, VSync: On
1107         case FB_BLANK_NORMAL:   // Screen: Off, HSync: On, VSync: On
1108                 PMCont |= 0x03;
1109                 DPMSCont |= 0x00;
1110                 break;
1111         case FB_BLANK_HSYNC_SUSPEND:    // Screen: Off, HSync: Off, VSync: On
1112                 PMCont |= 0x02;
1113                 DPMSCont |= 0x01;
1114                 break;
1115         case FB_BLANK_VSYNC_SUSPEND:    // Screen: Off, HSync: On, VSync: Off
1116                 PMCont |= 0x02;
1117                 DPMSCont |= 0x02;
1118                 break;
1119         case FB_BLANK_POWERDOWN:        // Screen: Off, HSync: Off, VSync: Off
1120                 PMCont |= 0x00;
1121                 DPMSCont |= 0x03;
1122                 break;
1123         }
1124
1125         write3CE(GR23, DPMSCont);
1126         out8(0x83C8, 4);
1127         out8(0x83C6, PMCont);
1128         //
1129         // let fbcon do a softblank for us
1130         //
1131         return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1132 }
1133
1134 static struct fb_ops cyblafb_ops __devinitdata = {
1135         .owner = THIS_MODULE,
1136         .fb_setcolreg = cyblafb_setcolreg,
1137         .fb_pan_display = cyblafb_pan_display,
1138         .fb_blank = cyblafb_blank,
1139         .fb_check_var = cyblafb_check_var,
1140         .fb_set_par = cyblafb_set_par,
1141         .fb_fillrect = cyblafb_fillrect,
1142         .fb_copyarea = cyblafb_copyarea,
1143         .fb_imageblit = cyblafb_imageblit,
1144         .fb_sync = cyblafb_sync,
1145         .fb_restore_state = cyblafb_restore_state,
1146         .fb_save_state = cyblafb_save_state,
1147 };
1148
1149 //==========================================================================
1150 //
1151 // getstartupmode() decides about the inital video mode
1152 //
1153 // There is no reason to use modedb, a lot of video modes there would
1154 // need altered timings to display correctly. So I decided that it is much
1155 // better to provide a limited optimized set of modes plus the option of
1156 // using the mode in effect at startup time (might be selected using the
1157 // vga=??? paramter). After that the user might use fbset to select any
1158 // mode he likes, check_var will not try to alter geometry parameters as
1159 // it would be necessary otherwise.
1160 //
1161 //==========================================================================
1162
1163 static int __devinit getstartupmode(struct fb_info *info)
1164 {
1165         u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend,
1166             vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend,
1167             cr00, cr01, cr02, cr03, cr04, cr05, cr2b,
1168             cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27,
1169             cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i;
1170
1171         struct modus {
1172                 int xres; int vxres; int yres; int vyres;
1173                 int bpp; int pxclk;
1174                 int left_margin; int right_margin;
1175                 int upper_margin; int lower_margin;
1176                 int hsync_len; int vsync_len;
1177         } modedb[5] = {
1178                 {
1179                 0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
1180                 640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
1181                 800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
1182                 1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
1183                 1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
1184         };
1185
1186         outb(0x00, 0x3d4); cr00 = inb(0x3d5);
1187         outb(0x01, 0x3d4); cr01 = inb(0x3d5);
1188         outb(0x02, 0x3d4); cr02 = inb(0x3d5);
1189         outb(0x03, 0x3d4); cr03 = inb(0x3d5);
1190         outb(0x04, 0x3d4); cr04 = inb(0x3d5);
1191         outb(0x05, 0x3d4); cr05 = inb(0x3d5);
1192         outb(0x06, 0x3d4); cr06 = inb(0x3d5);
1193         outb(0x07, 0x3d4); cr07 = inb(0x3d5);
1194         outb(0x09, 0x3d4); cr09 = inb(0x3d5);
1195         outb(0x10, 0x3d4); cr10 = inb(0x3d5);
1196         outb(0x11, 0x3d4); cr11 = inb(0x3d5);
1197         outb(0x12, 0x3d4); cr12 = inb(0x3d5);
1198         outb(0x15, 0x3d4); cr15 = inb(0x3d5);
1199         outb(0x16, 0x3d4); cr16 = inb(0x3d5);
1200         outb(0x27, 0x3d4); cr27 = inb(0x3d5);
1201         outb(0x2b, 0x3d4); cr2b = inb(0x3d5);
1202         outb(0x38, 0x3d4); cr38 = inb(0x3d5);
1203
1204         outb(0x0b, 0x3c4);
1205         inb(0x3c5);
1206
1207         outb(0x0d, 0x3c4); sr0d = inb(0x3c5);
1208         outb(0x18, 0x3c4); sr18 = inb(0x3c5);
1209         outb(0x19, 0x3c4); sr19 = inb(0x3c5);
1210         outb(0x0f, 0x3ce); gr0f = inb(0x3cf);
1211
1212         htotal = cr00 | (cr2b & 0x01) << 8;
1213         hdispend = cr01 | (cr2b & 0x02) << 7;
1214         hblankstart = cr02 | (cr2b & 0x10) << 4;
1215         hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
1216         hsyncstart = cr04 | (cr2b & 0x08) << 5;
1217         hsyncend = cr05 & 0x1f;
1218
1219         modedb[0].xres = hblankstart * 8;
1220         modedb[0].hsync_len = hsyncend * 8;
1221         modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
1222         modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
1223             modedb[0].right_margin - modedb[0].hsync_len;
1224
1225         vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
1226             | (cr27 & 0x80) << 3;
1227         vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
1228             | (cr27 & 0x10) << 6;
1229         vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
1230             | (cr27 & 0x20) << 5;
1231         vsyncend = cr11 & 0x0f;
1232         vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
1233             | (cr27 & 0x40) << 4;
1234         vblankend = cr16;
1235
1236         modedb[0].yres = vdispend + 1;
1237         modedb[0].vsync_len = vsyncend;
1238         modedb[0].lower_margin = vsyncstart - modedb[0].yres;
1239         modedb[0].upper_margin = vtotal - modedb[0].yres -
1240             modedb[0].lower_margin - modedb[0].vsync_len + 2;
1241
1242         tmp = cr38 & 0x3c;
1243         modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
1244             tmp == 8 ? 32 : 8;
1245
1246         fi = ((5864727 * (sr18 + 8)) /
1247               (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12;
1248         pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
1249         tmp = sr0d & 0x06;
1250         vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
1251         modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;
1252
1253         if (verbosity > 0)
1254                 output("detected startup mode: "
1255                        "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
1256                        modedb[0].xres, modedb[0].yres, modedb[0].xres,
1257                        modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin,
1258                        modedb[0].right_margin, modedb[0].upper_margin,
1259                        modedb[0].lower_margin, modedb[0].hsync_len,
1260                        modedb[0].vsync_len);
1261
1262         //
1263         // We use this goto target in case of a failed check_var. No, I really
1264         // do not want to do it in another way!
1265         //
1266
1267       tryagain:
1268
1269         i = (mode == NULL) ? 0 :
1270             !strncmp(mode, "640x480", 7) ? 1 :
1271             !strncmp(mode, "800x600", 7) ? 2 :
1272             !strncmp(mode, "1024x768", 8) ? 3 :
1273             !strncmp(mode, "1280x1024", 9) ? 4 : 0;
1274
1275         ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
1276
1277         if (i == 0) {
1278                 info->var.pixclock = modedb[i].pxclk;
1279                 info->var.bits_per_pixel = modedb[i].bpp;
1280         } else {
1281                 info->var.pixclock = (100000000 /
1282                                       ((modedb[i].left_margin +
1283                                         modedb[i].xres +
1284                                         modedb[i].right_margin +
1285                                         modedb[i].hsync_len) *
1286                                        (modedb[i].upper_margin +
1287                                         modedb[i].yres +
1288                                         modedb[i].lower_margin +
1289                                         modedb[i].vsync_len) * ref / 10000));
1290                 info->var.bits_per_pixel = bpp;
1291         }
1292
1293         info->var.left_margin = modedb[i].left_margin;
1294         info->var.right_margin = modedb[i].right_margin;
1295         info->var.xres = modedb[i].xres;
1296         if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32))
1297                 info->var.xres_virtual = modedb[i].vxres;
1298         else
1299                 info->var.xres_virtual = modedb[i].xres;
1300         info->var.xoffset = 0;
1301         info->var.hsync_len = modedb[i].hsync_len;
1302         info->var.upper_margin = modedb[i].upper_margin;
1303         info->var.yres = modedb[i].yres;
1304         info->var.yres_virtual = modedb[i].vyres;
1305         info->var.yoffset = 0;
1306         info->var.lower_margin = modedb[i].lower_margin;
1307         info->var.vsync_len = modedb[i].vsync_len;
1308         info->var.sync = 0;
1309         info->var.vmode = FB_VMODE_NONINTERLACED;
1310
1311         if (cyblafb_check_var(&info->var, info)) {
1312                 // 640x480 - 8@75 should really never fail. One case would
1313                 // be fp == 1 and nativex < 640 ... give up then
1314                 if (i == 1 && bpp == 8 && ref == 75) {
1315                         output("Can't find a valid mode :-(\n");
1316                         return -EINVAL;
1317                 }
1318                 // Our detected mode is unlikely to fail. If it does,
1319                 // try 640x480 - 8@75 ...
1320                 if (i == 0) {
1321                         mode = "640x480";
1322                         bpp = 8;
1323                         ref = 75;
1324                         output("Detected mode failed check_var! "
1325                                "Trying 640x480 - 8@75\n");
1326                         goto tryagain;
1327                 }
1328                 // A specified video mode failed for some reason.
1329                 // Try the startup mode first
1330                 output("Specified mode '%s' failed check! "
1331                        "Falling back to startup mode.\n", mode);
1332                 mode = NULL;
1333                 goto tryagain;
1334         }
1335
1336         return 0;
1337 }
1338
1339 //========================================================
1340 //
1341 // Detect activated memory size. Undefined values require
1342 // memsize parameter.
1343 //
1344 //========================================================
1345
1346 static unsigned int __devinit get_memsize(void)
1347 {
1348         unsigned char tmp;
1349         unsigned int k;
1350
1351         if (memsize)
1352                 k = memsize * Kb;
1353         else {
1354                 tmp = read3X4(CR1F) & 0x0F;
1355                 switch (tmp) {
1356                 case 0x03:
1357                         k = 1 * 1024 * 1024;
1358                         break;
1359                 case 0x07:
1360                         k = 2 * 1024 * 1024;
1361                         break;
1362                 case 0x0F:
1363                         k = 4 * 1024 * 1024;
1364                         break;
1365                 case 0x04:
1366                         k = 8 * 1024 * 1024;
1367                         break;
1368                 default:
1369                         k = 1 * 1024 * 1024;
1370                         output("Unknown memory size code %x in CR1F."
1371                                " We default to 1 Mb for now, please"
1372                                " do provide a memsize parameter!\n", tmp);
1373                 }
1374         }
1375
1376         if (verbosity > 0)
1377                 output("framebuffer size = %d Kb\n", k / Kb);
1378         return k;
1379 }
1380
1381 //=========================================================
1382 //
1383 // Detect if a flat panel monitor connected to the special
1384 // interface is active. Override is possible by fp and crt
1385 // parameters.
1386 //
1387 //=========================================================
1388
1389 static unsigned int __devinit get_displaytype(void)
1390 {
1391         if (fp)
1392                 return DISPLAY_FP;
1393         if (crt)
1394                 return DISPLAY_CRT;
1395         return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
1396 }
1397
1398 //=====================================
1399 //
1400 // Get native resolution of flat panel
1401 //
1402 //=====================================
1403
1404 static int __devinit get_nativex(void)
1405 {
1406         int x, y, tmp;
1407
1408         if (nativex)
1409                 return nativex;
1410
1411         tmp = (read3CE(GR52) >> 4) & 3;
1412
1413         switch (tmp) {
1414         case 0: x = 1280; y = 1024;
1415                 break;
1416         case 2: x = 1024; y = 768;
1417                 break;
1418         case 3: x = 800;  y = 600;
1419                 break;
1420         case 4: x = 1400; y = 1050;
1421                 break;
1422         case 1:
1423         default:
1424                 x = 640; y = 480;
1425                 break;
1426         }
1427
1428         if (verbosity > 0)
1429                 output("%dx%d flat panel found\n", x, y);
1430         return x;
1431 }
1432
1433 static int __devinit cybla_pci_probe(struct pci_dev *dev,
1434                                      const struct pci_device_id *id)
1435 {
1436         struct fb_info *info;
1437         struct cyblafb_par *par;
1438
1439         info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev);
1440         if (!info)
1441                 goto errout_alloc_info;
1442
1443         info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL);
1444         if (!info->pixmap.addr) {
1445                 output("allocation of pixmap buffer failed!\n");
1446                 goto errout_alloc_pixmap;
1447         }
1448         info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4;
1449         info->pixmap.buf_align = 4;
1450         info->pixmap.access_align = 32;
1451         info->pixmap.flags = FB_PIXMAP_SYSTEM;
1452         info->pixmap.scan_align = 4;
1453
1454         par = info->par;
1455         par->ops = cyblafb_ops;
1456
1457         info->fix = cyblafb_fix;
1458         info->fbops = &par->ops;
1459         info->fix = cyblafb_fix;
1460
1461         if (pci_enable_device(dev)) {
1462                 output("could not enable device!\n");
1463                 goto errout_enable;
1464         }
1465         // might already be requested by vga console or vesafb,
1466         // so we do care about success
1467         if (!request_region(0x3c0, 0x20, "cyblafb")) {
1468                 output("region 0x3c0/0x20 already reserved\n");
1469                 vesafb |= 1;
1470
1471         }
1472         //
1473         // Graphics Engine Registers
1474         //
1475         if (!request_region(GEBase, 0x100, "cyblafb")) {
1476                 output("region %#x/0x100 already reserved\n", GEBase);
1477                 vesafb |= 2;
1478         }
1479
1480         regdump(par);
1481
1482         enable_mmio();
1483
1484         // setup MMIO region
1485         info->fix.mmio_start = pci_resource_start(dev, 1);
1486         info->fix.mmio_len = 0x20000;
1487
1488         if (!request_mem_region(info->fix.mmio_start,
1489                                 info->fix.mmio_len, "cyblafb")) {
1490                 output("request_mem_region failed for mmio region!\n");
1491                 goto errout_mmio_reqmem;
1492         }
1493
1494         io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
1495
1496         if (!io_virt) {
1497                 output("ioremap failed for mmio region\n");
1498                 goto errout_mmio_remap;
1499         }
1500         // setup framebuffer memory ... might already be requested
1501         // by vesafb. Not to fail in case of an unsuccessful request
1502         // is useful if both are loaded.
1503         info->fix.smem_start = pci_resource_start(dev, 0);
1504         info->fix.smem_len = get_memsize();
1505
1506         if (!request_mem_region(info->fix.smem_start,
1507                                 info->fix.smem_len, "cyblafb")) {
1508                 output("region %#lx/%#x already reserved\n",
1509                        info->fix.smem_start, info->fix.smem_len);
1510                 vesafb |= 4;
1511         }
1512
1513         info->screen_base = ioremap_nocache(info->fix.smem_start,
1514                                             info->fix.smem_len);
1515
1516         if (!info->screen_base) {
1517                 output("ioremap failed for smem region\n");
1518                 goto errout_smem_remap;
1519         }
1520
1521         displaytype = get_displaytype();
1522
1523         if (displaytype == DISPLAY_FP)
1524                 nativex = get_nativex();
1525
1526         info->flags = FBINFO_DEFAULT
1527                     | FBINFO_HWACCEL_COPYAREA
1528                     | FBINFO_HWACCEL_FILLRECT
1529                     | FBINFO_HWACCEL_IMAGEBLIT
1530                     | FBINFO_READS_FAST
1531 //                  | FBINFO_PARTIAL_PAN_OK
1532                     | FBINFO_MISC_ALWAYS_SETPAR;
1533
1534         info->pseudo_palette = par->pseudo_pal;
1535
1536         if (getstartupmode(info))
1537                 goto errout_findmode;
1538
1539         fb_alloc_cmap(&info->cmap, 256, 0);
1540
1541         if (register_framebuffer(info)) {
1542                 output("Could not register CyBla framebuffer\n");
1543                 goto errout_register;
1544         }
1545
1546         pci_set_drvdata(dev, info);
1547
1548         //
1549         // normal exit and error paths
1550         //
1551
1552         return 0;
1553
1554       errout_register:
1555       errout_findmode:
1556         iounmap(info->screen_base);
1557       errout_smem_remap:
1558         if (!(vesafb & 4))
1559                 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1560         iounmap(io_virt);
1561       errout_mmio_remap:
1562         release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1563       errout_mmio_reqmem:
1564         if (!(vesafb & 1))
1565                 release_region(0x3c0, 32);
1566       errout_enable:
1567         kfree(info->pixmap.addr);
1568       errout_alloc_pixmap:
1569         framebuffer_release(info);
1570       errout_alloc_info:
1571         output("CyblaFB version %s aborting init.\n", VERSION);
1572         return -ENODEV;
1573 }
1574
1575 static void __devexit cybla_pci_remove(struct pci_dev *dev)
1576 {
1577         struct fb_info *info = pci_get_drvdata(dev);
1578
1579         unregister_framebuffer(info);
1580         iounmap(io_virt);
1581         iounmap(info->screen_base);
1582         if (!(vesafb & 4))
1583                 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1584         release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1585         fb_dealloc_cmap(&info->cmap);
1586         if (!(vesafb & 2))
1587                 release_region(GEBase, 0x100);
1588         if (!(vesafb & 1))
1589                 release_region(0x3c0, 32);
1590         kfree(info->pixmap.addr);
1591         framebuffer_release(info);
1592         output("CyblaFB version %s normal exit.\n", VERSION);
1593 }
1594
1595 //
1596 // List of boards that we are trying to support
1597 //
1598 static struct pci_device_id cybla_devices[] = {
1599         {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1600         {0,}
1601 };
1602
1603 MODULE_DEVICE_TABLE(pci, cybla_devices);
1604
1605 static struct pci_driver cyblafb_pci_driver = {
1606         .name = "cyblafb",
1607         .id_table = cybla_devices,
1608         .probe = cybla_pci_probe,
1609         .remove = __devexit_p(cybla_pci_remove)
1610 };
1611
1612 //=============================================================
1613 //
1614 // kernel command line example:
1615 //
1616 //      video=cyblafb:1280x1024, bpp=16, ref=50 ...
1617 //
1618 // modprobe command line example:
1619 //
1620 //      modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
1621 //
1622 //=============================================================
1623
1624 static int __devinit cyblafb_init(void)
1625 {
1626 #ifndef MODULE
1627         char *options = NULL;
1628         char *opt;
1629
1630         if (fb_get_options("cyblafb", &options))
1631                 return -ENODEV;
1632
1633         if (options && *options)
1634                 while ((opt = strsep(&options, ",")) != NULL) {
1635                         if (!*opt)
1636                                 continue;
1637                         else if (!strncmp(opt, "bpp=", 4))
1638                                 bpp = simple_strtoul(opt + 4, NULL, 0);
1639                         else if (!strncmp(opt, "ref=", 4))
1640                                 ref = simple_strtoul(opt + 4, NULL, 0);
1641                         else if (!strncmp(opt, "fp", 2))
1642                                 displaytype = DISPLAY_FP;
1643                         else if (!strncmp(opt, "crt", 3))
1644                                 displaytype = DISPLAY_CRT;
1645                         else if (!strncmp(opt, "nativex=", 8))
1646                                 nativex = simple_strtoul(opt + 8, NULL, 0);
1647                         else if (!strncmp(opt, "center", 6))
1648                                 center = 1;
1649                         else if (!strncmp(opt, "stretch", 7))
1650                                 stretch = 1;
1651                         else if (!strncmp(opt, "pciwb=", 6))
1652                                 pciwb = simple_strtoul(opt + 6, NULL, 0);
1653                         else if (!strncmp(opt, "pcirb=", 6))
1654                                 pcirb = simple_strtoul(opt + 6, NULL, 0);
1655                         else if (!strncmp(opt, "pciwr=", 6))
1656                                 pciwr = simple_strtoul(opt + 6, NULL, 0);
1657                         else if (!strncmp(opt, "pcirr=", 6))
1658                                 pcirr = simple_strtoul(opt + 6, NULL, 0);
1659                         else if (!strncmp(opt, "memsize=", 8))
1660                                 memsize = simple_strtoul(opt + 8, NULL, 0);
1661                         else if (!strncmp(opt, "verbosity=", 10))
1662                                 verbosity = simple_strtoul(opt + 10, NULL, 0);
1663                         else
1664                                 mode = opt;
1665                 }
1666 #endif
1667         output("CyblaFB version %s initializing\n", VERSION);
1668         return pci_register_driver(&cyblafb_pci_driver);
1669 }
1670
1671 static void __exit cyblafb_exit(void)
1672 {
1673         pci_unregister_driver(&cyblafb_pci_driver);
1674 }
1675
1676 module_init(cyblafb_init);
1677 module_exit(cyblafb_exit);
1678
1679 MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
1680 MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
1681 MODULE_LICENSE("GPL");