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");