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/module.h>
20 #include <linux/init.h>
21 #include <linux/pci.h>
23 #include <linux/delay.h>
24 #include <video/trident.h>
26 #define VERSION "0.7.8-NEWAPI"
28 struct tridentfb_par {
30 void __iomem * io_virt; //iospace virtual memory address
33 static unsigned char eng_oper; //engine operation...
34 static struct fb_ops tridentfb_ops;
36 static struct tridentfb_par default_par;
38 /* FIXME:kmalloc these 3 instead */
39 static struct fb_info fb_info;
40 static u32 pseudo_pal[16];
43 static struct fb_var_screeninfo default_var;
45 static struct fb_fix_screeninfo tridentfb_fix = {
47 .type = FB_TYPE_PACKED_PIXELS,
49 .visual = FB_VISUAL_PSEUDOCOLOR,
50 .accel = FB_ACCEL_NONE,
55 static int defaultaccel;
56 static int displaytype;
59 /* defaults which are normally overriden by user values */
62 static char * mode = "640x480";
78 module_param(mode, charp, 0);
79 module_param(bpp, int, 0);
80 module_param(center, int, 0);
81 module_param(stretch, int, 0);
82 module_param(noaccel, int, 0);
83 module_param(memsize, int, 0);
84 module_param(memdiff, int, 0);
85 module_param(nativex, int, 0);
86 module_param(fp, int, 0);
87 module_param(crt, int, 0);
93 static int is3Dchip(int id)
95 return ((id == BLADE3D) || (id == CYBERBLADEE4) ||
96 (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) ||
97 (id == CYBER9397) || (id == CYBER9397DVD) ||
98 (id == CYBER9520) || (id == CYBER9525DVD) ||
99 (id == IMAGE975) || (id == IMAGE985) ||
100 (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) ||
101 (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) ||
102 (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) ||
103 (id == CYBERBLADEXPAi1));
106 static int iscyber(int id)
122 case CYBERBLADEXPAi1:
130 case CYBERBLADEi7: /* VIA MPV4 integrated version */
133 /* case CYBERBLDAEXPm8: Strange */
134 /* case CYBERBLDAEXPm16: Strange */
139 #define CRT 0x3D0 //CRTC registers offset for color display
142 #define TRIDENT_MMIO 1
146 #define t_outb(val,reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg)
147 #define t_inb(reg) readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg)
149 #define t_outb(val,reg) outb(val,reg)
150 #define t_inb(reg) inb(reg)
154 static struct accel_switch {
155 void (*init_accel)(int,int);
156 void (*wait_engine)(void);
157 void (*fill_rect)(__u32,__u32,__u32,__u32,__u32,__u32);
158 void (*copy_rect)(__u32,__u32,__u32,__u32,__u32,__u32);
161 #define writemmr(r,v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r)
162 #define readmmr(r) readl(((struct tridentfb_par *)fb_info.par)->io_virt + r)
167 * Blade specific acceleration.
170 #define point(x,y) ((y)<<16|(x))
182 static void blade_init_accel(int pitch,int bpp)
184 int v1 = (pitch>>3)<<20;
187 case 8:tmp = 0;break;
188 case 15:tmp = 5;break;
189 case 16:tmp = 1;break;
191 case 32:tmp = 2;break;
205 static void blade_wait_engine(void)
207 while(readmmr(STA) & 0xFA800000);
210 static void blade_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop)
213 writemmr(ROP,rop ? 0x66:ROP_S);
214 writemmr(CMD,0x20000000|1<<19|1<<4|2<<2);
216 writemmr(DR1,point(x,y));
217 writemmr(DR2,point(x+w-1,y+h-1));
220 static void blade_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
225 s2 = point(x1+w-1,y1+h-1);
227 d2 = point(x2+w-1,y2+h-1);
229 if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
234 writemmr(CMD,0xE0000000|1<<19|1<<4|1<<2|direction);
236 writemmr(SR1,direction?s2:s1);
237 writemmr(SR2,direction?s1:s2);
238 writemmr(DR1,direction?d2:d1);
239 writemmr(DR2,direction?d1:d2);
242 static struct accel_switch accel_blade = {
251 * BladeXP specific acceleration functions
255 #define masked_point(x,y) ((y & 0xffff)<<16|(x & 0xffff))
257 static void xp_init_accel(int pitch,int bpp)
263 case 8: x = 0; break;
264 case 16: x = 1; break;
265 case 24: x = 3; break;
266 case 32: x = 2; break;
269 switch (pitch << (bpp >> 3)) {
271 case 512: x |= 0x00; break;
272 case 1024: x |= 0x04; break;
273 case 2048: x |= 0x08; break;
274 case 4096: x |= 0x0C; break;
282 case 8: tmp = 18; break;
284 case 16: tmp = 19; break;
286 case 32: tmp = 20; break;
296 static void xp_wait_engine(void)
304 busy = t_inb(STA) & 0x80;
308 if (count == 10000000) {
314 t_outb(0x00, 0x2120);
321 static void xp_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop)
323 writemmr(0x2127,ROP_P);
325 writemmr(0x2128,0x4000);
326 writemmr(0x2140,masked_point(h,w));
327 writemmr(0x2138,masked_point(y,x));
329 t_outb(eng_oper,0x2125);
332 static void xp_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
335 __u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
339 if ((x1 < x2) && (y1 == y2)) {
357 writemmr(0x2128,direction);
358 t_outb(ROP_S,0x2127);
359 writemmr(0x213C,masked_point(y1_tmp,x1_tmp));
360 writemmr(0x2138,masked_point(y2_tmp,x2_tmp));
361 writemmr(0x2140,masked_point(h,w));
365 static struct accel_switch accel_xp = {
374 * Image specific acceleration functions
376 static void image_init_accel(int pitch,int bpp)
380 case 8:tmp = 0;break;
381 case 15:tmp = 5;break;
382 case 16:tmp = 1;break;
384 case 32:tmp = 2;break;
386 writemmr(0x2120, 0xF0000000);
387 writemmr(0x2120, 0x40000000|tmp);
388 writemmr(0x2120, 0x80000000);
389 writemmr(0x2144, 0x00000000);
390 writemmr(0x2148, 0x00000000);
391 writemmr(0x2150, 0x00000000);
392 writemmr(0x2154, 0x00000000);
393 writemmr(0x2120, 0x60000000|(pitch<<16) |pitch);
394 writemmr(0x216C, 0x00000000);
395 writemmr(0x2170, 0x00000000);
396 writemmr(0x217C, 0x00000000);
397 writemmr(0x2120, 0x10000000);
398 writemmr(0x2130, (2047 << 16) | 2047);
401 static void image_wait_engine(void)
403 while(readmmr(0x2164) & 0xF0000000);
406 static void image_fill_rect(__u32 x, __u32 y, __u32 w, __u32 h, __u32 c, __u32 rop)
408 writemmr(0x2120,0x80000000);
409 writemmr(0x2120,0x90000000|ROP_S);
413 writemmr(DR1,point(x,y));
414 writemmr(DR2,point(x+w-1,y+h-1));
416 writemmr(0x2124,0x80000000|3<<22|1<<10|1<<9);
419 static void image_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
424 s2 = point(x1+w-1,y1+h-1);
426 d2 = point(x2+w-1,y2+h-1);
428 if ((y1 > y2) || ((y1 == y2) && (x1 >x2)))
431 writemmr(0x2120,0x80000000);
432 writemmr(0x2120,0x90000000|ROP_S);
434 writemmr(SR1,direction?s2:s1);
435 writemmr(SR2,direction?s1:s2);
436 writemmr(DR1,direction?d2:d1);
437 writemmr(DR2,direction?d1:d2);
438 writemmr(0x2124,0x80000000|1<<22|1<<10|1<<7|direction);
442 static struct accel_switch accel_image = {
450 * Accel functions called by the upper layers
452 #ifdef CONFIG_FB_TRIDENT_ACCEL
453 static void tridentfb_fillrect(struct fb_info * info, const struct fb_fillrect *fr)
455 int bpp = info->var.bits_per_pixel;
460 case 8: col |= fr->color;
464 case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
467 case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
471 acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop);
474 static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
476 acc->copy_rect(ca->sx,ca->sy,ca->dx,ca->dy,ca->width,ca->height);
479 #else /* !CONFIG_FB_TRIDENT_ACCEL */
480 #define tridentfb_fillrect cfb_fillrect
481 #define tridentfb_copyarea cfb_copyarea
482 #endif /* CONFIG_FB_TRIDENT_ACCEL */
486 * Hardware access functions
489 static inline unsigned char read3X4(int reg)
491 struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
492 writeb(reg, par->io_virt + CRT + 4);
493 return readb( par->io_virt + CRT + 5);
496 static inline void write3X4(int reg, unsigned char val)
498 struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
499 writeb(reg, par->io_virt + CRT + 4);
500 writeb(val, par->io_virt + CRT + 5);
503 static inline unsigned char read3C4(int reg)
509 static inline void write3C4(int reg, unsigned char val)
515 static inline unsigned char read3CE(int reg)
521 static inline void writeAttr(int reg, unsigned char val)
523 readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); //flip-flop to index
528 static inline void write3CE(int reg, unsigned char val)
534 static inline void enable_mmio(void)
540 /* Unprotect registers */
541 outb(NewMode1, 0x3C4);
546 outb(inb(0x3D5) | 0x01, 0x3D5);
550 #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
552 /* Return flat panel's maximum x resolution */
553 static int __devinit get_nativex(void)
560 tmp = (read3CE(VertStretch) >> 4) & 3;
563 case 0: x = 1280; y = 1024; break;
564 case 2: x = 1024; y = 768; break;
565 case 3: x = 800; y = 600; break;
566 case 4: x = 1400; y = 1050; break;
568 default:x = 640; y = 480; break;
571 output("%dx%d flat panel found\n", x, y);
576 static void set_lwidth(int width)
578 write3X4(Offset, width & 0xFF);
579 write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4));
582 /* For resolutions smaller than FP resolution stretch */
583 static void screen_stretch(void)
585 if (chip_id != CYBERBLADEXPAi1)
589 write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1);
590 write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1);
593 /* For resolutions smaller than FP resolution center */
594 static void screen_center(void)
596 write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80);
597 write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80);
600 /* Address of first shown pixel in display memory */
601 static void set_screen_start(int base)
603 write3X4(StartAddrLow, base & 0xFF);
604 write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
605 write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
606 write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
609 /* Use 20.12 fixed-point for NTSC value and frequency calculation */
610 #define calc_freq(n,m,k) ( ((unsigned long)0xE517 * (n+8) / ((m+2)*(1<<k))) >> 12 )
612 /* Set dotclock frequency */
613 static void set_vclk(int freq)
617 unsigned char lo=0,hi=0;
622 for(n = 0;n<128;n++) {
623 fi = calc_freq(n,m,k);
624 if ((di = abs(fi - freq)) < d) {
632 write3C4(ClockHigh,hi);
633 write3C4(ClockLow,lo);
638 debug("VCLK = %X %X\n",hi,lo);
641 /* Set number of lines for flat panels*/
642 static void set_number_of_lines(int lines)
644 int tmp = read3CE(CyberEnhance) & 0x8F;
647 else if (lines > 768)
649 else if (lines > 600)
651 else if (lines > 480)
653 write3CE(CyberEnhance, tmp);
657 * If we see that FP is active we assume we have one.
658 * Otherwise we have a CRT display.User can override.
660 static unsigned int __devinit get_displaytype(void)
664 if (crt || !chipcyber)
666 return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
669 /* Try detecting the video memory size */
670 static unsigned int __devinit get_memsize(void)
672 unsigned char tmp, tmp2;
675 /* If memory size provided by user */
680 case CYBER9525DVD: k = 2560 * Kb; break;
682 tmp = read3X4(SPR) & 0x0F;
685 case 0x01: k = 512; break;
686 case 0x02: k = 6 * Mb; break; /* XP */
687 case 0x03: k = 1 * Mb; break;
688 case 0x04: k = 8 * Mb; break;
689 case 0x06: k = 10 * Mb; break; /* XP */
690 case 0x07: k = 2 * Mb; break;
691 case 0x08: k = 12 * Mb; break; /* XP */
692 case 0x0A: k = 14 * Mb; break; /* XP */
693 case 0x0C: k = 16 * Mb; break; /* XP */
696 tmp2 = read3C4(0xC1);
698 case 0x00: k = 20 * Mb; break;
699 case 0x01: k = 24 * Mb; break;
700 case 0x10: k = 28 * Mb; break;
701 case 0x11: k = 32 * Mb; break;
702 default: k = 1 * Mb; break;
706 case 0x0F: k = 4 * Mb; break;
712 output("framebuffer size = %d Kb\n", k/Kb);
716 /* See if we can handle the video mode described in var */
717 static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
719 int bpp = var->bits_per_pixel;
722 /* check color depth */
724 bpp = var->bits_per_pixel = 32;
725 /* check whether resolution fits on panel and in memory*/
726 if (flatpanel && nativex && var->xres > nativex)
728 if (var->xres * var->yres_virtual * bpp/8 > info->fix.smem_len)
734 var->green.offset = 0;
735 var->blue.offset = 0;
737 var->green.length = 6;
738 var->blue.length = 6;
741 var->red.offset = 11;
742 var->green.offset = 5;
743 var->blue.offset = 0;
745 var->green.length = 6;
746 var->blue.length = 5;
749 var->red.offset = 16;
750 var->green.offset = 8;
751 var->blue.offset = 0;
753 var->green.length = 8;
754 var->blue.length = 8;
764 /* Pan the display */
765 static int tridentfb_pan_display(struct fb_var_screeninfo *var,
766 struct fb_info *info)
771 offset = (var->xoffset + (var->yoffset * var->xres))
772 * var->bits_per_pixel/32;
773 info->var.xoffset = var->xoffset;
774 info->var.yoffset = var->yoffset;
775 set_screen_start(offset);
780 #define shadowmode_on() write3CE(CyberControl,read3CE(CyberControl) | 0x81)
781 #define shadowmode_off() write3CE(CyberControl,read3CE(CyberControl) & 0x7E)
783 /* Set the hardware to the requested video mode */
784 static int tridentfb_set_par(struct fb_info *info)
786 struct tridentfb_par * par = (struct tridentfb_par *)(info->par);
787 u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
788 vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
789 struct fb_var_screeninfo *var = &info->var;
790 int bpp = var->bits_per_pixel;
793 htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10;
794 hdispend = var->xres/8 - 1;
795 hsyncstart = (var->xres + var->right_margin)/8;
796 hsyncend = var->hsync_len/8;
797 hblankstart = hdispend + 1;
798 hblankend = htotal + 5;
800 vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len - 2;
801 vdispend = var->yres - 1;
802 vsyncstart = var->yres + var->lower_margin;
803 vsyncend = var->vsync_len;
804 vblankstart = var->yres;
805 vblankend = vtotal + 2;
809 write3CE(CyberControl,8);
811 if (flatpanel && var->xres < nativex) {
813 * on flat panels with native size larger
814 * than requested resolution decide whether
815 * we stretch or center
828 write3CE(CyberControl,8);
831 /* vertical timing values */
832 write3X4(CRTVTotal, vtotal & 0xFF);
833 write3X4(CRTVDispEnd, vdispend & 0xFF);
834 write3X4(CRTVSyncStart, vsyncstart & 0xFF);
835 write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
836 write3X4(CRTVBlankStart, vblankstart & 0xFF);
837 write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/);
839 /* horizontal timing values */
840 write3X4(CRTHTotal, htotal & 0xFF);
841 write3X4(CRTHDispEnd, hdispend & 0xFF);
842 write3X4(CRTHSyncStart, hsyncstart & 0xFF);
843 write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
844 write3X4(CRTHBlankStart, hblankstart & 0xFF);
845 write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/);
847 /* higher bits of vertical timing values */
849 if (vtotal & 0x100) tmp |= 0x01;
850 if (vdispend & 0x100) tmp |= 0x02;
851 if (vsyncstart & 0x100) tmp |= 0x04;
852 if (vblankstart & 0x100) tmp |= 0x08;
854 if (vtotal & 0x200) tmp |= 0x20;
855 if (vdispend & 0x200) tmp |= 0x40;
856 if (vsyncstart & 0x200) tmp |= 0x80;
857 write3X4(CRTOverflow, tmp);
859 tmp = read3X4(CRTHiOrd) | 0x08; //line compare bit 10
860 if (vtotal & 0x400) tmp |= 0x80;
861 if (vblankstart & 0x400) tmp |= 0x40;
862 if (vsyncstart & 0x400) tmp |= 0x20;
863 if (vdispend & 0x400) tmp |= 0x10;
864 write3X4(CRTHiOrd, tmp);
867 if (htotal & 0x800) tmp |= 0x800 >> 11;
868 if (hblankstart & 0x800) tmp |= 0x800 >> 7;
869 write3X4(HorizOverflow, tmp);
872 if (vblankstart & 0x200) tmp |= 0x20;
873 //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; //double scan for 200 line modes
874 write3X4(CRTMaxScanLine, tmp);
876 write3X4(CRTLineCompare,0xFF);
877 write3X4(CRTPRowScan,0);
878 write3X4(CRTModeControl,0xC3);
880 write3X4(LinearAddReg,0x20); //enable linear addressing
882 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80;
883 write3X4(CRTCModuleTest,tmp); //enable access extended memory
885 write3X4(GraphEngReg, 0x80); //enable GE for text acceleration
887 #ifdef CONFIG_FB_TRIDENT_ACCEL
888 acc->init_accel(info->var.xres,bpp);
892 case 8: tmp = 0x00; break;
893 case 16: tmp = 0x05; break;
894 case 24: tmp = 0x29; break;
898 write3X4(PixelBusReg, tmp);
903 write3X4(DRAMControl, tmp); //both IO,linear enable
905 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
906 write3X4(Performance,0x92);
907 write3X4(PCIReg,0x07); //MMIO & PCI read and write burst enable
909 /* convert from picoseconds to MHz */
910 par->vclk = 1000000/info->var.pixclock;
916 write3C4(1,1); //set char clock 8 dots wide
917 write3C4(2,0x0F); //enable 4 maps because needed in chain4 mode
919 write3C4(4,0x0E); //memory mode enable bitmaps ??
921 write3CE(MiscExtFunc,(bpp==32)?0x1A:0x12); //divide clock by 2 if 32bpp
922 //chain4 mode display and CPU path
923 write3CE(0x5,0x40); //no CGA compat,allow 256 col
924 write3CE(0x6,0x05); //graphics mode
925 write3CE(0x7,0x0F); //planes?
927 if (chip_id == CYBERBLADEXPAi1) {
928 /* This fixes snow-effect in 32 bpp */
929 write3X4(CRTHSyncStart,0x84);
932 writeAttr(0x10,0x41); //graphics mode and support 256 color modes
933 writeAttr(0x12,0x0F); //planes
934 writeAttr(0x13,0); //horizontal pel panning
937 for(tmp = 0;tmp < 0x10;tmp++)
939 readb(par->io_virt + CRT + 0x0A); //flip-flop to index
940 t_outb(0x20, 0x3C0); //enable attr
943 case 8: tmp = 0;break; //256 colors
944 case 15: tmp = 0x10;break;
945 case 16: tmp = 0x30;break; //hicolor
947 case 32: tmp = 0xD0;break;
959 set_number_of_lines(info->var.yres);
960 set_lwidth(info->var.xres * bpp/(4*16));
961 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
962 info->fix.line_length = info->var.xres * (bpp >> 3);
963 info->cmap.len = (bpp == 8) ? 256: 16;
968 /* Set one color register */
969 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
970 unsigned blue, unsigned transp,
971 struct fb_info *info)
973 int bpp = info->var.bits_per_pixel;
975 if (regno >= info->cmap.len)
983 t_outb(red>>10,0x3C9);
984 t_outb(green>>10,0x3C9);
985 t_outb(blue>>10,0x3C9);
987 } else if (bpp == 16) { /* RGB 565 */
990 col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
991 ((blue & 0xF800) >> 11);
993 ((u32 *)(info->pseudo_palette))[regno] = col;
994 } else if (bpp == 32) /* ARGB 8888 */
995 ((u32*)info->pseudo_palette)[regno] =
996 ((transp & 0xFF00) <<16) |
997 ((red & 0xFF00) << 8) |
999 ((blue & 0xFF00)>>8);
1005 /* Try blanking the screen.For flat panels it does nothing */
1006 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1008 unsigned char PMCont,DPMSCont;
1013 t_outb(0x04,0x83C8); /* Read DPMS Control */
1014 PMCont = t_inb(0x83C6) & 0xFC;
1015 DPMSCont = read3CE(PowerStatus) & 0xFC;
1018 case FB_BLANK_UNBLANK:
1019 /* Screen: On, HSync: On, VSync: On */
1020 case FB_BLANK_NORMAL:
1021 /* Screen: Off, HSync: On, VSync: On */
1025 case FB_BLANK_HSYNC_SUSPEND:
1026 /* Screen: Off, HSync: Off, VSync: On */
1030 case FB_BLANK_VSYNC_SUSPEND:
1031 /* Screen: Off, HSync: On, VSync: Off */
1035 case FB_BLANK_POWERDOWN:
1036 /* Screen: Off, HSync: Off, VSync: Off */
1042 write3CE(PowerStatus,DPMSCont);
1044 t_outb(PMCont,0x83C6);
1048 /* let fbcon do a softblank for us */
1049 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1052 static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id)
1055 unsigned char revision;
1057 err = pci_enable_device(dev);
1061 chip_id = id->device;
1063 if(chip_id == CYBERBLADEi1)
1064 output("*** Please do use cyblafb, Cyberblade/i1 support "
1065 "will soon be removed from tridentfb!\n");
1068 /* If PCI id is 0x9660 then further detect chip type */
1070 if (chip_id == TGUI9660) {
1071 outb(RevisionID,0x3C4);
1072 revision = inb(0x3C5);
1076 case 0x23: chip_id = CYBER9397;break;
1077 case 0x2A: chip_id = CYBER9397DVD;break;
1084 case 0xB3: chip_id = CYBER9385;break;
1085 case 0x40 ... 0x43: chip_id = CYBER9382;break;
1086 case 0x4A: chip_id = CYBER9388;break;
1091 chip3D = is3Dchip(chip_id);
1092 chipcyber = iscyber(chip_id);
1094 if (is_xp(chip_id)) {
1097 if (is_blade(chip_id)) {
1103 /* acceleration is on by default for 3D chips */
1104 defaultaccel = chip3D && !noaccel;
1106 fb_info.par = &default_par;
1108 /* setup MMIO region */
1109 tridentfb_fix.mmio_start = pci_resource_start(dev,1);
1110 tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000;
1112 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1113 debug("request_region failed!\n");
1117 default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1119 if (!default_par.io_virt) {
1120 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1121 debug("ioremap failed\n");
1127 /* setup framebuffer memory */
1128 tridentfb_fix.smem_start = pci_resource_start(dev,0);
1129 tridentfb_fix.smem_len = get_memsize();
1131 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1132 debug("request_mem_region failed!\n");
1137 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1138 tridentfb_fix.smem_len);
1140 if (!fb_info.screen_base) {
1141 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1142 debug("ioremap failed\n");
1147 output("%s board found\n", pci_name(dev));
1149 output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n",
1150 tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt);
1152 displaytype = get_displaytype();
1155 nativex = get_nativex();
1157 fb_info.fix = tridentfb_fix;
1158 fb_info.fbops = &tridentfb_ops;
1161 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1162 #ifdef CONFIG_FB_TRIDENT_ACCEL
1163 fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1165 fb_info.pseudo_palette = pseudo_pal;
1167 if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp)) {
1171 fb_alloc_cmap(&fb_info.cmap,256,0);
1172 if (defaultaccel && acc)
1173 default_var.accel_flags |= FB_ACCELF_TEXT;
1175 default_var.accel_flags &= ~FB_ACCELF_TEXT;
1176 default_var.activate |= FB_ACTIVATE_NOW;
1177 fb_info.var = default_var;
1178 fb_info.device = &dev->dev;
1179 if (register_framebuffer(&fb_info) < 0) {
1180 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1184 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1185 fb_info.node, fb_info.fix.id,default_var.xres,
1186 default_var.yres,default_var.bits_per_pixel);
1190 if (default_par.io_virt)
1191 iounmap(default_par.io_virt);
1192 if (fb_info.screen_base)
1193 iounmap(fb_info.screen_base);
1197 static void __devexit trident_pci_remove(struct pci_dev * dev)
1199 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1200 unregister_framebuffer(&fb_info);
1201 iounmap(par->io_virt);
1202 iounmap(fb_info.screen_base);
1203 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1204 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1207 /* List of boards that we are trying to support */
1208 static struct pci_device_id trident_devices[] = {
1209 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1210 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1211 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1212 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1213 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1214 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1215 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1216 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1217 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1218 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1219 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1220 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1221 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1222 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1223 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1224 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1225 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1226 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1227 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1228 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1232 MODULE_DEVICE_TABLE(pci,trident_devices);
1234 static struct pci_driver tridentfb_pci_driver = {
1235 .name = "tridentfb",
1236 .id_table = trident_devices,
1237 .probe = trident_pci_probe,
1238 .remove = __devexit_p(trident_pci_remove)
1242 * Parse user specified options (`video=trident:')
1244 * video=trident:800x600,bpp=16,noaccel
1247 static int tridentfb_setup(char *options)
1250 if (!options || !*options)
1252 while((opt = strsep(&options,",")) != NULL ) {
1253 if (!*opt) continue;
1254 if (!strncmp(opt,"noaccel",7))
1256 else if (!strncmp(opt,"fp",2))
1257 displaytype = DISPLAY_FP;
1258 else if (!strncmp(opt,"crt",3))
1259 displaytype = DISPLAY_CRT;
1260 else if (!strncmp(opt,"bpp=",4))
1261 bpp = simple_strtoul(opt+4,NULL,0);
1262 else if (!strncmp(opt,"center",6))
1264 else if (!strncmp(opt,"stretch",7))
1266 else if (!strncmp(opt,"memsize=",8))
1267 memsize = simple_strtoul(opt+8,NULL,0);
1268 else if (!strncmp(opt,"memdiff=",8))
1269 memdiff = simple_strtoul(opt+8,NULL,0);
1270 else if (!strncmp(opt,"nativex=",8))
1271 nativex = simple_strtoul(opt+8,NULL,0);
1279 static int __init tridentfb_init(void)
1282 char *option = NULL;
1284 if (fb_get_options("tridentfb", &option))
1286 tridentfb_setup(option);
1288 output("Trident framebuffer %s initializing\n", VERSION);
1289 return pci_register_driver(&tridentfb_pci_driver);
1292 static void __exit tridentfb_exit(void)
1294 pci_unregister_driver(&tridentfb_pci_driver);
1297 static struct fb_ops tridentfb_ops = {
1298 .owner = THIS_MODULE,
1299 .fb_setcolreg = tridentfb_setcolreg,
1300 .fb_pan_display = tridentfb_pan_display,
1301 .fb_blank = tridentfb_blank,
1302 .fb_check_var = tridentfb_check_var,
1303 .fb_set_par = tridentfb_set_par,
1304 .fb_fillrect = tridentfb_fillrect,
1305 .fb_copyarea= tridentfb_copyarea,
1306 .fb_imageblit = cfb_imageblit,
1309 module_init(tridentfb_init);
1310 module_exit(tridentfb_exit);
1312 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1313 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1314 MODULE_LICENSE("GPL");