2 * Frame buffer driver for Trident Cyberblade/i1 graphics core
4 * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de>
7 * tridentfb.c by Jani Monoses
8 * see files above for further credits
12 #define CYBLAFB_DEBUG 0
13 #define CYBLAFB_KD_GRAPHICS_QUIRK 1
15 #define CYBLAFB_PIXMAPSIZE 8192
17 #include <linux/module.h>
18 #include <linux/string.h>
20 #include <linux/init.h>
21 #include <linux/pci.h>
22 #include <asm/types.h>
23 #include <video/cyblafb.h>
25 #define VERSION "0.62"
32 static struct fb_fix_screeninfo cyblafb_fix __devinitdata
= {
34 .type
= FB_TYPE_PACKED_PIXELS
,
38 .visual
= FB_VISUAL_PSEUDOCOLOR
,
39 .accel
= FB_ACCEL_NONE
,
42 static char *mode __devinitdata
= NULL
;
43 static int bpp __devinitdata
= 8;
44 static int ref __devinitdata
= 75;
45 static int fp __devinitdata
;
46 static int crt __devinitdata
;
47 static int memsize __devinitdata
;
49 static int basestride
;
60 static int displaytype
;
62 static void __iomem
*io_virt
; // iospace virtual memory address
64 module_param(mode
, charp
, 0);
65 module_param(bpp
, int, 0);
66 module_param(ref
, int, 0);
67 module_param(fp
, int, 0);
68 module_param(crt
, int, 0);
69 module_param(nativex
, int, 0);
70 module_param(center
, int, 0);
71 module_param(stretch
, int, 0);
72 module_param(pciwb
, int, 0);
73 module_param(pcirb
, int, 0);
74 module_param(pciwr
, int, 0);
75 module_param(pcirr
, int, 0);
76 module_param(memsize
, int, 0);
77 module_param(verbosity
, int, 0);
79 //=========================================
81 // Well, we have to fix the upper layers.
82 // Until this has been done, we work around
85 //=========================================
87 #if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
89 printk("********\n");\
94 #elif CYBLAFB_KD_GRAPHICS_QUIRK
95 #define KD_GRAPHICS_RETURN(val)\
100 #define KD_GRAPHICS_RETURN(val)
103 //=========================================
105 // Port access macros for memory mapped io
107 //=========================================
109 #define out8(r, v) writeb(v, io_virt + r)
110 #define out32(r, v) writel(v, io_virt + r)
111 #define in8(r) readb(io_virt + r)
112 #define in32(r) readl(io_virt + r)
114 //======================================
116 // Hardware access inline functions
118 //======================================
120 static inline u8
read3X4(u32 reg
)
126 static inline u8
read3C4(u32 reg
)
132 static inline u8
read3CE(u32 reg
)
138 static inline void write3X4(u32 reg
, u8 val
)
144 static inline void write3C4(u32 reg
, u8 val
)
150 static inline void write3CE(u32 reg
, u8 val
)
156 static inline void write3C0(u32 reg
, u8 val
)
158 in8(0x3DA); // read to reset index
163 //=================================================
165 // Enable memory mapped io and unprotect registers
167 //=================================================
169 static void enable_mmio(void)
174 inb(0x3C5); // Set NEW mode
175 outb(SR0E
, 0x3C4); // write enable a lot of extended ports
178 outb(SR11
, 0x3C4); // write enable those extended ports that
179 outb(0x87, 0x3C5); // are not affected by SR0E_New
181 outb(CR1E
, 0x3d4); // clear write protect bit for port 0x3c2
182 tmp
= inb(0x3d5) & 0xBF;
187 outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
190 //=================================================
192 // Set pixel clock VCLK1
193 // - multipliers set elswhere
194 // - freq in units of 0.01 MHz
196 // Hardware bug: SR18 >= 250 is broken for the
199 //=================================================
201 static void set_vclk(struct cyblafb_par
*par
, int freq
)
208 k
= freq
>= 10000 ? 0 : freq
>= 5000 ? 1 : freq
>= 2500 ? 2 : 3;
209 for (m
= 0; m
< 64; m
++)
210 for (n
= 0; n
< 250; n
++) {
211 fi
= (int)(((5864727 * (n
+ 8)) /
212 ((m
+ 2) * (1 << k
))) >> 12);
213 if ((di
= abs(fi
- freq
)) < d
) {
217 hi
= (u8
) ((k
<< 6) | m
);
223 output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
224 freq
/ 100, freq
% 100, (hi
& 0xc0) >> 6, hi
& 0x3f, lo
);
227 //================================================
229 // Cyberblade specific Graphics Engine (GE) setup
231 //================================================
233 static void cyblafb_setup_GE(int pitch
, int bpp
)
235 KD_GRAPHICS_RETURN();
239 basestride
= ((pitch
>> 3) << 20) | (0 << 29);
242 basestride
= ((pitch
>> 3) << 20) | (5 << 29);
245 basestride
= ((pitch
>> 3) << 20) | (1 << 29);
249 basestride
= ((pitch
>> 3) << 20) | (2 << 29);
253 write3X4(CR36
, 0x90); // reset GE
254 write3X4(CR36
, 0x80); // enable GE
255 out32(GE24
, 1 << 7); // reset all GE pointers by toggling
256 out32(GE24
, 0); // d7 of GE24
257 write3X4(CR2D
, 0x00); // GE Timinigs, no delays
258 out32(GE6C
, 0); // Pattern and Style, p 129, ok
261 //=====================================================================
263 // Cyberblade specific syncing
265 // A timeout might be caused by disabled mmio.
267 // - bit CR39 & 1 == 0 upon return, X trident driver bug
268 // - kdm bug (KD_GRAPHICS not set on first switch)
269 // - kernel design flaw (it believes in the correctness
271 // First we try to sync ignoring that problem, as most of the
272 // time that will succeed immediately and the enable_mmio()
273 // would only degrade performance.
275 //=====================================================================
277 static int cyblafb_sync(struct fb_info
*info
)
279 u32 status
, i
= 100000;
281 KD_GRAPHICS_RETURN(0);
283 while (((status
= in32(GE20
)) & 0xFe800000) && i
!= 0)
289 while (((status
= in32(GE20
)) & 0xFA800000) && i
!= 0)
292 output("GE Timeout, status: %x\n", status
);
293 if (status
& 0x80000000)
294 output("Bresenham Engine : Busy\n");
295 if (status
& 0x40000000)
296 output("Setup Engine : Busy\n");
297 if (status
& 0x20000000)
298 output("SP / DPE : Busy\n");
299 if (status
& 0x10000000)
300 output("Memory Interface : Busy\n");
301 if (status
& 0x08000000)
302 output("Com Lst Proc : Busy\n");
303 if (status
& 0x04000000)
304 output("Block Write : Busy\n");
305 if (status
& 0x02000000)
306 output("Command Buffer : Full\n");
307 if (status
& 0x01000000)
308 output("RESERVED : Busy\n");
309 if (status
& 0x00800000)
310 output("PCI Write Buffer : Busy\n");
311 cyblafb_setup_GE(info
->var
.xres
,
312 info
->var
.bits_per_pixel
);
319 //==============================
321 // Cyberblade specific fillrect
323 //==============================
325 static void cyblafb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*fr
)
327 u32 bpp
= info
->var
.bits_per_pixel
, col
, desty
, height
;
329 KD_GRAPHICS_RETURN();
339 col
= ((u32
*) (info
->pseudo_palette
))[fr
->color
];
343 col
= ((u32
*) (info
->pseudo_palette
))[fr
->color
];
350 out32(GEB8
, basestride
| ((desty
* info
->var
.xres_virtual
*
353 out32(GE48
, fr
->rop
? 0x66 : ROP_S
);
354 out32(GE44
, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
355 out32(GE08
, point(fr
->dx
, 0));
356 out32(GE0C
, point(fr
->dx
+ fr
->width
- 1,
357 height
> 4096 ? 4095 : height
- 1));
358 if (likely(height
<= 4096))
365 //================================================
367 // Cyberblade specific copyarea
369 // This function silently assumes that it never
370 // will be called with width or height exceeding
373 //================================================
375 static void cyblafb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*ca
)
377 u32 s1
, s2
, d1
, d2
, direction
;
379 KD_GRAPHICS_RETURN();
381 s1
= point(ca
->sx
, 0);
382 s2
= point(ca
->sx
+ ca
->width
- 1, ca
->height
- 1);
383 d1
= point(ca
->dx
, 0);
384 d2
= point(ca
->dx
+ ca
->width
- 1, ca
->height
- 1);
386 if ((ca
->sy
> ca
->dy
) || ((ca
->sy
== ca
->dy
) && (ca
->sx
> ca
->dx
)))
391 out32(GEB8
, basestride
| ((ca
->dy
* info
->var
.xres_virtual
*
392 info
->var
.bits_per_pixel
) >> 6));
393 out32(GEC8
, basestride
| ((ca
->sy
* info
->var
.xres_virtual
*
394 info
->var
.bits_per_pixel
) >> 6));
395 out32(GE44
, 0xa0000000 | 1 << 19 | 1 << 2 | direction
);
396 out32(GE00
, direction
? s2
: s1
);
397 out32(GE04
, direction
? s1
: s2
);
398 out32(GE08
, direction
? d2
: d1
);
399 out32(GE0C
, direction
? d1
: d2
);
402 //=======================================================================
404 // Cyberblade specific imageblit
406 // Accelerated for the most usual case, blitting 1 - bit deep
407 // character images. Everything else is passed to the generic imageblit
408 // unless it is so insane that it is better to printk an alert.
410 // Hardware bug: _Never_ blit across pixel column 2048, that will lock
411 // the system. We split those blit requests into three blitting
414 //=======================================================================
416 static void cyblafb_imageblit(struct fb_info
*info
,
417 const struct fb_image
*image
)
420 u32
*pd
= (u32
*) image
->data
;
421 u32 bpp
= info
->var
.bits_per_pixel
;
423 KD_GRAPHICS_RETURN();
425 // Used only for drawing the penguine (image->depth > 1)
426 if (image
->depth
!= 1) {
427 cfb_imageblit(info
, image
);
430 // That should never happen, but it would be fatal
431 if (image
->width
== 0 || image
->height
== 0) {
432 output("imageblit: width/height 0 detected\n");
436 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
437 info
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
) {
438 fgcol
= ((u32
*) (info
->pseudo_palette
))[image
->fg_color
];
439 bgcol
= ((u32
*) (info
->pseudo_palette
))[image
->bg_color
];
441 fgcol
= image
->fg_color
;
442 bgcol
= image
->bg_color
;
450 fgcol
|= fgcol
<< 16;
451 bgcol
|= bgcol
<< 16;
456 out32(GEB8
, basestride
| ((image
->dy
* info
->var
.xres_virtual
*
461 if (!(image
->dx
< 2048 && (image
->dx
+ image
->width
- 1) >= 2048)) {
462 u32 dds
= ((image
->width
+ 31) >> 5) * image
->height
;
463 out32(GE44
, 0xa0000000 | 1 << 20 | 1 << 19);
464 out32(GE08
, point(image
->dx
, 0));
465 out32(GE0C
, point(image
->dx
+ image
->width
- 1,
471 u32 ddstotal
= (image
->width
+ 31) >> 5;
472 u32 ddsleft
= (2048 - image
->dx
+ 31) >> 5;
473 u32 skipleft
= ddstotal
- ddsleft
;
475 out32(GE44
, 0xa0000000 | 1 << 20 | 1 << 19);
476 out32(GE08
, point(image
->dx
, 0));
477 out32(GE0C
, point(2048 - 1, image
->height
- 1));
478 for (i
= 0; i
< image
->height
; i
++) {
479 for (j
= 0; j
< ddsleft
; j
++)
484 if (image
->dx
% 32) {
485 out32(GE44
, 0xa0000000 | 1 << 20 | 1 << 19);
486 out32(GE08
, point(2048, 0));
487 if (image
->width
> ddsleft
<< 5)
488 out32(GE0C
, point(image
->dx
+ (ddsleft
<< 5) -
489 1, image
->height
- 1));
491 out32(GE0C
, point(image
->dx
+ image
->width
- 1,
493 pd
= ((u32
*) image
->data
) + ddstotal
- skipleft
- 1;
494 for (i
= 0; i
< image
->height
; i
++) {
495 out32(GE9C
, swab32(swab32(*pd
) << ((32 -
496 (image
->dx
& 31)) & 31)));
502 out32(GE44
, 0xa0000000 | 1 << 20 | 1 << 19);
503 out32(GE08
, point(image
->dx
+ (ddsleft
<< 5), 0));
504 out32(GE0C
, point(image
->dx
+ image
->width
- 1,
506 pd
= (u32
*) image
->data
;
507 for (i
= 0; i
< image
->height
; i
++) {
509 for (j
= 0; j
< skipleft
; j
++)
516 //==========================================================
518 // Check if video mode is acceptable. We change var->??? if
519 // video mode is slightly off or return error otherwise.
520 // info->??? must not be changed!
522 //==========================================================
524 static int cyblafb_check_var(struct fb_var_screeninfo
*var
,
525 struct fb_info
*info
)
527 int bpp
= var
->bits_per_pixel
;
530 // we try to support 8, 16, 24 and 32 bpp modes,
533 // there is a 24 bpp mode, but for now we change requests to 32 bpp
534 // (This is what tridentfb does ... will be changed in the future)
537 if (bpp
% 8 != 0 || bpp
< 8 || bpp
> 32)
540 bpp
= var
->bits_per_pixel
= 32;
543 // interlaced modes are broken, fail if one is requested
545 if (var
->vmode
& FB_VMODE_INTERLACED
)
549 // fail if requested resolution is higher than physical
550 // flatpanel resolution
552 if ((displaytype
== DISPLAY_FP
) && nativex
&& var
->xres
> nativex
)
556 // we do not allow vclk to exceed 230 MHz. If the requested
557 // vclk is too high, we default to 200 MHz
559 if ((bpp
== 32 ? 200000000 : 100000000) / var
->pixclock
> 23000)
560 var
->pixclock
= (bpp
== 32 ? 200000000 : 100000000) / 20000;
563 // enforce (h|v)sync_len limits
565 var
->hsync_len
&= ~7;
566 if(var
->hsync_len
> 248)
567 var
->hsync_len
= 248;
569 var
->vsync_len
&= 15;
572 // Enforce horizontal and vertical hardware limits.
573 // 1600x1200 is mentioned as a maximum, but higher resolutions could
574 // work with slow refresh, small margins and short sync.
578 if (((var
->xres
+ var
->left_margin
+ var
->right_margin
+
579 var
->hsync_len
) > (bpp
== 32 ? 2040 : 4088)) ||
580 ((var
->yres
+ var
->upper_margin
+ var
->lower_margin
+
581 var
->vsync_len
) > 2047))
584 if ((var
->xres
> 1600) || (var
->yres
> 1200))
585 output("Mode %dx%d exceeds documented limits.\n",
586 var
->xres
, var
->yres
);
588 // try to be smart about (x|y)res_virtual problems.
590 if (var
->xres
> var
->xres_virtual
)
591 var
->xres_virtual
= var
->xres
;
592 if (var
->yres
> var
->yres_virtual
)
593 var
->yres_virtual
= var
->yres
;
595 if (bpp
== 8 || bpp
== 16) {
596 if (var
->xres_virtual
> 4088)
597 var
->xres_virtual
= 4088;
599 if (var
->xres_virtual
> 2040)
600 var
->xres_virtual
= 2040;
602 var
->xres_virtual
&= ~7;
603 while (var
->xres_virtual
* var
->yres_virtual
* bpp
/ 8 >
604 info
->fix
.smem_len
) {
605 if (var
->yres_virtual
> var
->yres
)
607 else if (var
->xres_virtual
> var
->xres
)
608 var
->xres_virtual
-= 8;
616 var
->green
.offset
= 0;
617 var
->blue
.offset
= 0;
619 var
->green
.length
= 6;
620 var
->blue
.length
= 6;
623 var
->red
.offset
= 11;
624 var
->green
.offset
= 5;
625 var
->blue
.offset
= 0;
627 var
->green
.length
= 6;
628 var
->blue
.length
= 5;
631 var
->red
.offset
= 16;
632 var
->green
.offset
= 8;
633 var
->blue
.offset
= 0;
635 var
->green
.length
= 8;
636 var
->blue
.length
= 8;
645 //=====================================================================
649 // The datasheets defines crt start address to be 20 bits wide and
650 // to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
651 // CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
652 // it, so it is also safe to be used here. BTW: datasheet CR0E on page
653 // 90 really is CR1E, the real CRE is documented on page 72.
657 // As of internal version 0.60 we do not use vga panning any longer.
658 // Vga panning did not allow us the use of all available video memory
659 // and thus prevented ywrap scrolling. We do use the "right view"
663 //=====================================================================
665 static int cyblafb_pan_display(struct fb_var_screeninfo
*var
,
666 struct fb_info
*info
)
668 KD_GRAPHICS_RETURN(0);
670 info
->var
.xoffset
= var
->xoffset
;
671 info
->var
.yoffset
= var
->yoffset
;
672 out32(GE10
, 0x80000000 | ((var
->xoffset
+ (var
->yoffset
*
673 var
->xres_virtual
)) * var
->bits_per_pixel
/ 32));
677 //============================================
679 // This will really help in case of a bug ...
680 // dump most gaphics core registers.
682 //============================================
684 static void regdump(struct cyblafb_par
*par
)
692 for (i
= 0; i
<= 0xff; i
++) {
694 printk("CR%02x=%02x ", i
, inb(0x3d5));
700 outb(inb(0x3cf) | 0x40, 0x3cf);
701 for (i
= 0; i
<= 0x1f; i
++) {
702 if (i
== 0 || (i
> 2 && i
< 8) || i
== 0x10 || i
== 0x11
705 printk("CR%02x=%02x ", i
, inb(0x3d5));
712 outb(inb(0x3cf) & 0xbf, 0x3cf);
715 for (i
= 0; i
<= 0x7f; i
++) {
717 printk("GR%02x=%02x ", i
, inb(0x3cf));
723 for (i
= 0; i
<= 0xff; i
++) {
725 printk("SR%02x=%02x ", i
, inb(0x3c5));
731 for (i
= 0; i
<= 0x1F; i
++) {
732 inb(0x3da); // next access is index!
734 printk("AR%02x=%02x ", i
, inb(0x3c1));
740 inb(0x3DA); // reset internal flag to 3c0 index
741 outb(0x20, 0x3C0); // enable attr
746 //=======================================================================
750 // This function is called while a switch to KD_TEXT is in progress,
751 // before any of the other functions are called.
753 //=======================================================================
755 static void cyblafb_save_state(struct fb_info
*info
)
757 struct cyblafb_par
*par
= info
->par
;
759 output("Switching to KD_TEXT\n");
766 //=======================================================================
770 // This function is called while a switch to KD_GRAPHICS is in progress,
771 // We have to turn on vga style panning registers again because the
772 // trident driver of X does not know about GE10.
774 //=======================================================================
776 static void cyblafb_restore_state(struct fb_info
*info
)
779 output("Switching to KD_GRAPHICS\n");
785 //======================================
787 // Set hardware to requested video mode
789 //======================================
791 static int cyblafb_set_par(struct fb_info
*info
)
793 struct cyblafb_par
*par
= info
->par
;
794 u32 htotal
, hdispend
, hsyncstart
, hsyncend
, hblankstart
,
795 hblankend
, preendfetch
, vtotal
, vdispend
, vsyncstart
,
796 vsyncend
, vblankstart
, vblankend
;
797 struct fb_var_screeninfo
*var
= &info
->var
;
798 int bpp
= var
->bits_per_pixel
;
801 KD_GRAPHICS_RETURN(0);
804 output("Switching to new mode: "
805 "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
806 var
->xres
, var
->yres
, var
->xres_virtual
,
807 var
->yres_virtual
, var
->bits_per_pixel
, var
->pixclock
,
808 var
->left_margin
, var
->right_margin
, var
->upper_margin
,
809 var
->lower_margin
, var
->hsync_len
, var
->vsync_len
);
811 htotal
= (var
->xres
+ var
->left_margin
+ var
->right_margin
+
812 var
->hsync_len
) / 8 - 5;
813 hdispend
= var
->xres
/ 8 - 1;
814 hsyncstart
= (var
->xres
+ var
->right_margin
) / 8;
815 hsyncend
= var
->hsync_len
/ 8;
816 hblankstart
= hdispend
+ 1;
817 hblankend
= htotal
+ 3; // should be htotal + 5, bios does it this way
818 preendfetch
= ((var
->xres
>> 3) + 1) * ((bpp
+ 1) >> 3);
820 vtotal
= var
->yres
+ var
->upper_margin
+ var
->lower_margin
+
822 vdispend
= var
->yres
- 1;
823 vsyncstart
= var
->yres
+ var
->lower_margin
;
824 vblankstart
= var
->yres
;
825 vblankend
= vtotal
; // should be vtotal + 2, but bios does it this way
826 vsyncend
= var
->vsync_len
;
828 enable_mmio(); // necessary! ... check X ...
830 write3X4(CR11
, read3X4(CR11
) & 0x7F); // unlock cr00 .. cr07
834 if ((displaytype
== DISPLAY_FP
) && var
->xres
< nativex
) {
836 // stretch or center ?
840 write3CE(GR30
, read3CE(GR30
) | 0x81); // shadow mode on
843 write3CE(GR52
, (read3CE(GR52
) & 0x7C) | 0x80);
844 write3CE(GR53
, (read3CE(GR53
) & 0x7C) | 0x80);
845 } else if (stretch
) {
847 write3CE(GR52
, (read3CE(GR52
) & 0x7C) | 1);
848 write3CE(GR53
, (read3CE(GR53
) & 0x7C) | 1);
860 write3X4(CR00
, htotal
& 0xFF);
861 write3X4(CR01
, hdispend
& 0xFF);
862 write3X4(CR02
, hblankstart
& 0xFF);
863 write3X4(CR03
, hblankend
& 0x1F);
864 write3X4(CR04
, hsyncstart
& 0xFF);
865 write3X4(CR05
, (hsyncend
& 0x1F) | ((hblankend
& 0x20) << 2));
866 write3X4(CR06
, vtotal
& 0xFF);
867 write3X4(CR07
, (vtotal
& 0x100) >> 8 |
868 (vdispend
& 0x100) >> 7 |
869 (vsyncstart
& 0x100) >> 6 |
870 (vblankstart
& 0x100) >> 5 |
872 (vtotal
& 0x200) >> 4 |
873 (vdispend
& 0x200) >> 3 | (vsyncstart
& 0x200) >> 2);
875 write3X4(CR09
, (vblankstart
& 0x200) >> 4 | 0x40 | // FIX !!!
876 ((info
->var
.vmode
& FB_VMODE_DOUBLE
) ? 0x80 : 0));
877 write3X4(CR0A
, 0); // Init to some reasonable default
878 write3X4(CR0B
, 0); // Init to some reasonable default
879 write3X4(CR0C
, 0); // Offset 0
880 write3X4(CR0D
, 0); // Offset 0
881 write3X4(CR0E
, 0); // Init to some reasonable default
882 write3X4(CR0F
, 0); // Init to some reasonable default
883 write3X4(CR10
, vsyncstart
& 0xFF);
884 write3X4(CR11
, (vsyncend
& 0x0F));
885 write3X4(CR12
, vdispend
& 0xFF);
886 write3X4(CR13
, ((info
->var
.xres_virtual
* bpp
) / (4 * 16)) & 0xFF);
887 write3X4(CR14
, 0x40); // double word mode
888 write3X4(CR15
, vblankstart
& 0xFF);
889 write3X4(CR16
, vblankend
& 0xFF);
890 write3X4(CR17
, 0xE3);
891 write3X4(CR18
, 0xFF);
892 // CR19: needed for interlaced modes ... ignore it for now
893 write3X4(CR1A
, 0x07); // Arbitration Control Counter 1
894 write3X4(CR1B
, 0x07); // Arbitration Control Counter 2
895 write3X4(CR1C
, 0x07); // Arbitration Control Counter 3
896 write3X4(CR1D
, 0x00); // Don't know, doesn't hurt ; -)
897 write3X4(CR1E
, (info
->var
.vmode
& FB_VMODE_INTERLACED
) ? 0x84 : 0x80);
898 // CR1F: do not set, contains BIOS info about memsize
899 write3X4(CR20
, 0x20); // enabe wr buf, disable 16bit planar mode
900 write3X4(CR21
, 0x20); // enable linear memory access
901 // CR22: RO cpu latch readback
903 // CR24: RO AR flag state
904 // CR25: RAMDAC rw timing, pclk buffer tristate control ????
906 write3X4(CR27
, (vdispend
& 0x400) >> 6 |
907 (vsyncstart
& 0x400) >> 5 |
908 (vblankstart
& 0x400) >> 4 |
909 (vtotal
& 0x400) >> 3 |
912 write3X4(CR29
, (read3X4(CR29
) & 0xCF) | ((((info
->var
.xres_virtual
*
913 bpp
) / (4 * 16)) & 0x300) >> 4));
914 write3X4(CR2A
, read3X4(CR2A
) | 0x40);
915 write3X4(CR2B
, (htotal
& 0x100) >> 8 |
916 (hdispend
& 0x100) >> 7 |
917 // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
918 (hsyncstart
& 0x100) >> 5 |
919 (hblankstart
& 0x100) >> 4);
921 // CR2D: initialized in cyblafb_setup_GE()
922 write3X4(CR2F
, 0x92); // conservative, better signal quality
927 // CR34: disabled in CR36
928 // CR35: disabled in CR36
929 // CR36: initialized in cyblafb_setup_GE
930 // CR37: i2c, ignore for now
931 write3X4(CR38
, (bpp
== 8) ? 0x00 : //
932 (bpp
== 16) ? 0x05 : // highcolor
933 (bpp
== 24) ? 0x29 : // packed 24bit truecolor
934 (bpp
== 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
935 write3X4(CR39
, 0x01 | // MMIO enable
936 (pcirb
? 0x02 : 0) | // pci read burst enable
937 (pciwb
? 0x04 : 0)); // pci write burst enable
938 write3X4(CR55
, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
939 (pcirr
? 0x40 : 0) | // pci read retry enable
940 (pciwr
? 0x80 : 0)); // pci write retry enable
941 write3X4(CR56
, preendfetch
>> 8 < 2 ? (preendfetch
>> 8 & 0x01) | 2
943 write3X4(CR57
, preendfetch
>> 8 < 2 ? preendfetch
& 0xff : 0);
944 write3X4(CR58
, 0x82); // Bios does this .... don't know more
949 write3C4(SR01
, 1); //set char clock 8 dots wide
950 write3C4(SR02
, 0x0F); //enable 4 maps needed in chain4 mode
951 write3C4(SR03
, 0); //no character map select
952 write3C4(SR04
, 0x0E); //memory mode: ext mem, even, chain4
955 in8(0x3C5); // Set NEW mode
956 write3C4(SR0D
, 0x00); // test ... check
958 set_vclk(par
, (bpp
== 32 ? 200000000 : 100000000)
959 / info
->var
.pixclock
); //SR18, SR19
964 write3CE(GR00
, 0x00); // test ... check
965 write3CE(GR01
, 0x00); // test ... check
966 write3CE(GR02
, 0x00); // test ... check
967 write3CE(GR03
, 0x00); // test ... check
968 write3CE(GR04
, 0x00); // test ... check
969 write3CE(GR05
, 0x40); // no CGA compat, allow 256 col
970 write3CE(GR06
, 0x05); // graphics mode
971 write3CE(GR07
, 0x0F); // planes?
972 write3CE(GR08
, 0xFF); // test ... check
973 write3CE(GR0F
, (bpp
== 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
974 write3CE(GR20
, 0xC0); // test ... check
975 write3CE(GR2F
, 0xA0); // PCLK = VCLK, no skew,
980 for (i
= 0; i
< 0x10; i
++) // set AR00 .. AR0f
982 write3C0(AR10
, 0x41); // graphics mode and support 256 color modes
983 write3C0(AR12
, 0x0F); // planes
984 write3C0(AR13
, 0); // horizontal pel panning
985 in8(0x3DA); // reset internal flag to 3c0 index
986 out8(0x3C0, 0x20); // enable attr
989 // Setup hidden RAMDAC command register
991 in8(0x3C8); // these reads are
992 in8(0x3C6); // necessary to
993 in8(0x3C6); // unmask the RAMDAC
994 in8(0x3C6); // command reg, otherwise
995 in8(0x3C6); // we would write the pixelmask reg!
996 out8(0x3C6, (bpp
== 8) ? 0x00 : // 256 colors
997 (bpp
== 15) ? 0x10 : //
998 (bpp
== 16) ? 0x30 : // hicolor
999 (bpp
== 24) ? 0xD0 : // truecolor
1000 (bpp
== 32) ? 0xD0 : 0); // truecolor
1004 // GR31 is not mentioned in the datasheet
1006 if (displaytype
== DISPLAY_FP
)
1007 write3CE(GR31
, (read3CE(GR31
) & 0x8F) |
1008 ((info
->var
.yres
> 1024) ? 0x50 :
1009 (info
->var
.yres
> 768) ? 0x30 :
1010 (info
->var
.yres
> 600) ? 0x20 :
1011 (info
->var
.yres
> 480) ? 0x10 : 0));
1013 info
->fix
.visual
= (bpp
== 8) ? FB_VISUAL_PSEUDOCOLOR
1014 : FB_VISUAL_TRUECOLOR
;
1015 info
->fix
.line_length
= info
->var
.xres_virtual
* (bpp
>> 3);
1016 info
->cmap
.len
= (bpp
== 8) ? 256 : 16;
1019 // init acceleration engine
1021 cyblafb_setup_GE(info
->var
.xres_virtual
, info
->var
.bits_per_pixel
);
1024 // Set/clear flags to allow proper scroll mode selection.
1026 if (var
->xres
== var
->xres_virtual
)
1027 info
->flags
&= ~FBINFO_HWACCEL_XPAN
;
1029 info
->flags
|= FBINFO_HWACCEL_XPAN
;
1031 if (var
->yres
== var
->yres_virtual
)
1032 info
->flags
&= ~FBINFO_HWACCEL_YPAN
;
1034 info
->flags
|= FBINFO_HWACCEL_YPAN
;
1036 if (info
->fix
.smem_len
!=
1037 var
->xres_virtual
* var
->yres_virtual
* bpp
/ 8)
1038 info
->flags
&= ~FBINFO_HWACCEL_YWRAP
;
1040 info
->flags
|= FBINFO_HWACCEL_YWRAP
;
1047 //========================
1049 // Set one color register
1051 //========================
1053 static int cyblafb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
1054 unsigned blue
, unsigned transp
,
1055 struct fb_info
*info
)
1057 int bpp
= info
->var
.bits_per_pixel
;
1059 KD_GRAPHICS_RETURN(0);
1061 if (regno
>= info
->cmap
.len
)
1067 out8(0x3C9, red
>> 10);
1068 out8(0x3C9, green
>> 10);
1069 out8(0x3C9, blue
>> 10);
1071 } else if (bpp
== 16) // RGB 565
1072 ((u32
*) info
->pseudo_palette
)[regno
] =
1074 ((green
& 0xFC00) >> 5) | ((blue
& 0xF800) >> 11);
1075 else if (bpp
== 32) // ARGB 8888
1076 ((u32
*) info
->pseudo_palette
)[regno
] =
1077 ((transp
& 0xFF00) << 16) |
1078 ((red
& 0xFF00) << 8) |
1079 ((green
& 0xFF00)) | ((blue
& 0xFF00) >> 8);
1084 //==========================================================
1086 // Try blanking the screen. For flat panels it does nothing
1088 //==========================================================
1090 static int cyblafb_blank(int blank_mode
, struct fb_info
*info
)
1092 unsigned char PMCont
, DPMSCont
;
1094 KD_GRAPHICS_RETURN(0);
1096 if (displaytype
== DISPLAY_FP
)
1099 out8(0x83C8, 0x04); // DPMS Control
1100 PMCont
= in8(0x83C6) & 0xFC;
1102 DPMSCont
= read3CE(GR23
) & 0xFC;
1104 switch (blank_mode
) {
1105 case FB_BLANK_UNBLANK
: // Screen: On, HSync: On, VSync: On
1106 case FB_BLANK_NORMAL
: // Screen: Off, HSync: On, VSync: On
1110 case FB_BLANK_HSYNC_SUSPEND
: // Screen: Off, HSync: Off, VSync: On
1114 case FB_BLANK_VSYNC_SUSPEND
: // Screen: Off, HSync: On, VSync: Off
1118 case FB_BLANK_POWERDOWN
: // Screen: Off, HSync: Off, VSync: Off
1124 write3CE(GR23
, DPMSCont
);
1126 out8(0x83C6, PMCont
);
1128 // let fbcon do a softblank for us
1130 return (blank_mode
== FB_BLANK_NORMAL
) ? 1 : 0;
1133 static struct fb_ops cyblafb_ops __devinitdata
= {
1134 .owner
= THIS_MODULE
,
1135 .fb_setcolreg
= cyblafb_setcolreg
,
1136 .fb_pan_display
= cyblafb_pan_display
,
1137 .fb_blank
= cyblafb_blank
,
1138 .fb_check_var
= cyblafb_check_var
,
1139 .fb_set_par
= cyblafb_set_par
,
1140 .fb_fillrect
= cyblafb_fillrect
,
1141 .fb_copyarea
= cyblafb_copyarea
,
1142 .fb_imageblit
= cyblafb_imageblit
,
1143 .fb_sync
= cyblafb_sync
,
1144 .fb_restore_state
= cyblafb_restore_state
,
1145 .fb_save_state
= cyblafb_save_state
,
1148 //==========================================================================
1150 // getstartupmode() decides about the inital video mode
1152 // There is no reason to use modedb, a lot of video modes there would
1153 // need altered timings to display correctly. So I decided that it is much
1154 // better to provide a limited optimized set of modes plus the option of
1155 // using the mode in effect at startup time (might be selected using the
1156 // vga=??? paramter). After that the user might use fbset to select any
1157 // mode he likes, check_var will not try to alter geometry parameters as
1158 // it would be necessary otherwise.
1160 //==========================================================================
1162 static int __devinit
getstartupmode(struct fb_info
*info
)
1164 u32 htotal
, hdispend
, hsyncstart
, hsyncend
, hblankstart
, hblankend
,
1165 vtotal
, vdispend
, vsyncstart
, vsyncend
, vblankstart
, vblankend
,
1166 cr00
, cr01
, cr02
, cr03
, cr04
, cr05
, cr2b
,
1167 cr06
, cr07
, cr09
, cr10
, cr11
, cr12
, cr15
, cr16
, cr27
,
1168 cr38
, sr0d
, sr18
, sr19
, gr0f
, fi
, pxclkdiv
, vclkdiv
, tmp
, i
;
1171 int xres
; int vxres
; int yres
; int vyres
;
1173 int left_margin
; int right_margin
;
1174 int upper_margin
; int lower_margin
;
1175 int hsync_len
; int vsync_len
;
1178 0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
1179 640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
1180 800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
1181 1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
1182 1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
1185 outb(0x00, 0x3d4); cr00
= inb(0x3d5);
1186 outb(0x01, 0x3d4); cr01
= inb(0x3d5);
1187 outb(0x02, 0x3d4); cr02
= inb(0x3d5);
1188 outb(0x03, 0x3d4); cr03
= inb(0x3d5);
1189 outb(0x04, 0x3d4); cr04
= inb(0x3d5);
1190 outb(0x05, 0x3d4); cr05
= inb(0x3d5);
1191 outb(0x06, 0x3d4); cr06
= inb(0x3d5);
1192 outb(0x07, 0x3d4); cr07
= inb(0x3d5);
1193 outb(0x09, 0x3d4); cr09
= inb(0x3d5);
1194 outb(0x10, 0x3d4); cr10
= inb(0x3d5);
1195 outb(0x11, 0x3d4); cr11
= inb(0x3d5);
1196 outb(0x12, 0x3d4); cr12
= inb(0x3d5);
1197 outb(0x15, 0x3d4); cr15
= inb(0x3d5);
1198 outb(0x16, 0x3d4); cr16
= inb(0x3d5);
1199 outb(0x27, 0x3d4); cr27
= inb(0x3d5);
1200 outb(0x2b, 0x3d4); cr2b
= inb(0x3d5);
1201 outb(0x38, 0x3d4); cr38
= inb(0x3d5);
1206 outb(0x0d, 0x3c4); sr0d
= inb(0x3c5);
1207 outb(0x18, 0x3c4); sr18
= inb(0x3c5);
1208 outb(0x19, 0x3c4); sr19
= inb(0x3c5);
1209 outb(0x0f, 0x3ce); gr0f
= inb(0x3cf);
1211 htotal
= cr00
| (cr2b
& 0x01) << 8;
1212 hdispend
= cr01
| (cr2b
& 0x02) << 7;
1213 hblankstart
= cr02
| (cr2b
& 0x10) << 4;
1214 hblankend
= (cr03
& 0x1f) | (cr05
& 0x80) >> 2;
1215 hsyncstart
= cr04
| (cr2b
& 0x08) << 5;
1216 hsyncend
= cr05
& 0x1f;
1218 modedb
[0].xres
= hblankstart
* 8;
1219 modedb
[0].hsync_len
= hsyncend
* 8;
1220 modedb
[0].right_margin
= hsyncstart
* 8 - modedb
[0].xres
;
1221 modedb
[0].left_margin
= (htotal
+ 5) * 8 - modedb
[0].xres
-
1222 modedb
[0].right_margin
- modedb
[0].hsync_len
;
1224 vtotal
= cr06
| (cr07
& 0x01) << 8 | (cr07
& 0x20) << 4
1225 | (cr27
& 0x80) << 3;
1226 vdispend
= cr12
| (cr07
& 0x02) << 7 | (cr07
& 0x40) << 3
1227 | (cr27
& 0x10) << 6;
1228 vsyncstart
= cr10
| (cr07
& 0x04) << 6 | (cr07
& 0x80) << 2
1229 | (cr27
& 0x20) << 5;
1230 vsyncend
= cr11
& 0x0f;
1231 vblankstart
= cr15
| (cr07
& 0x08) << 5 | (cr09
& 0x20) << 4
1232 | (cr27
& 0x40) << 4;
1235 modedb
[0].yres
= vdispend
+ 1;
1236 modedb
[0].vsync_len
= vsyncend
;
1237 modedb
[0].lower_margin
= vsyncstart
- modedb
[0].yres
;
1238 modedb
[0].upper_margin
= vtotal
- modedb
[0].yres
-
1239 modedb
[0].lower_margin
- modedb
[0].vsync_len
+ 2;
1242 modedb
[0].bpp
= tmp
== 0 ? 8 : tmp
== 4 ? 16 : tmp
== 28 ? 24 :
1245 fi
= ((5864727 * (sr18
+ 8)) /
1246 (((sr19
& 0x3f) + 2) * (1 << ((sr19
& 0xc0) >> 6)))) >> 12;
1247 pxclkdiv
= ((gr0f
& 0x08) >> 3 | (gr0f
& 0x40) >> 5) + 1;
1249 vclkdiv
= tmp
== 0 ? 2 : tmp
== 2 ? 4 : tmp
== 4 ? 8 : 3; // * 2 !
1250 modedb
[0].pxclk
= ((100000000 * pxclkdiv
* vclkdiv
) >> 1) / fi
;
1253 output("detected startup mode: "
1254 "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
1255 modedb
[0].xres
, modedb
[0].yres
, modedb
[0].xres
,
1256 modedb
[0].bpp
, modedb
[0].pxclk
, modedb
[0].left_margin
,
1257 modedb
[0].right_margin
, modedb
[0].upper_margin
,
1258 modedb
[0].lower_margin
, modedb
[0].hsync_len
,
1259 modedb
[0].vsync_len
);
1262 // We use this goto target in case of a failed check_var. No, I really
1263 // do not want to do it in another way!
1268 i
= (mode
== NULL
) ? 0 :
1269 !strncmp(mode
, "640x480", 7) ? 1 :
1270 !strncmp(mode
, "800x600", 7) ? 2 :
1271 !strncmp(mode
, "1024x768", 8) ? 3 :
1272 !strncmp(mode
, "1280x1024", 9) ? 4 : 0;
1274 ref
= (ref
< 50) ? 50 : (ref
> 85) ? 85 : ref
;
1277 info
->var
.pixclock
= modedb
[i
].pxclk
;
1278 info
->var
.bits_per_pixel
= modedb
[i
].bpp
;
1280 info
->var
.pixclock
= (100000000 /
1281 ((modedb
[i
].left_margin
+
1283 modedb
[i
].right_margin
+
1284 modedb
[i
].hsync_len
) *
1285 (modedb
[i
].upper_margin
+
1287 modedb
[i
].lower_margin
+
1288 modedb
[i
].vsync_len
) * ref
/ 10000));
1289 info
->var
.bits_per_pixel
= bpp
;
1292 info
->var
.left_margin
= modedb
[i
].left_margin
;
1293 info
->var
.right_margin
= modedb
[i
].right_margin
;
1294 info
->var
.xres
= modedb
[i
].xres
;
1295 if (!(modedb
[i
].yres
== 1280 && modedb
[i
].bpp
== 32))
1296 info
->var
.xres_virtual
= modedb
[i
].vxres
;
1298 info
->var
.xres_virtual
= modedb
[i
].xres
;
1299 info
->var
.xoffset
= 0;
1300 info
->var
.hsync_len
= modedb
[i
].hsync_len
;
1301 info
->var
.upper_margin
= modedb
[i
].upper_margin
;
1302 info
->var
.yres
= modedb
[i
].yres
;
1303 info
->var
.yres_virtual
= modedb
[i
].vyres
;
1304 info
->var
.yoffset
= 0;
1305 info
->var
.lower_margin
= modedb
[i
].lower_margin
;
1306 info
->var
.vsync_len
= modedb
[i
].vsync_len
;
1308 info
->var
.vmode
= FB_VMODE_NONINTERLACED
;
1310 if (cyblafb_check_var(&info
->var
, info
)) {
1311 // 640x480 - 8@75 should really never fail. One case would
1312 // be fp == 1 and nativex < 640 ... give up then
1313 if (i
== 1 && bpp
== 8 && ref
== 75) {
1314 output("Can't find a valid mode :-(\n");
1317 // Our detected mode is unlikely to fail. If it does,
1318 // try 640x480 - 8@75 ...
1323 output("Detected mode failed check_var! "
1324 "Trying 640x480 - 8@75\n");
1327 // A specified video mode failed for some reason.
1328 // Try the startup mode first
1329 output("Specified mode '%s' failed check! "
1330 "Falling back to startup mode.\n", mode
);
1338 //========================================================
1340 // Detect activated memory size. Undefined values require
1341 // memsize parameter.
1343 //========================================================
1345 static unsigned int __devinit
get_memsize(void)
1353 tmp
= read3X4(CR1F
) & 0x0F;
1356 k
= 1 * 1024 * 1024;
1359 k
= 2 * 1024 * 1024;
1362 k
= 4 * 1024 * 1024;
1365 k
= 8 * 1024 * 1024;
1368 k
= 1 * 1024 * 1024;
1369 output("Unknown memory size code %x in CR1F."
1370 " We default to 1 Mb for now, please"
1371 " do provide a memsize parameter!\n", tmp
);
1376 output("framebuffer size = %d Kb\n", k
/ Kb
);
1380 //=========================================================
1382 // Detect if a flat panel monitor connected to the special
1383 // interface is active. Override is possible by fp and crt
1386 //=========================================================
1388 static unsigned int __devinit
get_displaytype(void)
1394 return (read3CE(GR33
) & 0x10) ? DISPLAY_FP
: DISPLAY_CRT
;
1397 //=====================================
1399 // Get native resolution of flat panel
1401 //=====================================
1403 static int __devinit
get_nativex(void)
1410 tmp
= (read3CE(GR52
) >> 4) & 3;
1413 case 0: x
= 1280; y
= 1024;
1415 case 2: x
= 1024; y
= 768;
1417 case 3: x
= 800; y
= 600;
1419 case 4: x
= 1400; y
= 1050;
1428 output("%dx%d flat panel found\n", x
, y
);
1432 static int __devinit
cybla_pci_probe(struct pci_dev
*dev
,
1433 const struct pci_device_id
*id
)
1435 struct fb_info
*info
;
1436 struct cyblafb_par
*par
;
1438 info
= framebuffer_alloc(sizeof(struct cyblafb_par
), &dev
->dev
);
1440 goto errout_alloc_info
;
1442 info
->pixmap
.addr
= kzalloc(CYBLAFB_PIXMAPSIZE
, GFP_KERNEL
);
1443 if (!info
->pixmap
.addr
) {
1444 output("allocation of pixmap buffer failed!\n");
1445 goto errout_alloc_pixmap
;
1447 info
->pixmap
.size
= CYBLAFB_PIXMAPSIZE
- 4;
1448 info
->pixmap
.buf_align
= 4;
1449 info
->pixmap
.access_align
= 32;
1450 info
->pixmap
.flags
= FB_PIXMAP_SYSTEM
;
1451 info
->pixmap
.scan_align
= 4;
1454 par
->ops
= cyblafb_ops
;
1456 info
->fix
= cyblafb_fix
;
1457 info
->fbops
= &par
->ops
;
1458 info
->fix
= cyblafb_fix
;
1460 if (pci_enable_device(dev
)) {
1461 output("could not enable device!\n");
1464 // might already be requested by vga console or vesafb,
1465 // so we do care about success
1466 if (!request_region(0x3c0, 0x20, "cyblafb")) {
1467 output("region 0x3c0/0x20 already reserved\n");
1472 // Graphics Engine Registers
1474 if (!request_region(GEBase
, 0x100, "cyblafb")) {
1475 output("region %#x/0x100 already reserved\n", GEBase
);
1483 // setup MMIO region
1484 info
->fix
.mmio_start
= pci_resource_start(dev
, 1);
1485 info
->fix
.mmio_len
= 0x20000;
1487 if (!request_mem_region(info
->fix
.mmio_start
,
1488 info
->fix
.mmio_len
, "cyblafb")) {
1489 output("request_mem_region failed for mmio region!\n");
1490 goto errout_mmio_reqmem
;
1493 io_virt
= ioremap_nocache(info
->fix
.mmio_start
, info
->fix
.mmio_len
);
1496 output("ioremap failed for mmio region\n");
1497 goto errout_mmio_remap
;
1499 // setup framebuffer memory ... might already be requested
1500 // by vesafb. Not to fail in case of an unsuccessful request
1501 // is useful if both are loaded.
1502 info
->fix
.smem_start
= pci_resource_start(dev
, 0);
1503 info
->fix
.smem_len
= get_memsize();
1505 if (!request_mem_region(info
->fix
.smem_start
,
1506 info
->fix
.smem_len
, "cyblafb")) {
1507 output("region %#lx/%#x already reserved\n",
1508 info
->fix
.smem_start
, info
->fix
.smem_len
);
1512 info
->screen_base
= ioremap_nocache(info
->fix
.smem_start
,
1513 info
->fix
.smem_len
);
1515 if (!info
->screen_base
) {
1516 output("ioremap failed for smem region\n");
1517 goto errout_smem_remap
;
1520 displaytype
= get_displaytype();
1522 if (displaytype
== DISPLAY_FP
)
1523 nativex
= get_nativex();
1525 info
->flags
= FBINFO_DEFAULT
1526 | FBINFO_HWACCEL_COPYAREA
1527 | FBINFO_HWACCEL_FILLRECT
1528 | FBINFO_HWACCEL_IMAGEBLIT
1530 // | FBINFO_PARTIAL_PAN_OK
1531 | FBINFO_MISC_ALWAYS_SETPAR
;
1533 info
->pseudo_palette
= par
->pseudo_pal
;
1535 if (getstartupmode(info
))
1536 goto errout_findmode
;
1538 fb_alloc_cmap(&info
->cmap
, 256, 0);
1540 if (register_framebuffer(info
)) {
1541 output("Could not register CyBla framebuffer\n");
1542 goto errout_register
;
1545 pci_set_drvdata(dev
, info
);
1548 // normal exit and error paths
1555 iounmap(info
->screen_base
);
1558 release_mem_region(info
->fix
.smem_start
, info
->fix
.smem_len
);
1561 release_mem_region(info
->fix
.mmio_start
, info
->fix
.mmio_len
);
1564 release_region(0x3c0, 32);
1566 kfree(info
->pixmap
.addr
);
1567 errout_alloc_pixmap
:
1568 framebuffer_release(info
);
1570 output("CyblaFB version %s aborting init.\n", VERSION
);
1574 static void __devexit
cybla_pci_remove(struct pci_dev
*dev
)
1576 struct fb_info
*info
= pci_get_drvdata(dev
);
1578 unregister_framebuffer(info
);
1580 iounmap(info
->screen_base
);
1582 release_mem_region(info
->fix
.smem_start
, info
->fix
.smem_len
);
1583 release_mem_region(info
->fix
.mmio_start
, info
->fix
.mmio_len
);
1584 fb_dealloc_cmap(&info
->cmap
);
1586 release_region(GEBase
, 0x100);
1588 release_region(0x3c0, 32);
1589 kfree(info
->pixmap
.addr
);
1590 framebuffer_release(info
);
1591 output("CyblaFB version %s normal exit.\n", VERSION
);
1595 // List of boards that we are trying to support
1597 static struct pci_device_id cybla_devices
[] = {
1598 {PCI_VENDOR_ID_TRIDENT
, CYBERBLADEi1
, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
1602 MODULE_DEVICE_TABLE(pci
, cybla_devices
);
1604 static struct pci_driver cyblafb_pci_driver
= {
1606 .id_table
= cybla_devices
,
1607 .probe
= cybla_pci_probe
,
1608 .remove
= __devexit_p(cybla_pci_remove
)
1611 //=============================================================
1613 // kernel command line example:
1615 // video=cyblafb:1280x1024, bpp=16, ref=50 ...
1617 // modprobe command line example:
1619 // modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
1621 //=============================================================
1623 static int __devinit
cyblafb_init(void)
1626 char *options
= NULL
;
1629 if (fb_get_options("cyblafb", &options
))
1632 if (options
&& *options
)
1633 while ((opt
= strsep(&options
, ",")) != NULL
) {
1636 else if (!strncmp(opt
, "bpp=", 4))
1637 bpp
= simple_strtoul(opt
+ 4, NULL
, 0);
1638 else if (!strncmp(opt
, "ref=", 4))
1639 ref
= simple_strtoul(opt
+ 4, NULL
, 0);
1640 else if (!strncmp(opt
, "fp", 2))
1641 displaytype
= DISPLAY_FP
;
1642 else if (!strncmp(opt
, "crt", 3))
1643 displaytype
= DISPLAY_CRT
;
1644 else if (!strncmp(opt
, "nativex=", 8))
1645 nativex
= simple_strtoul(opt
+ 8, NULL
, 0);
1646 else if (!strncmp(opt
, "center", 6))
1648 else if (!strncmp(opt
, "stretch", 7))
1650 else if (!strncmp(opt
, "pciwb=", 6))
1651 pciwb
= simple_strtoul(opt
+ 6, NULL
, 0);
1652 else if (!strncmp(opt
, "pcirb=", 6))
1653 pcirb
= simple_strtoul(opt
+ 6, NULL
, 0);
1654 else if (!strncmp(opt
, "pciwr=", 6))
1655 pciwr
= simple_strtoul(opt
+ 6, NULL
, 0);
1656 else if (!strncmp(opt
, "pcirr=", 6))
1657 pcirr
= simple_strtoul(opt
+ 6, NULL
, 0);
1658 else if (!strncmp(opt
, "memsize=", 8))
1659 memsize
= simple_strtoul(opt
+ 8, NULL
, 0);
1660 else if (!strncmp(opt
, "verbosity=", 10))
1661 verbosity
= simple_strtoul(opt
+ 10, NULL
, 0);
1666 output("CyblaFB version %s initializing\n", VERSION
);
1667 return pci_register_driver(&cyblafb_pci_driver
);
1670 static void __exit
cyblafb_exit(void)
1672 pci_unregister_driver(&cyblafb_pci_driver
);
1675 module_init(cyblafb_init
);
1676 module_exit(cyblafb_exit
);
1678 MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
1679 MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
1680 MODULE_LICENSE("GPL");