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