Merge branch 'upstream'
[linux-2.6] / 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                 const char *p = image->data + index;
414                 for(i=0;i<width_dds;i++) {
415                         out32(GE9C,*(u32*)p);
416                         p+=4;
417                         index+=4;
418                 }
419                 switch(width_dbs) {
420                 case 0: break;
421                 case 8: out32(GE9C,*(u8*)p);
422                         index+=1;
423                         break;
424                 case 16: out32(GE9C,*(u16*)p);
425                         index+=2;
426                         break;
427                 case 24: out32(GE9C,*(u16*)p | *(u8*)(p+2)<<16);
428                         index+=3;
429                         break;
430                 }
431         }
432 }
433
434 //==========================================================
435 //
436 // Check if video mode is acceptable. We change var->??? if
437 // video mode is slightly off or return error otherwise.
438 // info->??? must not be changed!
439 //
440 //==========================================================
441
442 static int cyblafb_check_var(struct fb_var_screeninfo *var,
443                              struct fb_info *info)
444 {
445         int bpp = var->bits_per_pixel;
446         int s,t,maxvyres;
447
448         //
449         // we try to support 8, 16, 24 and 32 bpp modes,
450         // default to 8
451         //
452         // there is a 24 bpp mode, but for now we change requests to 32 bpp
453         // (This is what tridentfb does ... will be changed in the future)
454         //
455         //
456         if ( bpp % 8 != 0 || bpp < 8 || bpp >32)
457                 bpp = 8;
458         if (bpp == 24 )
459                 bpp = var->bits_per_pixel = 32;
460
461         //
462         // interlaced modes are broken, fail if one is requested
463         //
464         if (var->vmode & FB_VMODE_INTERLACED)
465                 return -EINVAL;
466
467         //
468         // fail if requested resolution is higher than physical
469         // flatpanel resolution
470         //
471         if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
472                 return -EINVAL;
473
474         //
475         // xres != xres_virtual is broken, fail if such an
476         // unusual mode is requested
477         //
478         if (var->xres != var->xres_virtual)
479                 return -EINVAL;
480
481         //
482         // we do not allow vclk to exceed 230 MHz
483         //
484         if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000)
485                 return -EINVAL;
486
487         //
488         // calc max yres_virtual that would fit in memory
489         // and max yres_virtual that could be used for scrolling
490         // and use minimum of the results as maxvyres
491         //
492         // adjust vyres_virtual to maxvyres if necessary
493         // fail if requested yres is bigger than maxvyres
494         //
495         s = (0x1fffff / (var->xres * bpp/8)) + var->yres;
496         t = info->fix.smem_len / (var->xres * bpp/8);
497         maxvyres = t < s ? t : s;
498         if (maxvyres < var->yres_virtual)
499                 var->yres_virtual=maxvyres;
500         if (maxvyres < var->yres)
501                 return -EINVAL;
502
503         switch (bpp) {
504                 case 8:
505                         var->red.offset = 0;
506                         var->green.offset = 0;
507                         var->blue.offset = 0;
508                         var->red.length = 6;
509                         var->green.length = 6;
510                         var->blue.length = 6;
511                         break;
512                 case 16:
513                         var->red.offset = 11;
514                         var->green.offset = 5;
515                         var->blue.offset = 0;
516                         var->red.length = 5;
517                         var->green.length = 6;
518                         var->blue.length = 5;
519                         break;
520                 case 32:
521                         var->red.offset = 16;
522                         var->green.offset = 8;
523                         var->blue.offset = 0;
524                         var->red.length = 8;
525                         var->green.length = 8;
526                         var->blue.length = 8;
527                         break;
528                 default:
529                         return -EINVAL;
530         }
531
532         return 0;
533
534 }
535
536 //=====================================================================
537 //
538 // Pan the display
539 //
540 // The datasheets defines crt start address to be 20 bits wide and
541 // to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
542 // CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
543 // it, so it is also safe to be used here. BTW: datasheet CR0E on page
544 // 90 really is CR1E, the real CRE is documented on page 72.
545 //
546 //=====================================================================
547
548 static int cyblafb_pan_display(struct fb_var_screeninfo *var,
549                                struct fb_info *info)
550 {
551         unsigned int offset;
552
553         offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32;
554         info->var.xoffset = var->xoffset;
555         info->var.yoffset = var->yoffset;
556
557         write3X4(CR0D,offset & 0xFF);
558         write3X4(CR0C,(offset & 0xFF00) >> 8);
559         write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11));
560         write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17));
561         write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15));
562
563         return 0;
564 }
565
566 //============================================
567 //
568 // This will really help in case of a bug ...
569 // dump most gaphics core registers.
570 //
571 //============================================
572
573 static void regdump(struct cyblafb_par *par)
574 {
575         int i;
576
577         if (verbosity < 2)
578                 return;
579
580         printk("\n");
581         for(i=0; i<=0xff; i++) {
582                 outb(i,0x3d4);
583                 printk("CR%02x=%02x ",i,inb(0x3d5));
584                 if (i%16==15)
585                         printk("\n");
586         }
587
588         outb(0x30,0x3ce);
589         outb(inb(0x3cf) | 0x40,0x3cf);
590         for(i=0; i<=0x1f; i++) {
591                 if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) {
592                         outb(i,0x3d4);
593                         printk("CR%02x=%02x ",i,inb(0x3d5));
594                 } else
595                         printk("------- ");
596                 if (i%16==15)
597                         printk("\n");
598         }
599         outb(0x30,0x3ce);
600         outb(inb(0x3cf) & 0xbf,0x3cf);
601
602         printk("\n");
603         for(i=0; i<=0x7f; i++) {
604                 outb(i,0x3ce);
605                 printk("GR%02x=%02x ",i,inb(0x3cf));
606                 if (i%16==15)
607                         printk("\n");
608         }
609
610         printk("\n");
611         for(i=0; i<=0xff; i++) {
612                 outb(i,0x3c4);
613                 printk("SR%02x=%02x ",i,inb(0x3c5));
614                 if (i%16==15)
615                         printk("\n");
616         }
617
618         printk("\n");
619         for(i=0; i <= 0x1F; i++) {
620                 inb(0x3da); // next access is index!
621                 outb(i,0x3c0);
622                 printk("AR%02x=%02x ",i,inb(0x3c1));
623                 if (i%16==15)
624                         printk("\n");
625         }
626         printk("\n");
627
628         inb(0x3DA);                     // reset internal flag to 3c0 index
629         outb(0x20,0x3C0);               // enable attr
630
631         return;
632 }
633
634 //======================================
635 //
636 // Set hardware to requested video mode
637 //
638 //======================================
639
640 static int cyblafb_set_par(struct fb_info *info)
641 {
642         struct cyblafb_par *par = info->par;
643         u32
644         htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch,
645                 vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
646         struct fb_var_screeninfo *var = &info->var;
647         int bpp = var->bits_per_pixel;
648         int i;
649
650         if (verbosity > 0)
651                 output("Switching to new mode: "
652                        "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
653                         var->xres,var->yres,var->xres_virtual,
654                         var->yres_virtual,var->bits_per_pixel,var->pixclock,
655                         var->left_margin,var->right_margin,var->upper_margin,
656                         var->lower_margin,var->hsync_len,var->vsync_len);
657
658         htotal = (var->xres + var->left_margin + var->right_margin +
659                                                  var->hsync_len) / 8 - 5;
660         hdispend = var->xres/8 - 1;
661         hsyncstart = (var->xres + var->right_margin)/8;
662         hsyncend = var->hsync_len/8;
663         hblankstart = hdispend + 1;
664         hblankend = htotal + 3; // should be htotal + 5, bios does it this way
665         preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3);
666
667         vtotal = var->yres + var->upper_margin + var->lower_margin +
668                                                  var->vsync_len - 2;
669         vdispend = var->yres - 1;
670         vsyncstart = var->yres + var->lower_margin;
671         vblankstart = var->yres;
672         vblankend = vtotal; // should be vtotal + 2, but bios does it this way
673         vsyncend = var->vsync_len;
674
675         enable_mmio();          // necessary! ... check X ...
676
677         write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
678
679         write3CE(GR30,8);
680
681         if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
682
683                 // stretch or center ?
684
685                 out8(0x3C2,0xEB);
686
687                 write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on
688
689                 if (center) {
690                         write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80);
691                         write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80);
692                 }
693                 else if (stretch) {
694                         write3CE(GR5D,0);
695                         write3CE(GR52,(read3CE(GR52) & 0x7C) | 1);
696                         write3CE(GR53,(read3CE(GR53) & 0x7C) | 1);
697                 }
698
699         } else {
700                 out8(0x3C2,0x2B);
701                 write3CE(GR30,8);
702         }
703
704         //
705         // Setup CRxx regs
706         //
707
708         write3X4(CR00,htotal & 0xFF);
709         write3X4(CR01,hdispend & 0xFF);
710         write3X4(CR02,hblankstart & 0xFF);
711         write3X4(CR03,hblankend & 0x1F);
712         write3X4(CR04,hsyncstart & 0xFF);
713         write3X4(CR05,(hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
714         write3X4(CR06,vtotal & 0xFF);
715         write3X4(CR07,(vtotal & 0x100) >> 8 |
716                       (vdispend & 0x100) >> 7 |
717                       (vsyncstart & 0x100) >> 6 |
718                       (vblankstart & 0x100) >> 5 |
719                       0x10 |
720                       (vtotal & 0x200) >> 4 |
721                       (vdispend & 0x200) >> 3 |
722                       (vsyncstart & 0x200) >> 2);
723         write3X4(CR08,0);
724         write3X4(CR09,(vblankstart & 0x200) >> 4 | 0x40 |  // FIX !!!
725                       ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
726         write3X4(CR0A,0);  // Init to some reasonable default
727         write3X4(CR0B,0);  // Init to some reasonable default
728         write3X4(CR0C,0);  // Offset 0
729         write3X4(CR0D,0);  // Offset 0
730         write3X4(CR0E,0);  // Init to some reasonable default
731         write3X4(CR0F,0);  // Init to some reasonable default
732         write3X4(CR10,vsyncstart & 0xFF);
733         write3X4(CR11,(vsyncend & 0x0F));
734         write3X4(CR12,vdispend & 0xFF);
735         write3X4(CR13,((info->var.xres * bpp)/(4*16)) & 0xFF);
736         write3X4(CR14,0x40);  // double word mode
737         write3X4(CR15,vblankstart & 0xFF);
738         write3X4(CR16,vblankend & 0xFF);
739         write3X4(CR17,0xC3);
740         write3X4(CR18,0xFF);
741         //       CR19: needed for interlaced modes ... ignore it for now
742         write3X4(CR1A,0x07); // Arbitration Control Counter 1
743         write3X4(CR1B,0x07); // Arbitration Control Counter 2
744         write3X4(CR1C,0x07); // Arbitration Control Counter 3
745         write3X4(CR1D,0x00); // Don't know, doesn't hurt ;-)
746         write3X4(CR1E,(info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
747         //       CR1F: do not set, contains BIOS info about memsize
748         write3X4(CR20,0x20); // enabe wr buf, disable 16bit planar mode
749         write3X4(CR21,0x20); // enable linear memory access
750         //       CR22: RO cpu latch readback
751         //       CR23: ???
752         //       CR24: RO AR flag state
753         //       CR25: RAMDAC rw timing, pclk buffer tristate control ????
754         //       CR26: ???
755         write3X4(CR27,(vdispend & 0x400) >> 6 |
756                       (vsyncstart & 0x400) >> 5 |
757                       (vblankstart & 0x400) >> 4 |
758                       (vtotal & 0x400) >> 3 |
759                       0x8);
760         //       CR28: ???
761         write3X4(CR29,(read3X4(CR29) & 0xCF) |
762                       ((((info->var.xres * bpp) / (4*16)) & 0x300) >>4));
763         write3X4(CR2A,read3X4(CR2A) | 0x40);
764         write3X4(CR2B,(htotal & 0x100) >> 8 |
765                       (hdispend & 0x100) >> 7 |
766                       // (0x00 & 0x100) >> 6 |   hinterlace para bit 8 ???
767                       (hsyncstart & 0x100) >> 5 |
768                       (hblankstart & 0x100) >> 4);
769         //       CR2C: ???
770         //       CR2D: initialized in cyblafb_setup_GE()
771         write3X4(CR2F,0x92); // conservative, better signal quality
772         //       CR30: reserved
773         //       CR31: reserved
774         //       CR32: reserved
775         //       CR33: reserved
776         //       CR34: disabled in CR36
777         //       CR35: disabled in CR36
778         //       CR36: initialized in cyblafb_setup_GE
779         //       CR37: i2c, ignore for now
780         write3X4(CR38,(bpp == 8) ? 0x00 :       //
781                       (bpp == 16) ? 0x05 :      // highcolor
782                       (bpp == 24) ? 0x29 :      // packed 24bit truecolor
783                       (bpp == 32) ? 0x09 : 0);  // truecolor, 16 bit pixelbus
784         write3X4(CR39,0x01 |                    // MMIO enable
785                       (pcirb ? 0x02 : 0) | // pci read burst enable
786                       (pciwb ? 0x04 : 0)); // pci write burst enable
787         write3X4(CR55,0x1F | // pci clocks * 2 for STOP# during 1st data phase
788                       (pcirr ? 0x40 : 0) | // pci read retry enable
789                       (pciwr ? 0x80 : 0)); // pci write retry enable
790         write3X4(CR56,preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01)|2 : 0);
791         write3X4(CR57,preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
792         write3X4(CR58,0x82);    // Bios does this .... don't know more
793         //
794         // Setup SRxx regs
795         //
796         write3C4(SR00,3);
797         write3C4(SR01,1);       //set char clock 8 dots wide
798         write3C4(SR02,0x0F);    //enable 4 maps needed in chain4 mode
799         write3C4(SR03,0);       //no character map select
800         write3C4(SR04,0x0E);    //memory mode: ext mem, even, chain4
801
802         out8(0x3C4,0x0b);
803         in8(0x3C5);             // Set NEW mode
804         write3C4(SR0D,0x00);    // test ... check
805
806         set_vclk(par,(bpp==32 ? 200000000 : 100000000)/
807                  info->var.pixclock); //SR18,SR19
808
809         //
810         // Setup GRxx regs
811         //
812         write3CE(GR00,0x00);    // test ... check
813         write3CE(GR01,0x00);    // test ... check
814         write3CE(GR02,0x00);    // test ... check
815         write3CE(GR03,0x00);    // test ... check
816         write3CE(GR04,0x00);    // test ... check
817         write3CE(GR05,0x40);    // no CGA compat,allow 256 col
818         write3CE(GR06,0x05);    // graphics mode
819         write3CE(GR07,0x0F);    // planes?
820         write3CE(GR08,0xFF);    // test ... check
821         write3CE(GR0F,(bpp==32)?0x1A:0x12); // div vclk by 2 if 32bpp, chain4
822         write3CE(GR20,0xC0);    // test ... check
823         write3CE(GR2F,0xA0);    // PCLK = VCLK, no skew,
824
825         //
826         // Setup ARxx regs
827         //
828         for(i = 0;i < 0x10;i++) // set AR00 .. AR0f
829                 write3C0(i,i);
830         write3C0(AR10,0x41);    // graphics mode and support 256 color modes
831         write3C0(AR12,0x0F);    // planes
832         write3C0(AR13,0);       // horizontal pel panning
833         in8(0x3DA);             // reset internal flag to 3c0 index
834         out8(0x3C0,0x20);       // enable attr
835
836         //
837         // Setup hidden RAMDAC command register
838         //
839         in8(0x3C8);  // these reads are
840         in8(0x3C6);  // necessary to
841         in8(0x3C6);  // unmask the RAMDAC
842         in8(0x3C6);  // command reg, otherwise
843         in8(0x3C6);  // we would write the pixelmask reg!
844         out8(0x3C6,(bpp ==  8) ? 0x00 :         // 256 colors
845                    (bpp == 15) ? 0x10 :         //
846                    (bpp == 16) ? 0x30 :         // hicolor
847                    (bpp == 24) ? 0xD0 :         // truecolor
848                    (bpp == 32) ? 0xD0 : 0);     // truecolor
849         in8(0x3C8);
850
851         //
852         // GR31 is not mentioned in the datasheet
853         //
854         if (displaytype == DISPLAY_FP)
855                 write3CE(GR31,(read3CE(GR31) & 0x8F) |
856                          ((info->var.yres > 1024) ? 0x50 :
857                          (info->var.yres >   768) ? 0x30 :
858                          (info->var.yres >   600) ? 0x20 :
859                          (info->var.yres >   480) ? 0x10 : 0));
860
861         info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
862                                       : FB_VISUAL_TRUECOLOR;
863         info->fix.line_length = info->var.xres * (bpp >> 3);
864         info->cmap.len = (bpp == 8) ? 256: 16;
865
866         //
867         // init acceleration engine
868         //
869         cyblafb_setup_GE(info->var.xres,info->var.bits_per_pixel);
870
871         regdump(par);
872
873         return 0;
874 }
875
876 //========================
877 //
878 // Set one color register
879 //
880 //========================
881
882 static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
883                              unsigned blue, unsigned transp,
884                              struct fb_info *info)
885 {
886         int bpp = info->var.bits_per_pixel;
887
888         if (regno >= info->cmap.len)
889                 return 1;
890
891         if (bpp == 8) {
892                 out8(0x3C6,0xFF);
893                 out8(0x3C8,regno);
894                 out8(0x3C9,red>>10);
895                 out8(0x3C9,green>>10);
896                 out8(0x3C9,blue>>10);
897
898         } else if (bpp == 16)                           // RGB 565
899                 ((u32*)info->pseudo_palette)[regno] =
900                         (red & 0xF800) |
901                         ((green & 0xFC00) >> 5) |
902                         ((blue & 0xF800) >> 11);
903         else if (bpp == 32)                             // ARGB 8888
904                 ((u32*)info->pseudo_palette)[regno] =
905                         ((transp & 0xFF00) <<16) |
906                         ((red & 0xFF00) << 8) |
907                         ((green & 0xFF00)) |
908                         ((blue & 0xFF00)>>8);
909
910         return 0;
911 }
912
913 //==========================================================
914 //
915 // Try blanking the screen. For flat panels it does nothing
916 //
917 //==========================================================
918
919 static int cyblafb_blank(int blank_mode, struct fb_info *info)
920 {
921         unsigned char PMCont,DPMSCont;
922
923         if (displaytype == DISPLAY_FP)
924                 return 0;
925
926         out8(0x83C8,0x04);              // DPMS Control
927         PMCont = in8(0x83C6) & 0xFC;
928
929         DPMSCont = read3CE(GR23) & 0xFC;
930
931         switch (blank_mode)
932         {
933         case FB_BLANK_UNBLANK:       // Screen: On, HSync: On, VSync: On
934         case FB_BLANK_NORMAL:        // Screen: Off, HSync: On, VSync: On
935                 PMCont |= 0x03;
936                 DPMSCont |= 0x00;
937                 break;
938         case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
939                 PMCont |= 0x02;
940                 DPMSCont |= 0x01;
941                 break;
942         case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
943                 PMCont |= 0x02;
944                 DPMSCont |= 0x02;
945                 break;
946         case FB_BLANK_POWERDOWN:     // Screen: Off, HSync: Off, VSync: Off
947                 PMCont |= 0x00;
948                 DPMSCont |= 0x03;
949                 break;
950         }
951
952         write3CE(GR23,DPMSCont);
953         out8(0x83C8,4);
954         out8(0x83C6,PMCont);
955         //
956         // let fbcon do a softblank for us
957         //
958         return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
959 }
960
961 static struct fb_ops cyblafb_ops __devinitdata = {
962         .owner  = THIS_MODULE,
963         .fb_setcolreg = cyblafb_setcolreg,
964         .fb_pan_display = cyblafb_pan_display,
965         .fb_blank = cyblafb_blank,
966         .fb_check_var = cyblafb_check_var,
967         .fb_set_par = cyblafb_set_par,
968         .fb_fillrect = cyblafb_fillrect,
969         .fb_copyarea= cyblafb_copyarea,
970         .fb_imageblit = cyblafb_imageblit,
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");