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
14 #define CYBLAFB_DEBUG 0
16 #include <linux/config.h>
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.54"
32 static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
34 .type = FB_TYPE_PACKED_PIXELS,
36 .visual = FB_VISUAL_PSEUDOCOLOR,
37 .accel = FB_ACCEL_NONE,
40 static char *mode __devinitdata = NULL;
41 static int bpp __devinitdata = 8;
42 static int ref __devinitdata = 75;
43 static int fp __devinitdata;
44 static int crt __devinitdata;
45 static int memsize __devinitdata;
46 static int vesafb __devinitdata;
56 static int displaytype;
58 static void __iomem * io_virt; // iospace virtual memory address
60 module_param(mode,charp,0);
61 module_param(bpp,int,0);
62 module_param(ref,int,0);
63 module_param(fp,int,0);
64 module_param(crt,int,0);
65 module_param(nativex,int,0);
66 module_param(center,int,0);
67 module_param(stretch,int,0);
68 module_param(pciwb,int,0);
69 module_param(pcirb,int,0);
70 module_param(pciwr,int,0);
71 module_param(pcirr,int,0);
72 module_param(memsize,int,0);
73 module_param(verbosity,int,0);
74 module_param(vesafb,int,0);
76 //=========================================
78 // Port access macros for memory mapped io
80 //=========================================
82 #define out8(r,v) writeb(v,io_virt+r)
83 #define out32(r,v) writel(v,io_virt+r)
84 #define in8(r) readb(io_virt+r)
85 #define in32(r) readl(io_virt+r)
87 //======================================
89 // Hardware access inline functions
91 //======================================
93 static inline unsigned char read3X4(int reg)
99 static inline unsigned char read3C4(int reg)
105 static inline unsigned char read3CE(int reg)
111 static inline void write3X4(int reg,unsigned char val)
117 static inline void write3C4(int reg,unsigned char val)
123 static inline void write3CE(int reg,unsigned char val)
129 static inline void write3C0(int reg,unsigned char val)
131 in8(0x3DA); // read to reset index
136 //=================================================
138 // Enable memory mapped io and unprotect registers
140 //=================================================
142 static inline void enable_mmio(void)
147 inb(0x3C5); // Set NEW mode
148 outb(SR0E,0x3C4); // write enable a lot of extended ports
151 outb(SR11,0x3C4); // write enable those extended ports that
152 outb(0x87,0x3C5); // are not affected by SR0E_New
154 outb(CR1E,0x3d4); // clear write protect bit for port 0x3c2
155 tmp=inb(0x3d5) & 0xBF;
160 outb(inb(0x3D5)|0x01,0x3D5); // Enable mmio, everything else untouched
163 //=================================================
165 // Set pixel clock VCLK1
166 // - multipliers set elswhere
167 // - freq in units of 0.01 MHz
169 //=================================================
171 static void set_vclk(struct cyblafb_par *par, int freq)
178 k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
180 for(n = 0;n<250;n++) { // max 249 is a hardware limit for cybla/i1 !
181 fi = (int)(((5864727*(n+8))/((m+2)*(1<<k)))>>12);
182 if ((di = abs(fi - freq)) < d) {
186 hi = (u8) ((k<<6) | m);
192 output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
193 freq/100,freq%100,(hi&0xc0)>>6,hi&0x3f,lo);
196 //================================================
198 // Cyberblade specific Graphics Engine (GE) setup
200 //================================================
202 static void cyblafb_setup_GE(int pitch,int bpp)
204 int base = (pitch>>3)<<20;
207 case 8: base |= (0<<29); break;
208 case 15: base |= (5<<29); break;
209 case 16: base |= (1<<29); break;
211 case 32: base |= (2<<29); break;
214 write3X4(CR36,0x90); // reset GE
215 write3X4(CR36,0x80); // enable GE
217 out32(GE24,1<<7); // reset all GE pointers
220 write3X4(CR2D,0x00); // GE Timinigs, no delays
222 out32(GEB8,base); // Destination Stride / Buffer Base 0, p 133
223 out32(GEBC,base); // Destination Stride / Buffer Base 1, p 133
224 out32(GEC0,base); // Destination Stride / Buffer Base 2, p 133
225 out32(GEC4,base); // Destination Stride / Buffer Base 3, p 133
226 out32(GEC8,base); // Source Stride / Buffer Base 0, p 133
227 out32(GECC,base); // Source Stride / Buffer Base 1, p 133
228 out32(GED0,base); // Source Stride / Buffer Base 2, p 133
229 out32(GED4,base); // Source Stride / Buffer Base 3, p 133
230 out32(GE6C,0); // Pattern and Style, p 129, ok
233 //=====================================================================
235 // Although this is a .fb_sync function that could be enabled in
236 // cyblafb_ops, we do not include it there. We sync immediately before
237 // new GE operations to improve performance.
239 //=====================================================================
241 static int cyblafb_sync(struct fb_info *info)
243 int status, i=100000;
244 while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
248 // The timeout might be caused by disabled mmio.
250 // - bit CR39 & 1 == 0 upon return, X trident driver bug
251 // - kdm bug (KD_GRAPHICS not set on first switch)
252 // - kernel design flaw (it believes in the correctness
254 // So we make sure that mmio is enabled first ...
256 // show_trace(NULL,&status);
258 while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
261 output("GE Timeout, status: %x\n",status);
262 if(status & 0x80000000)
263 output("Bresenham Engine : Busy\n");
264 if(status & 0x40000000)
265 output("Setup Engine : Busy\n");
266 if(status & 0x20000000)
267 output("SP / DPE : Busy\n");
268 if(status & 0x10000000)
269 output("Memory Interface : Busy\n");
270 if(status & 0x08000000)
271 output("Com Lst Proc : Busy\n");
272 if(status & 0x04000000)
273 output("Block Write : Busy\n");
274 if(status & 0x02000000)
275 output("Command Buffer : Full\n");
276 if(status & 0x01000000)
277 output("RESERVED : Busy\n");
278 if(status & 0x00800000)
279 output("PCI Write Buffer : Busy\n");
280 cyblafb_setup_GE(info->var.xres,
281 info->var.bits_per_pixel);
288 //==============================
290 // Cyberblade specific fillrect
292 //==============================
294 static void cyblafb_fillrect(struct fb_info * info,
295 const struct fb_fillrect *fr)
297 int bpp = info->var.bits_per_pixel;
302 case 8: col = fr->color;
306 case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
309 case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
316 out32(GE48,fr->rop ? 0x66:ROP_S);
317 out32(GE44,0x20000000|1<<19|1<<4|2<<2);
318 out32(GE08,point(fr->dx,fr->dy));
319 out32(GE0C,point(fr->dx+fr->width-1,fr->dy+fr->height-1));
323 //==============================
325 // Cyberblade specific copyarea
327 //==============================
329 static void cyblafb_copyarea(struct fb_info *info,
330 const struct fb_copyarea *ca)
335 s1 = point(ca->sx,ca->sy);
336 s2 = point(ca->sx+ca->width-1,ca->sy+ca->height-1);
337 d1 = point(ca->dx,ca->dy);
338 d2 = point(ca->dx+ca->width-1,ca->dy+ca->height-1);
339 if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
346 out32(GE44,0xa0000000|1<<19|1<<2|direction);
347 out32(GE00,direction?s2:s1);
348 out32(GE04,direction?s1:s2);
349 out32(GE08,direction?d2:d1);
350 out32(GE0C,direction?d1:d2);
354 //=======================================================================
356 // Cyberblade specific imageblit
358 // Accelerated for the most usual case, blitting 1-bit deep character
359 // character images. Everything else is passed to the generic imageblit.
361 //=======================================================================
363 static void cyblafb_imageblit(struct fb_info *info,
364 const struct fb_image *image)
370 int bpp = info->var.bits_per_pixel;
372 int index_end=image->height * image->width / 8;
373 int width_dds=image->width / 32;
374 int width_dbs=image->width % 32;
376 if (image->depth != 1 || bpp < 8 || bpp > 32 || bpp % 8 != 0 ||
377 image->width % 8 != 0 || image->width == 0 || image->height == 0) {
378 cfb_imageblit(info,image);
382 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
383 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
384 fgcol = ((u32*)(info->pseudo_palette))[image->fg_color];
385 bgcol = ((u32*)(info->pseudo_palette))[image->bg_color];
387 fgcol = image->fg_color;
388 bgcol = image->bg_color;
393 fgcol |= fgcol <<8; fgcol |= fgcol <<16;
394 bgcol |= bgcol <<8; bgcol |= bgcol <<16;
408 out32(GE44,0xa0000000 | 1<<20 | 1<<19);
409 out32(GE08,point(image->dx,image->dy));
410 out32(GE0C,point(image->dx+image->width-1,image->dy+image->height-1));
412 while(index < index_end) {
413 for(i=0;i<width_dds;i++) {
414 out32(GE9C,*((u32*) ((u32)image->data + index)));
419 case 8: out32(GE9C,*((u8*)((u32)image->data+index)));
422 case 16: out32(GE9C,*((u16*)((u32)image->data+index)));
425 case 24: out32(GE9C,(u32)(*((u16*)((u32)image->data+index))) |
426 (u32)(*((u8*)((u32)image->data+index+2)))<<16);
433 //==========================================================
435 // Check if video mode is acceptable. We change var->??? if
436 // video mode is slightly off or return error otherwise.
437 // info->??? must not be changed!
439 //==========================================================
441 static int cyblafb_check_var(struct fb_var_screeninfo *var,
442 struct fb_info *info)
444 int bpp = var->bits_per_pixel;
448 // we try to support 8, 16, 24 and 32 bpp modes,
451 // there is a 24 bpp mode, but for now we change requests to 32 bpp
452 // (This is what tridentfb does ... will be changed in the future)
455 if ( bpp % 8 != 0 || bpp < 8 || bpp >32)
458 bpp = var->bits_per_pixel = 32;
461 // interlaced modes are broken, fail if one is requested
463 if (var->vmode & FB_VMODE_INTERLACED)
467 // fail if requested resolution is higher than physical
468 // flatpanel resolution
470 if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
474 // xres != xres_virtual is broken, fail if such an
475 // unusual mode is requested
477 if (var->xres != var->xres_virtual)
481 // we do not allow vclk to exceed 230 MHz
483 if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000)
487 // calc max yres_virtual that would fit in memory
488 // and max yres_virtual that could be used for scrolling
489 // and use minimum of the results as maxvyres
491 // adjust vyres_virtual to maxvyres if necessary
492 // fail if requested yres is bigger than maxvyres
494 s = (0x1fffff / (var->xres * bpp/8)) + var->yres;
495 t = info->fix.smem_len / (var->xres * bpp/8);
496 maxvyres = t < s ? t : s;
497 if (maxvyres < var->yres_virtual)
498 var->yres_virtual=maxvyres;
499 if (maxvyres < var->yres)
505 var->green.offset = 0;
506 var->blue.offset = 0;
508 var->green.length = 6;
509 var->blue.length = 6;
512 var->red.offset = 11;
513 var->green.offset = 5;
514 var->blue.offset = 0;
516 var->green.length = 6;
517 var->blue.length = 5;
520 var->red.offset = 16;
521 var->green.offset = 8;
522 var->blue.offset = 0;
524 var->green.length = 8;
525 var->blue.length = 8;
535 //=====================================================================
539 // The datasheets defines crt start address to be 20 bits wide and
540 // to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
541 // CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
542 // it, so it is also safe to be used here. BTW: datasheet CR0E on page
543 // 90 really is CR1E, the real CRE is documented on page 72.
545 //=====================================================================
547 static int cyblafb_pan_display(struct fb_var_screeninfo *var,
548 struct fb_info *info)
552 offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32;
553 info->var.xoffset = var->xoffset;
554 info->var.yoffset = var->yoffset;
556 write3X4(CR0D,offset & 0xFF);
557 write3X4(CR0C,(offset & 0xFF00) >> 8);
558 write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11));
559 write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17));
560 write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15));
565 //============================================
567 // This will really help in case of a bug ...
568 // dump most gaphics core registers.
570 //============================================
572 static void regdump(struct cyblafb_par *par)
580 for(i=0; i<=0xff; i++) {
582 printk("CR%02x=%02x ",i,inb(0x3d5));
588 outb(inb(0x3cf) | 0x40,0x3cf);
589 for(i=0; i<=0x1f; i++) {
590 if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) {
592 printk("CR%02x=%02x ",i,inb(0x3d5));
599 outb(inb(0x3cf) & 0xbf,0x3cf);
602 for(i=0; i<=0x7f; i++) {
604 printk("GR%02x=%02x ",i,inb(0x3cf));
610 for(i=0; i<=0xff; i++) {
612 printk("SR%02x=%02x ",i,inb(0x3c5));
618 for(i=0; i <= 0x1F; i++) {
619 inb(0x3da); // next access is index!
621 printk("AR%02x=%02x ",i,inb(0x3c1));
627 inb(0x3DA); // reset internal flag to 3c0 index
628 outb(0x20,0x3C0); // enable attr
633 //======================================
635 // Set hardware to requested video mode
637 //======================================
639 static int cyblafb_set_par(struct fb_info *info)
641 struct cyblafb_par *par = info->par;
643 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch,
644 vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
645 struct fb_var_screeninfo *var = &info->var;
646 int bpp = var->bits_per_pixel;
650 output("Switching to new mode: "
651 "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
652 var->xres,var->yres,var->xres_virtual,
653 var->yres_virtual,var->bits_per_pixel,var->pixclock,
654 var->left_margin,var->right_margin,var->upper_margin,
655 var->lower_margin,var->hsync_len,var->vsync_len);
657 htotal = (var->xres + var->left_margin + var->right_margin +
658 var->hsync_len) / 8 - 5;
659 hdispend = var->xres/8 - 1;
660 hsyncstart = (var->xres + var->right_margin)/8;
661 hsyncend = var->hsync_len/8;
662 hblankstart = hdispend + 1;
663 hblankend = htotal + 3; // should be htotal + 5, bios does it this way
664 preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3);
666 vtotal = var->yres + var->upper_margin + var->lower_margin +
668 vdispend = var->yres - 1;
669 vsyncstart = var->yres + var->lower_margin;
670 vblankstart = var->yres;
671 vblankend = vtotal; // should be vtotal + 2, but bios does it this way
672 vsyncend = var->vsync_len;
674 enable_mmio(); // necessary! ... check X ...
676 write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
680 if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
682 // stretch or center ?
686 write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on
689 write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80);
690 write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80);
694 write3CE(GR52,(read3CE(GR52) & 0x7C) | 1);
695 write3CE(GR53,(read3CE(GR53) & 0x7C) | 1);
707 write3X4(CR00,htotal & 0xFF);
708 write3X4(CR01,hdispend & 0xFF);
709 write3X4(CR02,hblankstart & 0xFF);
710 write3X4(CR03,hblankend & 0x1F);
711 write3X4(CR04,hsyncstart & 0xFF);
712 write3X4(CR05,(hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
713 write3X4(CR06,vtotal & 0xFF);
714 write3X4(CR07,(vtotal & 0x100) >> 8 |
715 (vdispend & 0x100) >> 7 |
716 (vsyncstart & 0x100) >> 6 |
717 (vblankstart & 0x100) >> 5 |
719 (vtotal & 0x200) >> 4 |
720 (vdispend & 0x200) >> 3 |
721 (vsyncstart & 0x200) >> 2);
723 write3X4(CR09,(vblankstart & 0x200) >> 4 | 0x40 | // FIX !!!
724 ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
725 write3X4(CR0A,0); // Init to some reasonable default
726 write3X4(CR0B,0); // Init to some reasonable default
727 write3X4(CR0C,0); // Offset 0
728 write3X4(CR0D,0); // Offset 0
729 write3X4(CR0E,0); // Init to some reasonable default
730 write3X4(CR0F,0); // Init to some reasonable default
731 write3X4(CR10,vsyncstart & 0xFF);
732 write3X4(CR11,(vsyncend & 0x0F));
733 write3X4(CR12,vdispend & 0xFF);
734 write3X4(CR13,((info->var.xres * bpp)/(4*16)) & 0xFF);
735 write3X4(CR14,0x40); // double word mode
736 write3X4(CR15,vblankstart & 0xFF);
737 write3X4(CR16,vblankend & 0xFF);
740 // CR19: needed for interlaced modes ... ignore it for now
741 write3X4(CR1A,0x07); // Arbitration Control Counter 1
742 write3X4(CR1B,0x07); // Arbitration Control Counter 2
743 write3X4(CR1C,0x07); // Arbitration Control Counter 3
744 write3X4(CR1D,0x00); // Don't know, doesn't hurt ;-)
745 write3X4(CR1E,(info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
746 // CR1F: do not set, contains BIOS info about memsize
747 write3X4(CR20,0x20); // enabe wr buf, disable 16bit planar mode
748 write3X4(CR21,0x20); // enable linear memory access
749 // CR22: RO cpu latch readback
751 // CR24: RO AR flag state
752 // CR25: RAMDAC rw timing, pclk buffer tristate control ????
754 write3X4(CR27,(vdispend & 0x400) >> 6 |
755 (vsyncstart & 0x400) >> 5 |
756 (vblankstart & 0x400) >> 4 |
757 (vtotal & 0x400) >> 3 |
760 write3X4(CR29,(read3X4(CR29) & 0xCF) |
761 ((((info->var.xres * bpp) / (4*16)) & 0x300) >>4));
762 write3X4(CR2A,read3X4(CR2A) | 0x40);
763 write3X4(CR2B,(htotal & 0x100) >> 8 |
764 (hdispend & 0x100) >> 7 |
765 // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
766 (hsyncstart & 0x100) >> 5 |
767 (hblankstart & 0x100) >> 4);
769 // CR2D: initialized in cyblafb_setup_GE()
770 write3X4(CR2F,0x92); // conservative, better signal quality
775 // CR34: disabled in CR36
776 // CR35: disabled in CR36
777 // CR36: initialized in cyblafb_setup_GE
778 // CR37: i2c, ignore for now
779 write3X4(CR38,(bpp == 8) ? 0x00 : //
780 (bpp == 16) ? 0x05 : // highcolor
781 (bpp == 24) ? 0x29 : // packed 24bit truecolor
782 (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
783 write3X4(CR39,0x01 | // MMIO enable
784 (pcirb ? 0x02 : 0) | // pci read burst enable
785 (pciwb ? 0x04 : 0)); // pci write burst enable
786 write3X4(CR55,0x1F | // pci clocks * 2 for STOP# during 1st data phase
787 (pcirr ? 0x40 : 0) | // pci read retry enable
788 (pciwr ? 0x80 : 0)); // pci write retry enable
789 write3X4(CR56,preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01)|2 : 0);
790 write3X4(CR57,preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
791 write3X4(CR58,0x82); // Bios does this .... don't know more
796 write3C4(SR01,1); //set char clock 8 dots wide
797 write3C4(SR02,0x0F); //enable 4 maps needed in chain4 mode
798 write3C4(SR03,0); //no character map select
799 write3C4(SR04,0x0E); //memory mode: ext mem, even, chain4
802 in8(0x3C5); // Set NEW mode
803 write3C4(SR0D,0x00); // test ... check
805 set_vclk(par,(bpp==32 ? 200000000 : 100000000)/
806 info->var.pixclock); //SR18,SR19
811 write3CE(GR00,0x00); // test ... check
812 write3CE(GR01,0x00); // test ... check
813 write3CE(GR02,0x00); // test ... check
814 write3CE(GR03,0x00); // test ... check
815 write3CE(GR04,0x00); // test ... check
816 write3CE(GR05,0x40); // no CGA compat,allow 256 col
817 write3CE(GR06,0x05); // graphics mode
818 write3CE(GR07,0x0F); // planes?
819 write3CE(GR08,0xFF); // test ... check
820 write3CE(GR0F,(bpp==32)?0x1A:0x12); // div vclk by 2 if 32bpp, chain4
821 write3CE(GR20,0xC0); // test ... check
822 write3CE(GR2F,0xA0); // PCLK = VCLK, no skew,
827 for(i = 0;i < 0x10;i++) // set AR00 .. AR0f
829 write3C0(AR10,0x41); // graphics mode and support 256 color modes
830 write3C0(AR12,0x0F); // planes
831 write3C0(AR13,0); // horizontal pel panning
832 in8(0x3DA); // reset internal flag to 3c0 index
833 out8(0x3C0,0x20); // enable attr
836 // Setup hidden RAMDAC command register
838 in8(0x3C8); // these reads are
839 in8(0x3C6); // necessary to
840 in8(0x3C6); // unmask the RAMDAC
841 in8(0x3C6); // command reg, otherwise
842 in8(0x3C6); // we would write the pixelmask reg!
843 out8(0x3C6,(bpp == 8) ? 0x00 : // 256 colors
844 (bpp == 15) ? 0x10 : //
845 (bpp == 16) ? 0x30 : // hicolor
846 (bpp == 24) ? 0xD0 : // truecolor
847 (bpp == 32) ? 0xD0 : 0); // truecolor
851 // GR31 is not mentioned in the datasheet
853 if (displaytype == DISPLAY_FP)
854 write3CE(GR31,(read3CE(GR31) & 0x8F) |
855 ((info->var.yres > 1024) ? 0x50 :
856 (info->var.yres > 768) ? 0x30 :
857 (info->var.yres > 600) ? 0x20 :
858 (info->var.yres > 480) ? 0x10 : 0));
860 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
861 : FB_VISUAL_TRUECOLOR;
862 info->fix.line_length = info->var.xres * (bpp >> 3);
863 info->cmap.len = (bpp == 8) ? 256: 16;
866 // init acceleration engine
868 cyblafb_setup_GE(info->var.xres,info->var.bits_per_pixel);
875 //========================
877 // Set one color register
879 //========================
881 static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
882 unsigned blue, unsigned transp,
883 struct fb_info *info)
885 int bpp = info->var.bits_per_pixel;
887 if (regno >= info->cmap.len)
894 out8(0x3C9,green>>10);
895 out8(0x3C9,blue>>10);
897 } else if (bpp == 16) // RGB 565
898 ((u32*)info->pseudo_palette)[regno] =
900 ((green & 0xFC00) >> 5) |
901 ((blue & 0xF800) >> 11);
902 else if (bpp == 32) // ARGB 8888
903 ((u32*)info->pseudo_palette)[regno] =
904 ((transp & 0xFF00) <<16) |
905 ((red & 0xFF00) << 8) |
907 ((blue & 0xFF00)>>8);
912 //==========================================================
914 // Try blanking the screen. For flat panels it does nothing
916 //==========================================================
918 static int cyblafb_blank(int blank_mode, struct fb_info *info)
920 unsigned char PMCont,DPMSCont;
922 if (displaytype == DISPLAY_FP)
925 out8(0x83C8,0x04); // DPMS Control
926 PMCont = in8(0x83C6) & 0xFC;
928 DPMSCont = read3CE(GR23) & 0xFC;
932 case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On
933 case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On
937 case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
941 case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
945 case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off
951 write3CE(GR23,DPMSCont);
955 // let fbcon do a softblank for us
957 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
960 static struct fb_ops cyblafb_ops __devinitdata = {
961 .owner = THIS_MODULE,
962 .fb_setcolreg = cyblafb_setcolreg,
963 .fb_pan_display = cyblafb_pan_display,
964 .fb_blank = cyblafb_blank,
965 .fb_check_var = cyblafb_check_var,
966 .fb_set_par = cyblafb_set_par,
967 .fb_fillrect = cyblafb_fillrect,
968 .fb_copyarea= cyblafb_copyarea,
969 .fb_imageblit = cyblafb_imageblit,
970 .fb_cursor = soft_cursor,
973 //==========================================================================
975 // getstartupmode() decides about the inital video mode
977 // There is no reason to use modedb, a lot of video modes there would
978 // need altered timings to display correctly. So I decided that it is much
979 // better to provide a limited optimized set of modes plus the option of
980 // using the mode in effect at startup time (might be selected using the
981 // vga=??? paramter). After that the user might use fbset to select any
982 // mode he likes, check_var will not try to alter geometry parameters as
983 // it would be necessary otherwise.
985 //==========================================================================
987 static int __devinit getstartupmode(struct fb_info *info)
989 u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
990 vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend,
991 cr00,cr01,cr02,cr03,cr04,cr05,cr2b,
992 cr06,cr07,cr09,cr10,cr11,cr12,cr15,cr16,cr27,
996 fi,pxclkdiv,vclkdiv,tmp,i;
999 int xres; int yres; int vyres; int bpp; int pxclk;
1000 int left_margin; int right_margin; int upper_margin;
1001 int lower_margin; int hsync_len; int vsync_len;
1003 { 0, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0},
1004 { 640, 480, 3756, 0, 0, -40, 24, 17, 0, 216, 3},
1005 { 800, 600, 3221, 0, 0, 96, 24, 14, 0, 136, 11},
1006 {1024, 768, 2815, 0, 0, 144, 24, 29, 0, 120, 3},
1007 {1280, 1024, 2662, 0, 0, 232, 16, 39, 0, 160, 3}
1010 outb(0x00,0x3d4); cr00=inb(0x3d5); outb(0x01,0x3d4); cr01=inb(0x3d5);
1011 outb(0x02,0x3d4); cr02=inb(0x3d5); outb(0x03,0x3d4); cr03=inb(0x3d5);
1012 outb(0x04,0x3d4); cr04=inb(0x3d5); outb(0x05,0x3d4); cr05=inb(0x3d5);
1013 outb(0x06,0x3d4); cr06=inb(0x3d5); outb(0x07,0x3d4); cr07=inb(0x3d5);
1014 outb(0x09,0x3d4); cr09=inb(0x3d5); outb(0x10,0x3d4); cr10=inb(0x3d5);
1015 outb(0x11,0x3d4); cr11=inb(0x3d5); outb(0x12,0x3d4); cr12=inb(0x3d5);
1016 outb(0x15,0x3d4); cr15=inb(0x3d5); outb(0x16,0x3d4); cr16=inb(0x3d5);
1017 outb(0x27,0x3d4); cr27=inb(0x3d5); outb(0x2b,0x3d4); cr2b=inb(0x3d5);
1018 outb(0x38,0x3d4); cr38=inb(0x3d5); outb(0x0b,0x3c4); inb(0x3c5);
1019 outb(0x0d,0x3c4); sr0d=inb(0x3c5); outb(0x18,0x3c4); sr18=inb(0x3c5);
1020 outb(0x19,0x3c4); sr19=inb(0x3c5); outb(0x0f,0x3ce); gr0f=inb(0x3cf);
1022 htotal = cr00 | (cr2b & 0x01) << 8;
1023 hdispend = cr01 | (cr2b & 0x02) << 7;
1024 hblankstart = cr02 | (cr2b & 0x10) << 4;
1025 hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
1026 hsyncstart = cr04 | (cr2b & 0x08) << 5;
1027 hsyncend = cr05 & 0x1f;
1029 modedb[0].xres = hblankstart * 8;
1030 modedb[0].hsync_len = hsyncend * 8;
1031 modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
1032 modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
1033 modedb[0].right_margin - modedb[0].hsync_len;
1035 vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
1036 | (cr27 & 0x80) << 3;
1037 vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
1038 | (cr27 & 0x10) << 6;
1039 vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
1040 | (cr27 & 0x20) << 5;
1041 vsyncend = cr11 & 0x0f;
1042 vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
1043 | (cr27 & 0x40) << 4;
1046 modedb[0].yres = vdispend + 1;
1047 modedb[0].vsync_len = vsyncend;
1048 modedb[0].lower_margin = vsyncstart - modedb[0].yres;
1049 modedb[0].upper_margin = vtotal - modedb[0].yres -
1050 modedb[0].lower_margin - modedb[0].vsync_len + 2;
1053 modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
1056 fi = ((5864727*(sr18+8))/(((sr19&0x3f)+2)*(1<<((sr19&0xc0)>>6))))>>12;
1057 pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
1059 vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
1060 modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;
1063 output("detected startup mode: "
1064 "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
1065 modedb[0].xres,modedb[0].yres,modedb[0].xres,
1066 modedb[0].bpp,modedb[0].pxclk,modedb[0].left_margin,
1067 modedb[0].right_margin,modedb[0].upper_margin,
1068 modedb[0].lower_margin,modedb[0].hsync_len,
1069 modedb[0].vsync_len);
1072 // We use this goto target in case of a failed check_var. No, I really
1073 // do not want to do it in another way!
1078 i = (mode == NULL) ? 0 :
1079 !strncmp(mode,"640x480",7) ? 1 :
1080 !strncmp(mode,"800x600",7) ? 2 :
1081 !strncmp(mode,"1024x768",8) ? 3 :
1082 !strncmp(mode,"1280x1024",9) ? 4 : 0;
1084 ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
1087 info->var.pixclock = modedb[i].pxclk;
1088 info->var.bits_per_pixel = modedb[i].bpp;
1090 info->var.pixclock = (100000000 /
1091 ((modedb[i].left_margin + modedb[i].xres +
1092 modedb[i].right_margin + modedb[i].hsync_len
1094 modedb[i].upper_margin + modedb[i].yres +
1095 modedb[i].lower_margin + modedb[i].vsync_len
1099 info->var.bits_per_pixel = bpp;
1102 info->var.left_margin = modedb[i].left_margin;
1103 info->var.right_margin = modedb[i].right_margin;
1104 info->var.xres = modedb[i].xres;
1105 info->var.xres_virtual = modedb[i].xres;
1106 info->var.xoffset = 0;
1107 info->var.hsync_len = modedb[i].hsync_len;
1108 info->var.upper_margin = modedb[i].upper_margin;
1109 info->var.yres = modedb[i].yres;
1110 info->var.yres_virtual = modedb[i].vyres;
1111 info->var.yoffset = 0;
1112 info->var.lower_margin = modedb[i].lower_margin;
1113 info->var.vsync_len = modedb[i].vsync_len;
1115 info->var.vmode = FB_VMODE_NONINTERLACED;
1117 if(cyblafb_check_var(&info->var,info)) {
1118 // 640x480-8@75 should really never fail. One case would
1119 // be fp == 1 and nativex < 640 ... give up then
1120 if(i==1 && bpp == 8 && ref == 75){
1121 output("Can't find a valid mode :-(\n");
1124 // Our detected mode is unlikely to fail. If it does,
1125 // try 640x480-8@75 ...
1130 output("Detected mode failed check_var! "
1131 "Trying 640x480-8@75\n");
1134 // A specified video mode failed for some reason.
1135 // Try the startup mode first
1136 output("Specified mode '%s' failed check! "
1137 "Falling back to startup mode.\n",mode);
1146 //========================================================
1148 // Detect activated memory size. Undefined values require
1149 // memsize parameter.
1151 //========================================================
1153 static unsigned int __devinit get_memsize(void)
1161 tmp = read3X4(CR1F) & 0x0F;
1163 case 0x03: k = 1 * Mb; break;
1164 case 0x07: k = 2 * Mb; break;
1165 case 0x0F: k = 4 * Mb; break;
1166 case 0x04: k = 8 * Mb; break;
1169 output("Unknown memory size code %x in CR1F."
1170 " We default to 1 Mb for now, please"
1171 " do provide a memsize parameter!\n",
1177 output("framebuffer size = %d Kb\n",k/Kb);
1181 //=========================================================
1183 // Detect if a flat panel monitor connected to the special
1184 // interface is active. Override is possible by fp and crt
1187 //=========================================================
1189 static unsigned int __devinit get_displaytype(void)
1195 return (read3CE(GR33) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
1198 //=====================================
1200 // Get native resolution of flat panel
1202 //=====================================
1204 static int __devinit get_nativex(void)
1211 tmp = (read3CE(GR52) >> 4) & 3;
1214 case 0: x = 1280; y = 1024; break;
1215 case 2: x = 1024; y = 768; break;
1216 case 3: x = 800; y = 600; break;
1217 case 4: x = 1400; y = 1050; break;
1219 default: x = 640; y = 480; break;
1223 output("%dx%d flat panel found\n",x,y);
1227 static int __devinit cybla_pci_probe(struct pci_dev * dev,
1228 const struct pci_device_id * id)
1230 struct fb_info *info;
1231 struct cyblafb_par *par;
1233 info = framebuffer_alloc(sizeof(struct cyblafb_par),&dev->dev);
1239 par->ops = cyblafb_ops;
1241 info->fix = cyblafb_fix;
1242 info->fbops = &par->ops;
1243 info->fix = cyblafb_fix;
1245 if (pci_enable_device(dev)) {
1246 output("could not enable device!\n");
1250 // might already be requested by vga console or vesafb,
1251 // so we do care about success
1252 request_region(0x3c0,32,"cyblafb");
1255 // Graphics Engine Registers
1257 request_region(GEBase,0x100,"cyblafb");
1263 // setup MMIO region
1264 info->fix.mmio_start = pci_resource_start(dev,1);
1265 info->fix.mmio_len = 0x20000;
1267 if (!request_mem_region(info->fix.mmio_start,
1268 info->fix.mmio_len,"cyblafb")) {
1269 output("request_mem_region failed for mmio region!\n");
1270 goto errout_mmio_reqmem;
1273 io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
1276 output("ioremap failed for mmio region\n");
1277 goto errout_mmio_remap;
1280 // setup framebuffer memory ... might already be requested
1281 // by vesafb. Not to fail in case of an unsuccessful request
1282 // is useful for the development cycle
1283 info->fix.smem_start = pci_resource_start(dev,0);
1284 info->fix.smem_len = get_memsize();
1286 if (!request_mem_region(info->fix.smem_start,
1287 info->fix.smem_len,"cyblafb")) {
1288 output("request_mem_region failed for smem region!\n");
1290 goto errout_smem_req;
1293 info->screen_base = ioremap_nocache(info->fix.smem_start,
1294 info->fix.smem_len);
1296 if (!info->screen_base) {
1297 output("ioremap failed for smem region\n");
1298 goto errout_smem_remap;
1301 displaytype = get_displaytype();
1303 if(displaytype == DISPLAY_FP)
1304 nativex = get_nativex();
1307 // FBINFO_HWACCEL_YWRAP .... does not work (could be made to work?)
1308 // FBINFO_PARTIAL_PAN_OK .... is not ok
1309 // FBINFO_READS_FAST .... is necessary for optimal scrolling
1311 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN
1312 | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT
1313 | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST;
1315 info->pseudo_palette = par->pseudo_pal;
1317 if(getstartupmode(info))
1318 goto errout_findmode;
1320 fb_alloc_cmap(&info->cmap,256,0);
1322 if (register_framebuffer(info)) {
1323 output("Could not register CyBla framebuffer\n");
1324 goto errout_register;
1327 pci_set_drvdata(dev,info);
1330 // normal exit and error paths
1337 iounmap(info->screen_base);
1339 release_mem_region(info->fix.smem_start,
1340 info->fix.smem_len);
1344 release_mem_region(info->fix.mmio_start,
1345 info->fix.mmio_len);
1347 // release_region(0x3c0,32);
1349 framebuffer_release(info);
1351 output("CyblaFB version %s aborting init.\n",VERSION);
1355 static void __devexit cybla_pci_remove(struct pci_dev *dev)
1357 struct fb_info *info = pci_get_drvdata(dev);
1359 unregister_framebuffer(info);
1361 iounmap(info->screen_base);
1362 release_mem_region(info->fix.smem_start,info->fix.smem_len);
1363 release_mem_region(info->fix.mmio_start,info->fix.mmio_len);
1364 fb_dealloc_cmap(&info->cmap);
1365 framebuffer_release(info);
1366 output("CyblaFB version %s normal exit.\n",VERSION);
1370 // List of boards that we are trying to support
1372 static struct pci_device_id cybla_devices[] = {
1373 {PCI_VENDOR_ID_TRIDENT,CYBERBLADEi1,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1377 MODULE_DEVICE_TABLE(pci,cybla_devices);
1379 static struct pci_driver cyblafb_pci_driver = {
1381 .id_table = cybla_devices,
1382 .probe = cybla_pci_probe,
1383 .remove = __devexit_p(cybla_pci_remove)
1386 //=============================================================
1388 // kernel command line example:
1390 // video=cyblafb:1280x1024,bpp=16,ref=50 ...
1392 // modprobe command line example:
1394 // modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
1396 //=============================================================
1398 static int __devinit cyblafb_init(void)
1401 char *options = NULL;
1404 if (fb_get_options("cyblafb",&options))
1407 if (options && *options)
1408 while((opt = strsep(&options,",")) != NULL ) {
1409 if (!*opt) continue;
1410 else if (!strncmp(opt,"bpp=",4))
1411 bpp = simple_strtoul(opt+4,NULL,0);
1412 else if (!strncmp(opt,"ref=",4))
1413 ref = simple_strtoul(opt+4,NULL,0);
1414 else if (!strncmp(opt,"fp",2))
1415 displaytype = DISPLAY_FP;
1416 else if (!strncmp(opt,"crt",3))
1417 displaytype = DISPLAY_CRT;
1418 else if (!strncmp(opt,"nativex=",8))
1419 nativex = simple_strtoul(opt+8,NULL,0);
1420 else if (!strncmp(opt,"center",6))
1422 else if (!strncmp(opt,"stretch",7))
1424 else if (!strncmp(opt,"pciwb=",6))
1425 pciwb = simple_strtoul(opt+6,NULL,0);
1426 else if (!strncmp(opt,"pcirb=",6))
1427 pcirb = simple_strtoul(opt+6,NULL,0);
1428 else if (!strncmp(opt,"pciwr=",6))
1429 pciwr = simple_strtoul(opt+6,NULL,0);
1430 else if (!strncmp(opt,"pcirr=",6))
1431 pcirr = simple_strtoul(opt+6,NULL,0);
1432 else if (!strncmp(opt,"memsize=",8))
1433 memsize = simple_strtoul(opt+8,NULL,0);
1434 else if (!strncmp(opt,"verbosity=",10))
1435 verbosity = simple_strtoul(opt+10,NULL,0);
1436 else if (!strncmp(opt,"vesafb",6))
1442 output("CyblaFB version %s initializing\n",VERSION);
1443 return pci_module_init(&cyblafb_pci_driver);
1446 static void __exit cyblafb_exit(void)
1448 pci_unregister_driver(&cyblafb_pci_driver);
1451 module_init(cyblafb_init);
1452 module_exit(cyblafb_exit);
1454 MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
1455 MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
1456 MODULE_LICENSE("GPL");