2 * Frame buffer driver for Trident Blade and Image series
4 * Copyright 2001,2002 - Jani Monoses <jani@iv.ro>
7 * CREDITS:(in order of appearance)
8 * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
9 * Special thanks ;) to Mattia Crivellini <tia@mclink.it>
10 * much inspired by the XFree86 4.x Trident driver sources by Alan Hourihane
12 * Francesco Salvestrini <salvestrini@users.sf.net> XP support,code,suggestions
14 * timing value tweaking so it looks good on every monitor in every mode
18 #include <linux/config.h>
19 #include <linux/module.h>
21 #include <linux/init.h>
22 #include <linux/pci.h>
24 #include <linux/delay.h>
25 #include <video/trident.h>
27 #define VERSION "0.7.8-NEWAPI"
29 struct tridentfb_par {
31 unsigned long io_virt; //iospace virtual memory address
34 unsigned char eng_oper; //engine operation...
35 static struct fb_ops tridentfb_ops;
37 static struct tridentfb_par default_par;
39 /* FIXME:kmalloc these 3 instead */
40 static struct fb_info fb_info;
41 static int pseudo_pal[16];
44 static struct fb_var_screeninfo default_var;
46 static struct fb_fix_screeninfo tridentfb_fix = {
48 .type = FB_TYPE_PACKED_PIXELS,
50 .visual = FB_VISUAL_PSEUDOCOLOR,
51 .accel = FB_ACCEL_NONE,
56 static int defaultaccel;
57 static int displaytype;
60 /* defaults which are normally overriden by user values */
63 static char * mode = "640x480";
79 MODULE_PARM(mode,"s");
81 MODULE_PARM(center,"i");
82 MODULE_PARM(stretch,"i");
83 MODULE_PARM(noaccel,"i");
84 MODULE_PARM(memsize,"i");
85 MODULE_PARM(memdiff,"i");
86 MODULE_PARM(nativex,"i");
96 return ((id == BLADE3D) || (id == CYBERBLADEE4) ||
97 (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) ||
98 (id == CYBER9397) || (id == CYBER9397DVD) ||
99 (id == CYBER9520) || (id == CYBER9525DVD) ||
100 (id == IMAGE975) || (id == IMAGE985) ||
101 (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) ||
102 (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) ||
103 (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) ||
104 (id == CYBERBLADEXPAi1));
123 case CYBERBLADEXPAi1:
131 case CYBERBLADEi7: /* VIA MPV4 integrated version */
134 /* case CYBERBLDAEXPm8: Strange */
135 /* case CYBERBLDAEXPm16: Strange */
140 #define CRT 0x3D0 //CRTC registers offset for color display
143 #define TRIDENT_MMIO 1
147 #define t_outb(val,reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg)
148 #define t_inb(reg) readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg)
150 #define t_outb(val,reg) outb(val,reg)
151 #define t_inb(reg) inb(reg)
155 static struct accel_switch {
156 void (*init_accel)(int,int);
157 void (*wait_engine)(void);
158 void (*fill_rect)(__u32,__u32,__u32,__u32,__u32,__u32);
159 void (*copy_rect)(__u32,__u32,__u32,__u32,__u32,__u32);
162 #define writemmr(r,v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r)
163 #define readmmr(r) readl(((struct tridentfb_par *)fb_info.par)->io_virt + r)
168 * Blade specific acceleration.
171 #define point(x,y) ((y)<<16|(x))
183 static void blade_init_accel(int pitch,int bpp)
185 int v1 = (pitch>>3)<<20;
188 case 8:tmp = 0;break;
189 case 15:tmp = 5;break;
190 case 16:tmp = 1;break;
192 case 32:tmp = 2;break;
206 static void blade_wait_engine(void)
208 while(readmmr(STA) & 0xFA800000);
211 static void blade_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop)
214 writemmr(ROP,rop ? 0x66:ROP_S);
215 writemmr(CMD,0x20000000|1<<19|1<<4|2<<2);
217 writemmr(DR1,point(x,y));
218 writemmr(DR2,point(x+w-1,y+h-1));
221 static void blade_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
226 s2 = point(x1+w-1,y1+h-1);
228 d2 = point(x2+w-1,y2+h-1);
230 if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
235 writemmr(CMD,0xE0000000|1<<19|1<<4|1<<2|direction);
237 writemmr(SR1,direction?s2:s1);
238 writemmr(SR2,direction?s1:s2);
239 writemmr(DR1,direction?d2:d1);
240 writemmr(DR2,direction?d1:d2);
243 static struct accel_switch accel_blade = {
252 * BladeXP specific acceleration functions
256 #define masked_point(x,y) ((y & 0xffff)<<16|(x & 0xffff))
258 static void xp_init_accel(int pitch,int bpp)
264 case 8: x = 0; break;
265 case 16: x = 1; break;
266 case 24: x = 3; break;
267 case 32: x = 2; break;
270 switch (pitch << (bpp >> 3)) {
272 case 512: x |= 0x00; break;
273 case 1024: x |= 0x04; break;
274 case 2048: x |= 0x08; break;
275 case 4096: x |= 0x0C; break;
283 case 8: tmp = 18; break;
285 case 16: tmp = 19; break;
287 case 32: tmp = 20; break;
297 static void xp_wait_engine(void)
305 busy = t_inb(STA) & 0x80;
309 if (count == 10000000) {
315 t_outb(0x00, 0x2120);
322 static void xp_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop)
324 writemmr(0x2127,ROP_P);
326 writemmr(0x2128,0x4000);
327 writemmr(0x2140,masked_point(h,w));
328 writemmr(0x2138,masked_point(y,x));
330 t_outb(eng_oper,0x2125);
333 static void xp_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
336 __u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
340 if ((x1 < x2) && (y1 == y2)) {
358 writemmr(0x2128,direction);
359 t_outb(ROP_S,0x2127);
360 writemmr(0x213C,masked_point(y1_tmp,x1_tmp));
361 writemmr(0x2138,masked_point(y2_tmp,x2_tmp));
362 writemmr(0x2140,masked_point(h,w));
366 static struct accel_switch accel_xp = {
375 * Image specific acceleration functions
377 static void image_init_accel(int pitch,int bpp)
381 case 8:tmp = 0;break;
382 case 15:tmp = 5;break;
383 case 16:tmp = 1;break;
385 case 32:tmp = 2;break;
387 writemmr(0x2120, 0xF0000000);
388 writemmr(0x2120, 0x40000000|tmp);
389 writemmr(0x2120, 0x80000000);
390 writemmr(0x2144, 0x00000000);
391 writemmr(0x2148, 0x00000000);
392 writemmr(0x2150, 0x00000000);
393 writemmr(0x2154, 0x00000000);
394 writemmr(0x2120, 0x60000000|(pitch<<16) |pitch);
395 writemmr(0x216C, 0x00000000);
396 writemmr(0x2170, 0x00000000);
397 writemmr(0x217C, 0x00000000);
398 writemmr(0x2120, 0x10000000);
399 writemmr(0x2130, (2047 << 16) | 2047);
402 static void image_wait_engine(void)
404 while(readmmr(0x2164) & 0xF0000000);
407 static void image_fill_rect(__u32 x, __u32 y, __u32 w, __u32 h, __u32 c, __u32 rop)
409 writemmr(0x2120,0x80000000);
410 writemmr(0x2120,0x90000000|ROP_S);
414 writemmr(DR1,point(x,y));
415 writemmr(DR2,point(x+w-1,y+h-1));
417 writemmr(0x2124,0x80000000|3<<22|1<<10|1<<9);
420 static void image_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
425 s2 = point(x1+w-1,y1+h-1);
427 d2 = point(x2+w-1,y2+h-1);
429 if ((y1 > y2) || ((y1 == y2) && (x1 >x2)))
432 writemmr(0x2120,0x80000000);
433 writemmr(0x2120,0x90000000|ROP_S);
435 writemmr(SR1,direction?s2:s1);
436 writemmr(SR2,direction?s1:s2);
437 writemmr(DR1,direction?d2:d1);
438 writemmr(DR2,direction?d1:d2);
439 writemmr(0x2124,0x80000000|1<<22|1<<10|1<<7|direction);
443 static struct accel_switch accel_image = {
451 * Accel functions called by the upper layers
453 #ifdef CONFIG_FB_TRIDENT_ACCEL
454 static void tridentfb_fillrect(struct fb_info * info, const struct fb_fillrect *fr)
456 int bpp = info->var.bits_per_pixel;
461 case 8: col = fr->color;
463 case 16: col = ((u16 *)(info->pseudo_palette))[fr->color];
465 case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
469 acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop);
472 static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
474 acc->copy_rect(ca->sx,ca->sy,ca->dx,ca->dy,ca->width,ca->height);
477 #else /* !CONFIG_FB_TRIDENT_ACCEL */
478 #define tridentfb_fillrect cfb_fillrect
479 #define tridentfb_copyarea cfb_copyarea
480 #endif /* CONFIG_FB_TRIDENT_ACCEL */
484 * Hardware access functions
487 static inline unsigned char read3X4(int reg)
489 struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
490 writeb(reg, par->io_virt + CRT + 4);
491 return readb( par->io_virt + CRT + 5);
494 static inline void write3X4(int reg, unsigned char val)
496 struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
497 writeb(reg, par->io_virt + CRT + 4);
498 writeb(val, par->io_virt + CRT + 5);
501 static inline unsigned char read3C4(int reg)
507 static inline void write3C4(int reg, unsigned char val)
513 static inline unsigned char read3CE(int reg)
519 static inline void writeAttr(int reg, unsigned char val)
521 readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); //flip-flop to index
526 static inline unsigned char readAttr(int reg)
528 readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); //flip-flop to index
533 static inline void write3CE(int reg, unsigned char val)
539 static inline void enable_mmio(void)
545 /* Unprotect registers */
546 outb(NewMode1, 0x3C4);
551 outb(inb(0x3D5) | 0x01, 0x3D5);
555 #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
557 /* Return flat panel's maximum x resolution */
558 static int __init get_nativex(void)
565 tmp = (read3CE(VertStretch) >> 4) & 3;
568 case 0: x = 1280; y = 1024; break;
569 case 2: x = 1024; y = 768; break;
570 case 3: x = 800; y = 600; break;
571 case 4: x = 1400; y = 1050; break;
573 default:x = 640; y = 480; break;
576 output("%dx%d flat panel found\n", x, y);
581 static void set_lwidth(int width)
583 write3X4(Offset, width & 0xFF);
584 write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4));
587 /* For resolutions smaller than FP resolution stretch */
588 static void screen_stretch(void)
590 if (chip_id != CYBERBLADEXPAi1)
594 write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1);
595 write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1);
598 /* For resolutions smaller than FP resolution center */
599 static void screen_center(void)
601 write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80);
602 write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80);
605 /* Address of first shown pixel in display memory */
606 static void set_screen_start(int base)
608 write3X4(StartAddrLow, base & 0xFF);
609 write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
610 write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
611 write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
614 /* Use 20.12 fixed-point for NTSC value and frequency calculation */
615 #define calc_freq(n,m,k) ( ((unsigned long)0xE517 * (n+8) / ((m+2)*(1<<k))) >> 12 )
617 /* Set dotclock frequency */
618 static void set_vclk(int freq)
622 unsigned char lo=0,hi=0;
627 for(n = 0;n<128;n++) {
628 fi = calc_freq(n,m,k);
629 if ((di = abs(fi - freq)) < d) {
637 write3C4(ClockHigh,hi);
638 write3C4(ClockLow,lo);
643 debug("VCLK = %X %X\n",hi,lo);
646 /* Set number of lines for flat panels*/
647 static void set_number_of_lines(int lines)
649 int tmp = read3CE(CyberEnhance) & 0x8F;
652 else if (lines > 768)
654 else if (lines > 600)
656 else if (lines > 480)
658 write3CE(CyberEnhance, tmp);
662 * If we see that FP is active we assume we have one.
663 * Otherwise we have a CRT display.User can override.
665 static unsigned int __init get_displaytype(void)
669 if (crt || !chipcyber)
671 return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
674 /* Try detecting the video memory size */
675 static unsigned int __init get_memsize(void)
677 unsigned char tmp, tmp2;
680 /* If memory size provided by user */
685 case CYBER9525DVD: k = 2560 * Kb; break;
687 tmp = read3X4(SPR) & 0x0F;
690 case 0x01: k = 512; break;
691 case 0x02: k = 6 * Mb; break; /* XP */
692 case 0x03: k = 1 * Mb; break;
693 case 0x04: k = 8 * Mb; break;
694 case 0x06: k = 10 * Mb; break; /* XP */
695 case 0x07: k = 2 * Mb; break;
696 case 0x08: k = 12 * Mb; break; /* XP */
697 case 0x0A: k = 14 * Mb; break; /* XP */
698 case 0x0C: k = 16 * Mb; break; /* XP */
701 tmp2 = read3C4(0xC1);
703 case 0x00: k = 20 * Mb; break;
704 case 0x01: k = 24 * Mb; break;
705 case 0x10: k = 28 * Mb; break;
706 case 0x11: k = 32 * Mb; break;
707 default: k = 1 * Mb; break;
711 case 0x0F: k = 4 * Mb; break;
717 output("framebuffer size = %d Kb\n", k/Kb);
721 /* See if we can handle the video mode described in var */
722 static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
724 int bpp = var->bits_per_pixel;
727 /* check color depth */
729 bpp = var->bits_per_pixel = 32;
730 /* check whether resolution fits on panel and in memory*/
731 if (flatpanel && nativex && var->xres > nativex)
733 if (var->xres * var->yres_virtual * bpp/8 > info->fix.smem_len)
739 var->green.offset = 0;
740 var->blue.offset = 0;
742 var->green.length = 6;
743 var->blue.length = 6;
746 var->red.offset = 11;
747 var->green.offset = 5;
748 var->blue.offset = 0;
750 var->green.length = 6;
751 var->blue.length = 5;
754 var->red.offset = 16;
755 var->green.offset = 8;
756 var->blue.offset = 0;
758 var->green.length = 8;
759 var->blue.length = 8;
769 /* Pan the display */
770 static int tridentfb_pan_display(struct fb_var_screeninfo *var,
771 struct fb_info *info)
776 offset = (var->xoffset + (var->yoffset * var->xres))
777 * var->bits_per_pixel/32;
778 info->var.xoffset = var->xoffset;
779 info->var.yoffset = var->yoffset;
780 set_screen_start(offset);
785 #define shadowmode_on() write3CE(CyberControl,read3CE(CyberControl) | 0x81)
786 #define shadowmode_off() write3CE(CyberControl,read3CE(CyberControl) & 0x7E)
788 /* Set the hardware to the requested video mode */
789 static int tridentfb_set_par(struct fb_info *info)
791 struct tridentfb_par * par = (struct tridentfb_par *)(info->par);
792 u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
793 vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
794 struct fb_var_screeninfo *var = &info->var;
795 int bpp = var->bits_per_pixel;
798 htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10;
799 hdispend = var->xres/8 - 1;
800 hsyncstart = (var->xres + var->right_margin)/8;
801 hsyncend = var->hsync_len/8;
802 hblankstart = hdispend + 1;
803 hblankend = htotal + 5;
805 vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len - 2;
806 vdispend = var->yres - 1;
807 vsyncstart = var->yres + var->lower_margin;
808 vsyncend = var->vsync_len;
809 vblankstart = var->yres;
810 vblankend = vtotal + 2;
814 write3CE(CyberControl,8);
816 if (flatpanel && var->xres < nativex) {
818 * on flat panels with native size larger
819 * than requested resolution decide whether
820 * we stretch or center
833 write3CE(CyberControl,8);
836 /* vertical timing values */
837 write3X4(CRTVTotal, vtotal & 0xFF);
838 write3X4(CRTVDispEnd, vdispend & 0xFF);
839 write3X4(CRTVSyncStart, vsyncstart & 0xFF);
840 write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
841 write3X4(CRTVBlankStart, vblankstart & 0xFF);
842 write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/);
844 /* horizontal timing values */
845 write3X4(CRTHTotal, htotal & 0xFF);
846 write3X4(CRTHDispEnd, hdispend & 0xFF);
847 write3X4(CRTHSyncStart, hsyncstart & 0xFF);
848 write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
849 write3X4(CRTHBlankStart, hblankstart & 0xFF);
850 write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/);
852 /* higher bits of vertical timing values */
854 if (vtotal & 0x100) tmp |= 0x01;
855 if (vdispend & 0x100) tmp |= 0x02;
856 if (vsyncstart & 0x100) tmp |= 0x04;
857 if (vblankstart & 0x100) tmp |= 0x08;
859 if (vtotal & 0x200) tmp |= 0x20;
860 if (vdispend & 0x200) tmp |= 0x40;
861 if (vsyncstart & 0x200) tmp |= 0x80;
862 write3X4(CRTOverflow, tmp);
864 tmp = read3X4(CRTHiOrd) | 0x08; //line compare bit 10
865 if (vtotal & 0x400) tmp |= 0x80;
866 if (vblankstart & 0x400) tmp |= 0x40;
867 if (vsyncstart & 0x400) tmp |= 0x20;
868 if (vdispend & 0x400) tmp |= 0x10;
869 write3X4(CRTHiOrd, tmp);
872 if (htotal & 0x800) tmp |= 0x800 >> 11;
873 if (hblankstart & 0x800) tmp |= 0x800 >> 7;
874 write3X4(HorizOverflow, tmp);
877 if (vblankstart & 0x200) tmp |= 0x20;
878 //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; //double scan for 200 line modes
879 write3X4(CRTMaxScanLine, tmp);
881 write3X4(CRTLineCompare,0xFF);
882 write3X4(CRTPRowScan,0);
883 write3X4(CRTModeControl,0xC3);
885 write3X4(LinearAddReg,0x20); //enable linear addressing
887 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80;
888 write3X4(CRTCModuleTest,tmp); //enable access extended memory
890 write3X4(GraphEngReg, 0x80); //enable GE for text acceleration
892 // if (info->var.accel_flags & FB_ACCELF_TEXT)
893 //FIXME acc->init_accel(info->var.xres,bpp);
896 case 8: tmp = 0x00; break;
897 case 16: tmp = 0x05; break;
898 case 24: tmp = 0x29; break;
902 write3X4(PixelBusReg, tmp);
907 write3X4(DRAMControl, tmp); //both IO,linear enable
909 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
910 write3X4(Performance,0x20);
911 write3X4(PCIReg,0x07); //MMIO & PCI read and write burst enable
913 /* convert from picoseconds to MHz */
914 par->vclk = 1000000/info->var.pixclock;
920 write3C4(1,1); //set char clock 8 dots wide
921 write3C4(2,0x0F); //enable 4 maps because needed in chain4 mode
923 write3C4(4,0x0E); //memory mode enable bitmaps ??
925 write3CE(MiscExtFunc,(bpp==32)?0x1A:0x12); //divide clock by 2 if 32bpp
926 //chain4 mode display and CPU path
927 write3CE(0x5,0x40); //no CGA compat,allow 256 col
928 write3CE(0x6,0x05); //graphics mode
929 write3CE(0x7,0x0F); //planes?
931 if (chip_id == CYBERBLADEXPAi1) {
932 /* This fixes snow-effect in 32 bpp */
933 write3X4(CRTHSyncStart,0x84);
936 writeAttr(0x10,0x41); //graphics mode and support 256 color modes
937 writeAttr(0x12,0x0F); //planes
938 writeAttr(0x13,0); //horizontal pel panning
941 for(tmp = 0;tmp < 0x10;tmp++)
943 readb(par->io_virt + CRT + 0x0A); //flip-flop to index
944 t_outb(0x20, 0x3C0); //enable attr
947 case 8: tmp = 0;break; //256 colors
948 case 15: tmp = 0x10;break;
949 case 16: tmp = 0x30;break; //hicolor
951 case 32: tmp = 0xD0;break;
963 set_number_of_lines(info->var.yres);
964 set_lwidth(info->var.xres * bpp/(4*16));
965 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
966 info->fix.line_length = info->var.xres * (bpp >> 3);
967 info->cmap.len = (bpp == 8) ? 256: 16;
972 /* Set one color register */
973 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
974 unsigned blue, unsigned transp,
975 struct fb_info *info)
977 int bpp = info->var.bits_per_pixel;
979 if (regno >= info->cmap.len)
987 t_outb(red>>10,0x3C9);
988 t_outb(green>>10,0x3C9);
989 t_outb(blue>>10,0x3C9);
992 if (bpp == 16) /* RGB 565 */
993 ((u16*)info->pseudo_palette)[regno] = (red & 0xF800) |
994 ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
996 if (bpp == 32) /* ARGB 8888 */
997 ((u32*)info->pseudo_palette)[regno] =
998 ((transp & 0xFF00) <<16) |
999 ((red & 0xFF00) << 8) |
1000 ((green & 0xFF00)) |
1001 ((blue & 0xFF00)>>8);
1007 /* Try blanking the screen.For flat panels it does nothing */
1008 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1010 unsigned char PMCont,DPMSCont;
1015 t_outb(0x04,0x83C8); /* Read DPMS Control */
1016 PMCont = t_inb(0x83C6) & 0xFC;
1017 DPMSCont = read3CE(PowerStatus) & 0xFC;
1020 case VESA_NO_BLANKING:
1021 /* Screen: On, HSync: On, VSync: On */
1025 case VESA_HSYNC_SUSPEND:
1026 /* Screen: Off, HSync: Off, VSync: On */
1030 case VESA_VSYNC_SUSPEND:
1031 /* Screen: Off, HSync: On, VSync: Off */
1035 case VESA_POWERDOWN:
1036 /* Screen: Off, HSync: Off, VSync: Off */
1042 write3CE(PowerStatus,DPMSCont);
1044 t_outb(PMCont,0x83C6);
1050 static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id)
1053 unsigned char revision;
1055 err = pci_enable_device(dev);
1059 chip_id = id->device;
1061 /* If PCI id is 0x9660 then further detect chip type */
1063 if (chip_id == TGUI9660) {
1064 outb(RevisionID,0x3C4);
1065 revision = inb(0x3C5);
1069 case 0x23: chip_id = CYBER9397;break;
1070 case 0x2A: chip_id = CYBER9397DVD;break;
1077 case 0xB3: chip_id = CYBER9385;break;
1078 case 0x40 ... 0x43: chip_id = CYBER9382;break;
1079 case 0x4A: chip_id = CYBER9388;break;
1084 chip3D = is3Dchip(chip_id);
1085 chipcyber = iscyber(chip_id);
1087 if (is_xp(chip_id)) {
1090 if (is_blade(chip_id)) {
1096 /* acceleration is on by default for 3D chips */
1097 defaultaccel = chip3D && !noaccel;
1099 fb_info.par = &default_par;
1101 /* setup MMIO region */
1102 tridentfb_fix.mmio_start = pci_resource_start(dev,1);
1103 tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000;
1105 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1106 debug("request_region failed!\n");
1110 default_par.io_virt = (unsigned long)ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1112 if (!default_par.io_virt) {
1113 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1114 debug("ioremap failed\n");
1120 /* setup framebuffer memory */
1121 tridentfb_fix.smem_start = pci_resource_start(dev,0);
1122 tridentfb_fix.smem_len = get_memsize();
1124 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1125 debug("request_mem_region failed!\n");
1129 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1130 tridentfb_fix.smem_len);
1132 if (!fb_info.screen_base) {
1133 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1134 debug("ioremap failed\n");
1138 output("%s board found\n", pci_name(dev));
1140 output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n",
1141 tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt);
1143 displaytype = get_displaytype();
1146 nativex = get_nativex();
1148 fb_info.fix = tridentfb_fix;
1149 fb_info.fbops = &tridentfb_ops;
1152 fb_info.flags = FBINFO_FLAG_DEFAULT;
1153 fb_info.pseudo_palette = pseudo_pal;
1155 if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp))
1157 fb_alloc_cmap(&fb_info.cmap,256,0);
1158 if (defaultaccel && acc)
1159 default_var.accel_flags |= FB_ACCELF_TEXT;
1161 default_var.accel_flags &= ~FB_ACCELF_TEXT;
1162 default_var.activate |= FB_ACTIVATE_NOW;
1163 fb_info.var = default_var;
1164 if (register_framebuffer(&fb_info) < 0) {
1165 output("Could not register Trident framebuffer\n");
1168 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1169 fb_info.node, fb_info.fix.id,default_var.xres,
1170 default_var.yres,default_var.bits_per_pixel);
1174 static void __devexit trident_pci_remove(struct pci_dev * dev)
1176 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1177 unregister_framebuffer(&fb_info);
1178 iounmap((void *)par->io_virt);
1179 iounmap((void*)fb_info.screen_base);
1180 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1181 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1184 /* List of boards that we are trying to support */
1185 static struct pci_device_id trident_devices[] = {
1186 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1187 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1188 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1189 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1190 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1191 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1192 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1193 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1194 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1195 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1196 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1197 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1198 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1199 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1200 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1201 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1202 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1203 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1204 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1205 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1209 MODULE_DEVICE_TABLE(pci,trident_devices);
1211 static struct pci_driver tridentfb_pci_driver = {
1212 .name = "tridentfb",
1213 .id_table = trident_devices,
1214 .probe = trident_pci_probe,
1215 .remove = __devexit_p(trident_pci_remove)
1218 int __init tridentfb_init(void)
1220 output("Trident framebuffer %s initializing\n", VERSION);
1221 return pci_module_init(&tridentfb_pci_driver);
1224 void __exit tridentfb_exit(void)
1226 pci_unregister_driver(&tridentfb_pci_driver);
1231 * Parse user specified options (`video=trident:')
1233 * video=trident:800x600,bpp=16,noaccel
1235 int tridentfb_setup(char *options)
1238 if (!options || !*options)
1240 while((opt = strsep(&options,",")) != NULL ) {
1241 if (!*opt) continue;
1242 if (!strncmp(opt,"noaccel",7))
1244 else if (!strncmp(opt,"fp",2))
1245 displaytype = DISPLAY_FP;
1246 else if (!strncmp(opt,"crt",3))
1247 displaytype = DISPLAY_CRT;
1248 else if (!strncmp(opt,"bpp=",4))
1249 bpp = simple_strtoul(opt+4,NULL,0);
1250 else if (!strncmp(opt,"center",6))
1252 else if (!strncmp(opt,"stretch",7))
1254 else if (!strncmp(opt,"memsize=",8))
1255 memsize = simple_strtoul(opt+8,NULL,0);
1256 else if (!strncmp(opt,"memdiff=",8))
1257 memdiff = simple_strtoul(opt+8,NULL,0);
1258 else if (!strncmp(opt,"nativex=",8))
1259 nativex = simple_strtoul(opt+8,NULL,0);
1266 static struct fb_ops tridentfb_ops = {
1267 .owner = THIS_MODULE,
1268 .fb_setcolreg = tridentfb_setcolreg,
1269 .fb_pan_display = tridentfb_pan_display,
1270 .fb_blank = tridentfb_blank,
1271 .fb_check_var = tridentfb_check_var,
1272 .fb_set_par = tridentfb_set_par,
1273 .fb_fillrect = tridentfb_fillrect,
1274 .fb_copyarea= tridentfb_copyarea,
1275 .fb_imageblit = cfb_imageblit,
1276 .fb_cursor = soft_cursor,
1280 module_init(tridentfb_init);
1282 module_exit(tridentfb_exit);
1284 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1285 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1286 MODULE_LICENSE("GPL");