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