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/config.h>
18 #include <linux/module.h>
19 #include <linux/string.h>
21 #include <linux/init.h>
22 #include <linux/pci.h>
23 #include <asm/types.h>
24 #include <video/cyblafb.h>
26 #define VERSION "0.62"
33 static struct fb_fix_screeninfo cyblafb_fix __devinitdata
= {
35 .type
= FB_TYPE_PACKED_PIXELS
,
39 .visual
= FB_VISUAL_PSEUDOCOLOR
,
40 .accel
= FB_ACCEL_NONE
,
43 static char *mode __devinitdata
= NULL
;
44 static int bpp __devinitdata
= 8;
45 static int ref __devinitdata
= 75;
46 static int fp __devinitdata
;
47 static int crt __devinitdata
;
48 static int memsize __devinitdata
;
50 static int basestride
;
61 static int displaytype
;
63 static void __iomem
*io_virt
; // iospace virtual memory address
65 module_param(mode
, charp
, 0);
66 module_param(bpp
, int, 0);
67 module_param(ref
, int, 0);
68 module_param(fp
, int, 0);
69 module_param(crt
, int, 0);
70 module_param(nativex
, int, 0);
71 module_param(center
, int, 0);
72 module_param(stretch
, int, 0);
73 module_param(pciwb
, int, 0);
74 module_param(pcirb
, int, 0);
75 module_param(pciwr
, int, 0);
76 module_param(pcirr
, int, 0);
77 module_param(memsize
, int, 0);
78 module_param(verbosity
, int, 0);
80 //=========================================
82 // Well, we have to fix the upper layers.
83 // Until this has been done, we work around
86 //=========================================
88 #if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
90 printk("********\n");\
95 #elif CYBLAFB_KD_GRAPHICS_QUIRK
96 #define KD_GRAPHICS_RETURN(val)\
101 #define KD_GRAPHICS_RETURN(val)
104 //=========================================
106 // Port access macros for memory mapped io
108 //=========================================
110 #define out8(r, v) writeb(v, io_virt + r)
111 #define out32(r, v) writel(v, io_virt + r)
112 #define in8(r) readb(io_virt + r)
113 #define in32(r) readl(io_virt + r)
115 //======================================
117 // Hardware access inline functions
119 //======================================
121 static inline u8
read3X4(u32 reg
)
127 static inline u8
read3C4(u32 reg
)
133 static inline u8
read3CE(u32 reg
)
139 static inline void write3X4(u32 reg
, u8 val
)
145 static inline void write3C4(u32 reg
, u8 val
)
151 static inline void write3CE(u32 reg
, u8 val
)
157 static inline void write3C0(u32 reg
, u8 val
)
159 in8(0x3DA); // read to reset index
164 //=================================================
166 // Enable memory mapped io and unprotect registers
168 //=================================================
170 static void enable_mmio(void)
175 inb(0x3C5); // Set NEW mode
176 outb(SR0E
, 0x3C4); // write enable a lot of extended ports
179 outb(SR11
, 0x3C4); // write enable those extended ports that
180 outb(0x87, 0x3C5); // are not affected by SR0E_New
182 outb(CR1E
, 0x3d4); // clear write protect bit for port 0x3c2
183 tmp
= inb(0x3d5) & 0xBF;
188 outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
191 //=================================================
193 // Set pixel clock VCLK1
194 // - multipliers set elswhere
195 // - freq in units of 0.01 MHz
197 // Hardware bug: SR18 >= 250 is broken for the
200 //=================================================
202 static void set_vclk(struct cyblafb_par
*par
, int freq
)
209 k
= freq
>= 10000 ? 0 : freq
>= 5000 ? 1 : freq
>= 2500 ? 2 : 3;
210 for (m
= 0; m
< 64; m
++)
211 for (n
= 0; n
< 250; n
++) {
212 fi
= (int)(((5864727 * (n
+ 8)) /
213 ((m
+ 2) * (1 << k
))) >> 12);
214 if ((di
= abs(fi
- freq
)) < d
) {
218 hi
= (u8
) ((k
<< 6) | m
);
224 output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
225 freq
/ 100, freq
% 100, (hi
& 0xc0) >> 6, hi
& 0x3f, lo
);
228 //================================================
230 // Cyberblade specific Graphics Engine (GE) setup
232 //================================================
234 static void cyblafb_setup_GE(int pitch
, int bpp
)
236 KD_GRAPHICS_RETURN();
240 basestride
= ((pitch
>> 3) << 20) | (0 << 29);
243 basestride
= ((pitch
>> 3) << 20) | (5 << 29);
246 basestride
= ((pitch
>> 3) << 20) | (1 << 29);
250 basestride
= ((pitch
>> 3) << 20) | (2 << 29);
254 write3X4(CR36
, 0x90); // reset GE
255 write3X4(CR36
, 0x80); // enable GE
256 out32(GE24
, 1 << 7); // reset all GE pointers by toggling
257 out32(GE24
, 0); // d7 of GE24
258 write3X4(CR2D
, 0x00); // GE Timinigs, no delays
259 out32(GE6C
, 0); // Pattern and Style, p 129, ok
262 //=====================================================================
264 // Cyberblade specific syncing
266 // A timeout might be caused by disabled mmio.
268 // - bit CR39 & 1 == 0 upon return, X trident driver bug
269 // - kdm bug (KD_GRAPHICS not set on first switch)
270 // - kernel design flaw (it believes in the correctness
272 // First we try to sync ignoring that problem, as most of the
273 // time that will succeed immediately and the enable_mmio()
274 // would only degrade performance.
276 //=====================================================================
278 static int cyblafb_sync(struct fb_info
*info
)
280 u32 status
, i
= 100000;
282 KD_GRAPHICS_RETURN(0);
284 while (((status
= in32(GE20
)) & 0xFe800000) && i
!= 0)
290 while (((status
= in32(GE20
)) & 0xFA800000) && i
!= 0)
293 output("GE Timeout, status: %x\n", status
);
294 if (status
& 0x80000000)
295 output("Bresenham Engine : Busy\n");
296 if (status
& 0x40000000)
297 output("Setup Engine : Busy\n");
298 if (status
& 0x20000000)
299 output("SP / DPE : Busy\n");
300 if (status
& 0x10000000)
301 output("Memory Interface : Busy\n");
302 if (status
& 0x08000000)
303 output("Com Lst Proc : Busy\n");
304 if (status
& 0x04000000)
305 output("Block Write : Busy\n");
306 if (status
& 0x02000000)
307 output("Command Buffer : Full\n");
308 if (status
& 0x01000000)
309 output("RESERVED : Busy\n");
310 if (status
& 0x00800000)
311 output("PCI Write Buffer : Busy\n");
312 cyblafb_setup_GE(info
->var
.xres
,
313 info
->var
.bits_per_pixel
);
320 //==============================
322 // Cyberblade specific fillrect
324 //==============================
326 static void cyblafb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*fr
)
328 u32 bpp
= info
->var
.bits_per_pixel
, col
, desty
, height
;
330 KD_GRAPHICS_RETURN();
340 col
= ((u32
*) (info
->pseudo_palette
))[fr
->color
];
344 col
= ((u32
*) (info
->pseudo_palette
))[fr
->color
];
351 out32(GEB8
, basestride
| ((desty
* info
->var
.xres_virtual
*
354 out32(GE48
, fr
->rop
? 0x66 : ROP_S
);
355 out32(GE44
, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
356 out32(GE08
, point(fr
->dx
, 0));
357 out32(GE0C
, point(fr
->dx
+ fr
->width
- 1,
358 height
> 4096 ? 4095 : height
- 1));
359 if (likely(height
<= 4096))
366 //================================================
368 // Cyberblade specific copyarea
370 // This function silently assumes that it never
371 // will be called with width or height exceeding
374 //================================================
376 static void cyblafb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*ca
)
378 u32 s1
, s2
, d1
, d2
, direction
;
380 KD_GRAPHICS_RETURN();
382 s1
= point(ca
->sx
, 0);
383 s2
= point(ca
->sx
+ ca
->width
- 1, ca
->height
- 1);
384 d1
= point(ca
->dx
, 0);
385 d2
= point(ca
->dx
+ ca
->width
- 1, ca
->height
- 1);
387 if ((ca
->sy
> ca
->dy
) || ((ca
->sy
== ca
->dy
) && (ca
->sx
> ca
->dx
)))
392 out32(GEB8
, basestride
| ((ca
->dy
* info
->var
.xres_virtual
*
393 info
->var
.bits_per_pixel
) >> 6));
394 out32(GEC8
, basestride
| ((ca
->sy
* info
->var
.xres_virtual
*
395 info
->var
.bits_per_pixel
) >> 6));
396 out32(GE44
, 0xa0000000 | 1 << 19 | 1 << 2 | direction
);
397 out32(GE00
, direction
? s2
: s1
);
398 out32(GE04
, direction
? s1
: s2
);
399 out32(GE08
, direction
? d2
: d1
);
400 out32(GE0C
, direction
? d1
: d2
);
403 //=======================================================================
405 // Cyberblade specific imageblit
407 // Accelerated for the most usual case, blitting 1 - bit deep
408 // character images. Everything else is passed to the generic imageblit
409 // unless it is so insane that it is better to printk an alert.
411 // Hardware bug: _Never_ blit across pixel column 2048, that will lock
412 // the system. We split those blit requests into three blitting
415 //=======================================================================
417 static void cyblafb_imageblit(struct fb_info
*info
,
418 const struct fb_image
*image
)
421 u32
*pd
= (u32
*) image
->data
;
422 u32 bpp
= info
->var
.bits_per_pixel
;
424 KD_GRAPHICS_RETURN();
426 // Used only for drawing the penguine (image->depth > 1)
427 if (image
->depth
!= 1) {
428 cfb_imageblit(info
, image
);
431 // That should never happen, but it would be fatal
432 if (image
->width
== 0 || image
->height
== 0) {
433 output("imageblit: width/height 0 detected\n");
437 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
438 info
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
) {
439 fgcol
= ((u32
*) (info
->pseudo_palette
))[image
->fg_color
];
440 bgcol
= ((u32
*) (info
->pseudo_palette
))[image
->bg_color
];
442 fgcol
= image
->fg_color
;
443 bgcol
= image
->bg_color
;
451 fgcol
|= fgcol
<< 16;
452 bgcol
|= bgcol
<< 16;
457 out32(GEB8
, basestride
| ((image
->dy
* info
->var
.xres_virtual
*
462 if (!(image
->dx
< 2048 && (image
->dx
+ image
->width
- 1) >= 2048)) {
463 u32 dds
= ((image
->width
+ 31) >> 5) * image
->height
;
464 out32(GE44
, 0xa0000000 | 1 << 20 | 1 << 19);
465 out32(GE08
, point(image
->dx
, 0));
466 out32(GE0C
, point(image
->dx
+ image
->width
- 1,
472 u32 ddstotal
= (image
->width
+ 31) >> 5;
473 u32 ddsleft
= (2048 - image
->dx
+ 31) >> 5;
474 u32 skipleft
= ddstotal
- ddsleft
;
476 out32(GE44
, 0xa0000000 | 1 << 20 | 1 << 19);
477 out32(GE08
, point(image
->dx
, 0));
478 out32(GE0C
, point(2048 - 1, image
->height
- 1));
479 for (i
= 0; i
< image
->height
; i
++) {
480 for (j
= 0; j
< ddsleft
; j
++)
485 if (image
->dx
% 32) {
486 out32(GE44
, 0xa0000000 | 1 << 20 | 1 << 19);
487 out32(GE08
, point(2048, 0));
488 if (image
->width
> ddsleft
<< 5)
489 out32(GE0C
, point(image
->dx
+ (ddsleft
<< 5) -
490 1, image
->height
- 1));
492 out32(GE0C
, point(image
->dx
+ image
->width
- 1,
494 pd
= ((u32
*) image
->data
) + ddstotal
- skipleft
- 1;
495 for (i
= 0; i
< image
->height
; i
++) {
496 out32(GE9C
, swab32(swab32(*pd
) << ((32 -
497 (image
->dx
& 31)) & 31)));
503 out32(GE44
, 0xa0000000 | 1 << 20 | 1 << 19);
504 out32(GE08
, point(image
->dx
+ (ddsleft
<< 5), 0));
505 out32(GE0C
, point(image
->dx
+ image
->width
- 1,
507 pd
= (u32
*) image
->data
;
508 for (i
= 0; i
< image
->height
; i
++) {
510 for (j
= 0; j
< skipleft
; j
++)
517 //==========================================================
519 // Check if video mode is acceptable. We change var->??? if
520 // video mode is slightly off or return error otherwise.
521 // info->??? must not be changed!
523 //==========================================================
525 static int cyblafb_check_var(struct fb_var_screeninfo
*var
,
526 struct fb_info
*info
)
528 int bpp
= var
->bits_per_pixel
;
531 // we try to support 8, 16, 24 and 32 bpp modes,
534 // there is a 24 bpp mode, but for now we change requests to 32 bpp
535 // (This is what tridentfb does ... will be changed in the future)
538 if (bpp
% 8 != 0 || bpp
< 8 || bpp
> 32)
541 bpp
= var
->bits_per_pixel
= 32;
544 // interlaced modes are broken, fail if one is requested
546 if (var
->vmode
& FB_VMODE_INTERLACED
)
550 // fail if requested resolution is higher than physical
551 // flatpanel resolution
553 if ((displaytype
== DISPLAY_FP
) && nativex
&& var
->xres
> nativex
)
557 // we do not allow vclk to exceed 230 MHz. If the requested
558 // vclk is too high, we default to 200 MHz
560 if ((bpp
== 32 ? 200000000 : 100000000) / var
->pixclock
> 23000)
561 var
->pixclock
= (bpp
== 32 ? 200000000 : 100000000) / 20000;
564 // enforce (h|v)sync_len limits
566 var
->hsync_len
&= ~7;
567 if(var
->hsync_len
> 248)
568 var
->hsync_len
= 248;
570 var
->vsync_len
&= 15;
573 // Enforce horizontal and vertical hardware limits.
574 // 1600x1200 is mentioned as a maximum, but higher resolutions could
575 // work with slow refresh, small margins and short sync.
579 if (((var
->xres
+ var
->left_margin
+ var
->right_margin
+
580 var
->hsync_len
) > (bpp
== 32 ? 2040 : 4088)) ||
581 ((var
->yres
+ var
->upper_margin
+ var
->lower_margin
+
582 var
->vsync_len
) > 2047))
585 if ((var
->xres
> 1600) || (var
->yres
> 1200))
586 output("Mode %dx%d exceeds documented limits.\n",
587 var
->xres
, var
->yres
);
589 // try to be smart about (x|y)res_virtual problems.
591 if (var
->xres
> var
->xres_virtual
)
592 var
->xres_virtual
= var
->xres
;
593 if (var
->yres
> var
->yres_virtual
)
594 var
->yres_virtual
= var
->yres
;
596 if (bpp
== 8 || bpp
== 16) {
597 if (var
->xres_virtual
> 4088)
598 var
->xres_virtual
= 4088;
600 if (var
->xres_virtual
> 2040)
601 var
->xres_virtual
= 2040;
603 var
->xres_virtual
&= ~7;
604 while (var
->xres_virtual
* var
->yres_virtual
* bpp
/ 8 >
605 info
->fix
.smem_len
) {
606 if (var
->yres_virtual
> var
->yres
)
608 else if (var
->xres_virtual
> var
->xres
)
609 var
->xres_virtual
-= 8;
617 var
->green
.offset
= 0;
618 var
->blue
.offset
= 0;
620 var
->green
.length
= 6;
621 var
->blue
.length
= 6;
624 var
->red
.offset
= 11;
625 var
->green
.offset
= 5;
626 var
->blue
.offset
= 0;
628 var
->green
.length
= 6;
629 var
->blue
.length
= 5;
632 var
->red
.offset
= 16;
633 var
->green
.offset
= 8;
634 var
->blue
.offset
= 0;
636 var
->green
.length
= 8;
637 var
->blue
.length
= 8;
646 //=====================================================================
650 // The datasheets defines crt start address to be 20 bits wide and
651 // to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
652 // CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
653 // it, so it is also safe to be used here. BTW: datasheet CR0E on page
654 // 90 really is CR1E, the real CRE is documented on page 72.
658 // As of internal version 0.60 we do not use vga panning any longer.
659 // Vga panning did not allow us the use of all available video memory
660 // and thus prevented ywrap scrolling. We do use the "right view"
664 //=====================================================================
666 static int cyblafb_pan_display(struct fb_var_screeninfo
*var
,
667 struct fb_info
*info
)
669 KD_GRAPHICS_RETURN(0);
671 info
->var
.xoffset
= var
->xoffset
;
672 info
->var
.yoffset
= var
->yoffset
;
673 out32(GE10
, 0x80000000 | ((var
->xoffset
+ (var
->yoffset
*
674 var
->xres_virtual
)) * var
->bits_per_pixel
/ 32));
678 //============================================
680 // This will really help in case of a bug ...
681 // dump most gaphics core registers.
683 //============================================
685 static void regdump(struct cyblafb_par
*par
)
693 for (i
= 0; i
<= 0xff; i
++) {
695 printk("CR%02x=%02x ", i
, inb(0x3d5));
701 outb(inb(0x3cf) | 0x40, 0x3cf);
702 for (i
= 0; i
<= 0x1f; i
++) {
703 if (i
== 0 || (i
> 2 && i
< 8) || i
== 0x10 || i
== 0x11
706 printk("CR%02x=%02x ", i
, inb(0x3d5));
713 outb(inb(0x3cf) & 0xbf, 0x3cf);
716 for (i
= 0; i
<= 0x7f; i
++) {
718 printk("GR%02x=%02x ", i
, inb(0x3cf));
724 for (i
= 0; i
<= 0xff; i
++) {
726 printk("SR%02x=%02x ", i
, inb(0x3c5));
732 for (i
= 0; i
<= 0x1F; i
++) {
733 inb(0x3da); // next access is index!
735 printk("AR%02x=%02x ", i
, inb(0x3c1));
741 inb(0x3DA); // reset internal flag to 3c0 index
742 outb(0x20, 0x3C0); // enable attr
747 //=======================================================================
751 // This function is called while a switch to KD_TEXT is in progress,
752 // before any of the other functions are called.
754 //=======================================================================
756 static void cyblafb_save_state(struct fb_info
*info
)
758 struct cyblafb_par
*par
= info
->par
;
760 output("Switching to KD_TEXT\n");
767 //=======================================================================
771 // This function is called while a switch to KD_GRAPHICS is in progress,
772 // We have to turn on vga style panning registers again because the
773 // trident driver of X does not know about GE10.
775 //=======================================================================
777 static void cyblafb_restore_state(struct fb_info
*info
)
780 output("Switching to KD_GRAPHICS\n");
786 //======================================
788 // Set hardware to requested video mode
790 //======================================
792 static int cyblafb_set_par(struct fb_info
*info
)
794 struct cyblafb_par
*par
= info
->par
;
795 u32 htotal
, hdispend
, hsyncstart
, hsyncend
, hblankstart
,
796 hblankend
, preendfetch
, vtotal
, vdispend
, vsyncstart
,
797 vsyncend
, vblankstart
, vblankend
;
798 struct fb_var_screeninfo
*var
= &info
->var
;
799 int bpp
= var
->bits_per_pixel
;
802 KD_GRAPHICS_RETURN(0);
805 output("Switching to new mode: "
806 "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
807 var
->xres
, var
->yres
, var
->xres_virtual
,
808 var
->yres_virtual
, var
->bits_per_pixel
, var
->pixclock
,
809 var
->left_margin
, var
->right_margin
, var
->upper_margin
,
810 var
->lower_margin
, var
->hsync_len
, var
->vsync_len
);
812 htotal
= (var
->xres
+ var
->left_margin
+ var
->right_margin
+
813 var
->hsync_len
) / 8 - 5;
814 hdispend
= var
->xres
/ 8 - 1;
815 hsyncstart
= (var
->xres
+ var
->right_margin
) / 8;
816 hsyncend
= var
->hsync_len
/ 8;
817 hblankstart
= hdispend
+ 1;
818 hblankend
= htotal
+ 3; // should be htotal + 5, bios does it this way
819 preendfetch
= ((var
->xres
>> 3) + 1) * ((bpp
+ 1) >> 3);
821 vtotal
= var
->yres
+ var
->upper_margin
+ var
->lower_margin
+
823 vdispend
= var
->yres
- 1;
824 vsyncstart
= var
->yres
+ var
->lower_margin
;
825 vblankstart
= var
->yres
;
826 vblankend
= vtotal
; // should be vtotal + 2, but bios does it this way
827 vsyncend
= var
->vsync_len
;
829 enable_mmio(); // necessary! ... check X ...
831 write3X4(CR11
, read3X4(CR11
) & 0x7F); // unlock cr00 .. cr07
835 if ((displaytype
== DISPLAY_FP
) && var
->xres
< nativex
) {
837 // stretch or center ?
841 write3CE(GR30
, read3CE(GR30
) | 0x81); // shadow mode on
844 write3CE(GR52
, (read3CE(GR52
) & 0x7C) | 0x80);
845 write3CE(GR53
, (read3CE(GR53
) & 0x7C) | 0x80);
846 } else if (stretch
) {
848 write3CE(GR52
, (read3CE(GR52
) & 0x7C) | 1);
849 write3CE(GR53
, (read3CE(GR53
) & 0x7C) | 1);
861 write3X4(CR00
, htotal
& 0xFF);
862 write3X4(CR01
, hdispend
& 0xFF);
863 write3X4(CR02
, hblankstart
& 0xFF);
864 write3X4(CR03
, hblankend
& 0x1F);
865 write3X4(CR04
, hsyncstart
& 0xFF);
866 write3X4(CR05
, (hsyncend
& 0x1F) | ((hblankend
& 0x20) << 2));
867 write3X4(CR06
, vtotal
& 0xFF);
868 write3X4(CR07
, (vtotal
& 0x100) >> 8 |
869 (vdispend
& 0x100) >> 7 |
870 (vsyncstart
& 0x100) >> 6 |
871 (vblankstart
& 0x100) >> 5 |
873 (vtotal
& 0x200) >> 4 |
874 (vdispend
& 0x200) >> 3 | (vsyncstart
& 0x200) >> 2);
876 write3X4(CR09
, (vblankstart
& 0x200) >> 4 | 0x40 | // FIX !!!
877 ((info
->var
.vmode
& FB_VMODE_DOUBLE
) ? 0x80 : 0));
878 write3X4(CR0A
, 0); // Init to some reasonable default
879 write3X4(CR0B
, 0); // Init to some reasonable default
880 write3X4(CR0C
, 0); // Offset 0
881 write3X4(CR0D
, 0); // Offset 0
882 write3X4(CR0E
, 0); // Init to some reasonable default
883 write3X4(CR0F
, 0); // Init to some reasonable default
884 write3X4(CR10
, vsyncstart
& 0xFF);
885 write3X4(CR11
, (vsyncend
& 0x0F));
886 write3X4(CR12
, vdispend
& 0xFF);
887 write3X4(CR13
, ((info
->var
.xres_virtual
* bpp
) / (4 * 16)) & 0xFF);
888 write3X4(CR14
, 0x40); // double word mode
889 write3X4(CR15
, vblankstart
& 0xFF);
890 write3X4(CR16
, vblankend
& 0xFF);
891 write3X4(CR17
, 0xE3);
892 write3X4(CR18
, 0xFF);
893 // CR19: needed for interlaced modes ... ignore it for now
894 write3X4(CR1A
, 0x07); // Arbitration Control Counter 1
895 write3X4(CR1B
, 0x07); // Arbitration Control Counter 2
896 write3X4(CR1C
, 0x07); // Arbitration Control Counter 3
897 write3X4(CR1D
, 0x00); // Don't know, doesn't hurt ; -)
898 write3X4(CR1E
, (info
->var
.vmode
& FB_VMODE_INTERLACED
) ? 0x84 : 0x80);
899 // CR1F: do not set, contains BIOS info about memsize
900 write3X4(CR20
, 0x20); // enabe wr buf, disable 16bit planar mode
901 write3X4(CR21
, 0x20); // enable linear memory access
902 // CR22: RO cpu latch readback
904 // CR24: RO AR flag state
905 // CR25: RAMDAC rw timing, pclk buffer tristate control ????
907 write3X4(CR27
, (vdispend
& 0x400) >> 6 |
908 (vsyncstart
& 0x400) >> 5 |
909 (vblankstart
& 0x400) >> 4 |
910 (vtotal
& 0x400) >> 3 |
913 write3X4(CR29
, (read3X4(CR29
) & 0xCF) | ((((info
->var
.xres_virtual
*
914 bpp
) / (4 * 16)) & 0x300) >> 4));
915 write3X4(CR2A
, read3X4(CR2A
) | 0x40);
916 write3X4(CR2B
, (htotal
& 0x100) >> 8 |
917 (hdispend
& 0x100) >> 7 |
918 // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
919 (hsyncstart
& 0x100) >> 5 |
920 (hblankstart
& 0x100) >> 4);
922 // CR2D: initialized in cyblafb_setup_GE()
923 write3X4(CR2F
, 0x92); // conservative, better signal quality
928 // CR34: disabled in CR36
929 // CR35: disabled in CR36
930 // CR36: initialized in cyblafb_setup_GE
931 // CR37: i2c, ignore for now
932 write3X4(CR38
, (bpp
== 8) ? 0x00 : //
933 (bpp
== 16) ? 0x05 : // highcolor
934 (bpp
== 24) ? 0x29 : // packed 24bit truecolor
935 (bpp
== 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
936 write3X4(CR39
, 0x01 | // MMIO enable
937 (pcirb
? 0x02 : 0) | // pci read burst enable
938 (pciwb
? 0x04 : 0)); // pci write burst enable
939 write3X4(CR55
, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
940 (pcirr
? 0x40 : 0) | // pci read retry enable
941 (pciwr
? 0x80 : 0)); // pci write retry enable
942 write3X4(CR56
, preendfetch
>> 8 < 2 ? (preendfetch
>> 8 & 0x01) | 2
944 write3X4(CR57
, preendfetch
>> 8 < 2 ? preendfetch
& 0xff : 0);
945 write3X4(CR58
, 0x82); // Bios does this .... don't know more
950 write3C4(SR01
, 1); //set char clock 8 dots wide
951 write3C4(SR02
, 0x0F); //enable 4 maps needed in chain4 mode
952 write3C4(SR03
, 0); //no character map select
953 write3C4(SR04
, 0x0E); //memory mode: ext mem, even, chain4
956 in8(0x3C5); // Set NEW mode
957 write3C4(SR0D
, 0x00); // test ... check
959 set_vclk(par
, (bpp
== 32 ? 200000000 : 100000000)
960 / info
->var
.pixclock
); //SR18, SR19
965 write3CE(GR00
, 0x00); // test ... check
966 write3CE(GR01
, 0x00); // test ... check
967 write3CE(GR02
, 0x00); // test ... check
968 write3CE(GR03
, 0x00); // test ... check
969 write3CE(GR04
, 0x00); // test ... check
970 write3CE(GR05
, 0x40); // no CGA compat, allow 256 col
971 write3CE(GR06
, 0x05); // graphics mode
972 write3CE(GR07
, 0x0F); // planes?
973 write3CE(GR08
, 0xFF); // test ... check
974 write3CE(GR0F
, (bpp
== 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
975 write3CE(GR20
, 0xC0); // test ... check
976 write3CE(GR2F
, 0xA0); // PCLK = VCLK, no skew,
981 for (i
= 0; i
< 0x10; i
++) // set AR00 .. AR0f
983 write3C0(AR10
, 0x41); // graphics mode and support 256 color modes
984 write3C0(AR12
, 0x0F); // planes
985 write3C0(AR13
, 0); // horizontal pel panning
986 in8(0x3DA); // reset internal flag to 3c0 index
987 out8(0x3C0, 0x20); // enable attr
990 // Setup hidden RAMDAC command register
992 in8(0x3C8); // these reads are
993 in8(0x3C6); // necessary to
994 in8(0x3C6); // unmask the RAMDAC
995 in8(0x3C6); // command reg, otherwise
996 in8(0x3C6); // we would write the pixelmask reg!
997 out8(0x3C6, (bpp
== 8) ? 0x00 : // 256 colors
998 (bpp
== 15) ? 0x10 : //
999 (bpp
== 16) ? 0x30 : // hicolor
1000 (bpp
== 24) ? 0xD0 : // truecolor
1001 (bpp
== 32) ? 0xD0 : 0); // truecolor
1005 // GR31 is not mentioned in the datasheet
1007 if (displaytype
== DISPLAY_FP
)
1008 write3CE(GR31
, (read3CE(GR31
) & 0x8F) |
1009 ((info
->var
.yres
> 1024) ? 0x50 :
1010 (info
->var
.yres
> 768) ? 0x30 :
1011 (info
->var
.yres
> 600) ? 0x20 :
1012 (info
->var
.yres
> 480) ? 0x10 : 0));
1014 info
->fix
.visual
= (bpp
== 8) ? FB_VISUAL_PSEUDOCOLOR
1015 : FB_VISUAL_TRUECOLOR
;
1016 info
->fix
.line_length
= info
->var
.xres_virtual
* (bpp
>> 3);
1017 info
->cmap
.len
= (bpp
== 8) ? 256 : 16;
1020 // init acceleration engine
1022 cyblafb_setup_GE(info
->var
.xres_virtual
, info
->var
.bits_per_pixel
);
1025 // Set/clear flags to allow proper scroll mode selection.
1027 if (var
->xres
== var
->xres_virtual
)
1028 info
->flags
&= ~FBINFO_HWACCEL_XPAN
;
1030 info
->flags
|= FBINFO_HWACCEL_XPAN
;
1032 if (var
->yres
== var
->yres_virtual
)
1033 info
->flags
&= ~FBINFO_HWACCEL_YPAN
;
1035 info
->flags
|= FBINFO_HWACCEL_YPAN
;
1037 if (info
->fix
.smem_len
!=
1038 var
->xres_virtual
* var
->yres_virtual
* bpp
/ 8)
1039 info
->flags
&= ~FBINFO_HWACCEL_YWRAP
;
1041 info
->flags
|= FBINFO_HWACCEL_YWRAP
;
1048 //========================
1050 // Set one color register
1052 //========================
1054 static int cyblafb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
1055 unsigned blue
, unsigned transp
,
1056 struct fb_info
*info
)
1058 int bpp
= info
->var
.bits_per_pixel
;
1060 KD_GRAPHICS_RETURN(0);
1062 if (regno
>= info
->cmap
.len
)
1068 out8(0x3C9, red
>> 10);
1069 out8(0x3C9, green
>> 10);
1070 out8(0x3C9, blue
>> 10);
1072 } else if (bpp
== 16) // RGB 565
1073 ((u32
*) info
->pseudo_palette
)[regno
] =
1075 ((green
& 0xFC00) >> 5) | ((blue
& 0xF800) >> 11);
1076 else if (bpp
== 32) // ARGB 8888
1077 ((u32
*) info
->pseudo_palette
)[regno
] =
1078 ((transp
& 0xFF00) << 16) |
1079 ((red
& 0xFF00) << 8) |
1080 ((green
& 0xFF00)) | ((blue
& 0xFF00) >> 8);
1085 //==========================================================
1087 // Try blanking the screen. For flat panels it does nothing
1089 //==========================================================
1091 static int cyblafb_blank(int blank_mode
, struct fb_info
*info
)
1093 unsigned char PMCont
, DPMSCont
;
1095 KD_GRAPHICS_RETURN(0);
1097 if (displaytype
== DISPLAY_FP
)
1100 out8(0x83C8, 0x04); // DPMS Control
1101 PMCont
= in8(0x83C6) & 0xFC;
1103 DPMSCont
= read3CE(GR23
) & 0xFC;
1105 switch (blank_mode
) {
1106 case FB_BLANK_UNBLANK
: // Screen: On, HSync: On, VSync: On
1107 case FB_BLANK_NORMAL
: // Screen: Off, HSync: On, VSync: On
1111 case FB_BLANK_HSYNC_SUSPEND
: // Screen: Off, HSync: Off, VSync: On
1115 case FB_BLANK_VSYNC_SUSPEND
: // Screen: Off, HSync: On, VSync: Off
1119 case FB_BLANK_POWERDOWN
: // Screen: Off, HSync: Off, VSync: Off
1125 write3CE(GR23
, DPMSCont
);
1127 out8(0x83C6, PMCont
);
1129 // let fbcon do a softblank for us
1131 return (blank_mode
== FB_BLANK_NORMAL
) ? 1 : 0;
1134 static struct fb_ops cyblafb_ops __devinitdata
= {
1135 .owner
= THIS_MODULE
,
1136 .fb_setcolreg
= cyblafb_setcolreg
,
1137 .fb_pan_display
= cyblafb_pan_display
,
1138 .fb_blank
= cyblafb_blank
,
1139 .fb_check_var
= cyblafb_check_var
,
1140 .fb_set_par
= cyblafb_set_par
,
1141 .fb_fillrect
= cyblafb_fillrect
,
1142 .fb_copyarea
= cyblafb_copyarea
,
1143 .fb_imageblit
= cyblafb_imageblit
,
1144 .fb_sync
= cyblafb_sync
,
1145 .fb_restore_state
= cyblafb_restore_state
,
1146 .fb_save_state
= cyblafb_save_state
,
1149 //==========================================================================
1151 // getstartupmode() decides about the inital video mode
1153 // There is no reason to use modedb, a lot of video modes there would
1154 // need altered timings to display correctly. So I decided that it is much
1155 // better to provide a limited optimized set of modes plus the option of
1156 // using the mode in effect at startup time (might be selected using the
1157 // vga=??? paramter). After that the user might use fbset to select any
1158 // mode he likes, check_var will not try to alter geometry parameters as
1159 // it would be necessary otherwise.
1161 //==========================================================================
1163 static int __devinit
getstartupmode(struct fb_info
*info
)
1165 u32 htotal
, hdispend
, hsyncstart
, hsyncend
, hblankstart
, hblankend
,
1166 vtotal
, vdispend
, vsyncstart
, vsyncend
, vblankstart
, vblankend
,
1167 cr00
, cr01
, cr02
, cr03
, cr04
, cr05
, cr2b
,
1168 cr06
, cr07
, cr09
, cr10
, cr11
, cr12
, cr15
, cr16
, cr27
,
1169 cr38
, sr0d
, sr18
, sr19
, gr0f
, fi
, pxclkdiv
, vclkdiv
, tmp
, i
;
1172 int xres
; int vxres
; int yres
; int vyres
;
1174 int left_margin
; int right_margin
;
1175 int upper_margin
; int lower_margin
;
1176 int hsync_len
; int vsync_len
;
1179 0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
1180 640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
1181 800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
1182 1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
1183 1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
1186 outb(0x00, 0x3d4); cr00
= inb(0x3d5);
1187 outb(0x01, 0x3d4); cr01
= inb(0x3d5);
1188 outb(0x02, 0x3d4); cr02
= inb(0x3d5);
1189 outb(0x03, 0x3d4); cr03
= inb(0x3d5);
1190 outb(0x04, 0x3d4); cr04
= inb(0x3d5);
1191 outb(0x05, 0x3d4); cr05
= inb(0x3d5);
1192 outb(0x06, 0x3d4); cr06
= inb(0x3d5);
1193 outb(0x07, 0x3d4); cr07
= inb(0x3d5);
1194 outb(0x09, 0x3d4); cr09
= inb(0x3d5);
1195 outb(0x10, 0x3d4); cr10
= inb(0x3d5);
1196 outb(0x11, 0x3d4); cr11
= inb(0x3d5);
1197 outb(0x12, 0x3d4); cr12
= inb(0x3d5);
1198 outb(0x15, 0x3d4); cr15
= inb(0x3d5);
1199 outb(0x16, 0x3d4); cr16
= inb(0x3d5);
1200 outb(0x27, 0x3d4); cr27
= inb(0x3d5);
1201 outb(0x2b, 0x3d4); cr2b
= inb(0x3d5);
1202 outb(0x38, 0x3d4); cr38
= inb(0x3d5);
1207 outb(0x0d, 0x3c4); sr0d
= inb(0x3c5);
1208 outb(0x18, 0x3c4); sr18
= inb(0x3c5);
1209 outb(0x19, 0x3c4); sr19
= inb(0x3c5);
1210 outb(0x0f, 0x3ce); gr0f
= inb(0x3cf);
1212 htotal
= cr00
| (cr2b
& 0x01) << 8;
1213 hdispend
= cr01
| (cr2b
& 0x02) << 7;
1214 hblankstart
= cr02
| (cr2b
& 0x10) << 4;
1215 hblankend
= (cr03
& 0x1f) | (cr05
& 0x80) >> 2;
1216 hsyncstart
= cr04
| (cr2b
& 0x08) << 5;
1217 hsyncend
= cr05
& 0x1f;
1219 modedb
[0].xres
= hblankstart
* 8;
1220 modedb
[0].hsync_len
= hsyncend
* 8;
1221 modedb
[0].right_margin
= hsyncstart
* 8 - modedb
[0].xres
;
1222 modedb
[0].left_margin
= (htotal
+ 5) * 8 - modedb
[0].xres
-
1223 modedb
[0].right_margin
- modedb
[0].hsync_len
;
1225 vtotal
= cr06
| (cr07
& 0x01) << 8 | (cr07
& 0x20) << 4
1226 | (cr27
& 0x80) << 3;
1227 vdispend
= cr12
| (cr07
& 0x02) << 7 | (cr07
& 0x40) << 3
1228 | (cr27
& 0x10) << 6;
1229 vsyncstart
= cr10
| (cr07
& 0x04) << 6 | (cr07
& 0x80) << 2
1230 | (cr27
& 0x20) << 5;
1231 vsyncend
= cr11
& 0x0f;
1232 vblankstart
= cr15
| (cr07
& 0x08) << 5 | (cr09
& 0x20) << 4
1233 | (cr27
& 0x40) << 4;
1236 modedb
[0].yres
= vdispend
+ 1;
1237 modedb
[0].vsync_len
= vsyncend
;
1238 modedb
[0].lower_margin
= vsyncstart
- modedb
[0].yres
;
1239 modedb
[0].upper_margin
= vtotal
- modedb
[0].yres
-
1240 modedb
[0].lower_margin
- modedb
[0].vsync_len
+ 2;
1243 modedb
[0].bpp
= tmp
== 0 ? 8 : tmp
== 4 ? 16 : tmp
== 28 ? 24 :
1246 fi
= ((5864727 * (sr18
+ 8)) /
1247 (((sr19
& 0x3f) + 2) * (1 << ((sr19
& 0xc0) >> 6)))) >> 12;
1248 pxclkdiv
= ((gr0f
& 0x08) >> 3 | (gr0f
& 0x40) >> 5) + 1;
1250 vclkdiv
= tmp
== 0 ? 2 : tmp
== 2 ? 4 : tmp
== 4 ? 8 : 3; // * 2 !
1251 modedb
[0].pxclk
= ((100000000 * pxclkdiv
* vclkdiv
) >> 1) / fi
;
1254 output("detected startup mode: "
1255 "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
1256 modedb
[0].xres
, modedb
[0].yres
, modedb
[0].xres
,
1257 modedb
[0].bpp
, modedb
[0].pxclk
, modedb
[0].left_margin
,
1258 modedb
[0].right_margin
, modedb
[0].upper_margin
,
1259 modedb
[0].lower_margin
, modedb
[0].hsync_len
,
1260 modedb
[0].vsync_len
);
1263 // We use this goto target in case of a failed check_var. No, I really
1264 // do not want to do it in another way!
1269 i
= (mode
== NULL
) ? 0 :
1270 !strncmp(mode
, "640x480", 7) ? 1 :
1271 !strncmp(mode
, "800x600", 7) ? 2 :
1272 !strncmp(mode
, "1024x768", 8) ? 3 :
1273 !strncmp(mode
, "1280x1024", 9) ? 4 : 0;
1275 ref
= (ref
< 50) ? 50 : (ref
> 85) ? 85 : ref
;
1278 info
->var
.pixclock
= modedb
[i
].pxclk
;
1279 info
->var
.bits_per_pixel
= modedb
[i
].bpp
;
1281 info
->var
.pixclock
= (100000000 /
1282 ((modedb
[i
].left_margin
+
1284 modedb
[i
].right_margin
+
1285 modedb
[i
].hsync_len
) *
1286 (modedb
[i
].upper_margin
+
1288 modedb
[i
].lower_margin
+
1289 modedb
[i
].vsync_len
) * ref
/ 10000));
1290 info
->var
.bits_per_pixel
= bpp
;
1293 info
->var
.left_margin
= modedb
[i
].left_margin
;
1294 info
->var
.right_margin
= modedb
[i
].right_margin
;
1295 info
->var
.xres
= modedb
[i
].xres
;
1296 if (!(modedb
[i
].yres
== 1280 && modedb
[i
].bpp
== 32))
1297 info
->var
.xres_virtual
= modedb
[i
].vxres
;
1299 info
->var
.xres_virtual
= modedb
[i
].xres
;
1300 info
->var
.xoffset
= 0;
1301 info
->var
.hsync_len
= modedb
[i
].hsync_len
;
1302 info
->var
.upper_margin
= modedb
[i
].upper_margin
;
1303 info
->var
.yres
= modedb
[i
].yres
;
1304 info
->var
.yres_virtual
= modedb
[i
].vyres
;
1305 info
->var
.yoffset
= 0;
1306 info
->var
.lower_margin
= modedb
[i
].lower_margin
;
1307 info
->var
.vsync_len
= modedb
[i
].vsync_len
;
1309 info
->var
.vmode
= FB_VMODE_NONINTERLACED
;
1311 if (cyblafb_check_var(&info
->var
, info
)) {
1312 // 640x480 - 8@75 should really never fail. One case would
1313 // be fp == 1 and nativex < 640 ... give up then
1314 if (i
== 1 && bpp
== 8 && ref
== 75) {
1315 output("Can't find a valid mode :-(\n");
1318 // Our detected mode is unlikely to fail. If it does,
1319 // try 640x480 - 8@75 ...
1324 output("Detected mode failed check_var! "
1325 "Trying 640x480 - 8@75\n");
1328 // A specified video mode failed for some reason.
1329 // Try the startup mode first
1330 output("Specified mode '%s' failed check! "
1331 "Falling back to startup mode.\n", mode
);
1339 //========================================================
1341 // Detect activated memory size. Undefined values require
1342 // memsize parameter.
1344 //========================================================
1346 static unsigned int __devinit
get_memsize(void)
1354 tmp
= read3X4(CR1F
) & 0x0F;
1357 k
= 1 * 1024 * 1024;
1360 k
= 2 * 1024 * 1024;
1363 k
= 4 * 1024 * 1024;
1366 k
= 8 * 1024 * 1024;
1369 k
= 1 * 1024 * 1024;
1370 output("Unknown memory size code %x in CR1F."
1371 " We default to 1 Mb for now, please"
1372 " do provide a memsize parameter!\n", tmp
);
1377 output("framebuffer size = %d Kb\n", k
/ Kb
);
1381 //=========================================================
1383 // Detect if a flat panel monitor connected to the special
1384 // interface is active. Override is possible by fp and crt
1387 //=========================================================
1389 static unsigned int __devinit
get_displaytype(void)
1395 return (read3CE(GR33
) & 0x10) ? DISPLAY_FP
: DISPLAY_CRT
;
1398 //=====================================
1400 // Get native resolution of flat panel
1402 //=====================================
1404 static int __devinit
get_nativex(void)
1411 tmp
= (read3CE(GR52
) >> 4) & 3;
1414 case 0: x
= 1280; y
= 1024;
1416 case 2: x
= 1024; y
= 768;
1418 case 3: x
= 800; y
= 600;
1420 case 4: x
= 1400; y
= 1050;
1429 output("%dx%d flat panel found\n", x
, y
);
1433 static int __devinit
cybla_pci_probe(struct pci_dev
*dev
,
1434 const struct pci_device_id
*id
)
1436 struct fb_info
*info
;
1437 struct cyblafb_par
*par
;
1439 info
= framebuffer_alloc(sizeof(struct cyblafb_par
), &dev
->dev
);
1441 goto errout_alloc_info
;
1443 info
->pixmap
.addr
= kzalloc(CYBLAFB_PIXMAPSIZE
, GFP_KERNEL
);
1444 if (!info
->pixmap
.addr
) {
1445 output("allocation of pixmap buffer failed!\n");
1446 goto errout_alloc_pixmap
;
1448 info
->pixmap
.size
= CYBLAFB_PIXMAPSIZE
- 4;
1449 info
->pixmap
.buf_align
= 4;
1450 info
->pixmap
.access_align
= 32;
1451 info
->pixmap
.flags
= FB_PIXMAP_SYSTEM
;
1452 info
->pixmap
.scan_align
= 4;
1455 par
->ops
= cyblafb_ops
;
1457 info
->fix
= cyblafb_fix
;
1458 info
->fbops
= &par
->ops
;
1459 info
->fix
= cyblafb_fix
;
1461 if (pci_enable_device(dev
)) {
1462 output("could not enable device!\n");
1465 // might already be requested by vga console or vesafb,
1466 // so we do care about success
1467 if (!request_region(0x3c0, 0x20, "cyblafb")) {
1468 output("region 0x3c0/0x20 already reserved\n");
1473 // Graphics Engine Registers
1475 if (!request_region(GEBase
, 0x100, "cyblafb")) {
1476 output("region %#x/0x100 already reserved\n", GEBase
);
1484 // setup MMIO region
1485 info
->fix
.mmio_start
= pci_resource_start(dev
, 1);
1486 info
->fix
.mmio_len
= 0x20000;
1488 if (!request_mem_region(info
->fix
.mmio_start
,
1489 info
->fix
.mmio_len
, "cyblafb")) {
1490 output("request_mem_region failed for mmio region!\n");
1491 goto errout_mmio_reqmem
;
1494 io_virt
= ioremap_nocache(info
->fix
.mmio_start
, info
->fix
.mmio_len
);
1497 output("ioremap failed for mmio region\n");
1498 goto errout_mmio_remap
;
1500 // setup framebuffer memory ... might already be requested
1501 // by vesafb. Not to fail in case of an unsuccessful request
1502 // is useful if both are loaded.
1503 info
->fix
.smem_start
= pci_resource_start(dev
, 0);
1504 info
->fix
.smem_len
= get_memsize();
1506 if (!request_mem_region(info
->fix
.smem_start
,
1507 info
->fix
.smem_len
, "cyblafb")) {
1508 output("region %#lx/%#x already reserved\n",
1509 info
->fix
.smem_start
, info
->fix
.smem_len
);
1513 info
->screen_base
= ioremap_nocache(info
->fix
.smem_start
,
1514 info
->fix
.smem_len
);
1516 if (!info
->screen_base
) {
1517 output("ioremap failed for smem region\n");
1518 goto errout_smem_remap
;
1521 displaytype
= get_displaytype();
1523 if (displaytype
== DISPLAY_FP
)
1524 nativex
= get_nativex();
1526 info
->flags
= FBINFO_DEFAULT
1527 | FBINFO_HWACCEL_COPYAREA
1528 | FBINFO_HWACCEL_FILLRECT
1529 | FBINFO_HWACCEL_IMAGEBLIT
1531 // | FBINFO_PARTIAL_PAN_OK
1532 | FBINFO_MISC_ALWAYS_SETPAR
;
1534 info
->pseudo_palette
= par
->pseudo_pal
;
1536 if (getstartupmode(info
))
1537 goto errout_findmode
;
1539 fb_alloc_cmap(&info
->cmap
, 256, 0);
1541 if (register_framebuffer(info
)) {
1542 output("Could not register CyBla framebuffer\n");
1543 goto errout_register
;
1546 pci_set_drvdata(dev
, info
);
1549 // normal exit and error paths
1556 iounmap(info
->screen_base
);
1559 release_mem_region(info
->fix
.smem_start
, info
->fix
.smem_len
);
1562 release_mem_region(info
->fix
.mmio_start
, info
->fix
.mmio_len
);
1565 release_region(0x3c0, 32);
1567 kfree(info
->pixmap
.addr
);
1568 errout_alloc_pixmap
:
1569 framebuffer_release(info
);
1571 output("CyblaFB version %s aborting init.\n", VERSION
);
1575 static void __devexit
cybla_pci_remove(struct pci_dev
*dev
)
1577 struct fb_info
*info
= pci_get_drvdata(dev
);
1579 unregister_framebuffer(info
);
1581 iounmap(info
->screen_base
);
1583 release_mem_region(info
->fix
.smem_start
, info
->fix
.smem_len
);
1584 release_mem_region(info
->fix
.mmio_start
, info
->fix
.mmio_len
);
1585 fb_dealloc_cmap(&info
->cmap
);
1587 release_region(GEBase
, 0x100);
1589 release_region(0x3c0, 32);
1590 kfree(info
->pixmap
.addr
);
1591 framebuffer_release(info
);
1592 output("CyblaFB version %s normal exit.\n", VERSION
);
1596 // List of boards that we are trying to support
1598 static struct pci_device_id cybla_devices
[] = {
1599 {PCI_VENDOR_ID_TRIDENT
, CYBERBLADEi1
, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
1603 MODULE_DEVICE_TABLE(pci
, cybla_devices
);
1605 static struct pci_driver cyblafb_pci_driver
= {
1607 .id_table
= cybla_devices
,
1608 .probe
= cybla_pci_probe
,
1609 .remove
= __devexit_p(cybla_pci_remove
)
1612 //=============================================================
1614 // kernel command line example:
1616 // video=cyblafb:1280x1024, bpp=16, ref=50 ...
1618 // modprobe command line example:
1620 // modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
1622 //=============================================================
1624 static int __devinit
cyblafb_init(void)
1627 char *options
= NULL
;
1630 if (fb_get_options("cyblafb", &options
))
1633 if (options
&& *options
)
1634 while ((opt
= strsep(&options
, ",")) != NULL
) {
1637 else if (!strncmp(opt
, "bpp=", 4))
1638 bpp
= simple_strtoul(opt
+ 4, NULL
, 0);
1639 else if (!strncmp(opt
, "ref=", 4))
1640 ref
= simple_strtoul(opt
+ 4, NULL
, 0);
1641 else if (!strncmp(opt
, "fp", 2))
1642 displaytype
= DISPLAY_FP
;
1643 else if (!strncmp(opt
, "crt", 3))
1644 displaytype
= DISPLAY_CRT
;
1645 else if (!strncmp(opt
, "nativex=", 8))
1646 nativex
= simple_strtoul(opt
+ 8, NULL
, 0);
1647 else if (!strncmp(opt
, "center", 6))
1649 else if (!strncmp(opt
, "stretch", 7))
1651 else if (!strncmp(opt
, "pciwb=", 6))
1652 pciwb
= simple_strtoul(opt
+ 6, NULL
, 0);
1653 else if (!strncmp(opt
, "pcirb=", 6))
1654 pcirb
= simple_strtoul(opt
+ 6, NULL
, 0);
1655 else if (!strncmp(opt
, "pciwr=", 6))
1656 pciwr
= simple_strtoul(opt
+ 6, NULL
, 0);
1657 else if (!strncmp(opt
, "pcirr=", 6))
1658 pcirr
= simple_strtoul(opt
+ 6, NULL
, 0);
1659 else if (!strncmp(opt
, "memsize=", 8))
1660 memsize
= simple_strtoul(opt
+ 8, NULL
, 0);
1661 else if (!strncmp(opt
, "verbosity=", 10))
1662 verbosity
= simple_strtoul(opt
+ 10, NULL
, 0);
1667 output("CyblaFB version %s initializing\n", VERSION
);
1668 return pci_register_driver(&cyblafb_pci_driver
);
1671 static void __exit
cyblafb_exit(void)
1673 pci_unregister_driver(&cyblafb_pci_driver
);
1676 module_init(cyblafb_init
);
1677 module_exit(cyblafb_exit
);
1679 MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
1680 MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
1681 MODULE_LICENSE("GPL");