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 (regno < 16) {
988 if (bpp == 16) { /* RGB 565 */
991 col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
992 ((blue & 0xF800) >> 11);
994 ((u32 *)(info->pseudo_palette))[regno] = col;
995 } else if (bpp == 32) /* ARGB 8888 */
996 ((u32*)info->pseudo_palette)[regno] =
997 ((transp & 0xFF00) <<16) |
998 ((red & 0xFF00) << 8) |
1000 ((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 FB_BLANK_UNBLANK:
1021 /* Screen: On, HSync: On, VSync: On */
1022 case FB_BLANK_NORMAL:
1023 /* Screen: Off, HSync: On, VSync: On */
1027 case FB_BLANK_HSYNC_SUSPEND:
1028 /* Screen: Off, HSync: Off, VSync: On */
1032 case FB_BLANK_VSYNC_SUSPEND:
1033 /* Screen: Off, HSync: On, VSync: Off */
1037 case FB_BLANK_POWERDOWN:
1038 /* Screen: Off, HSync: Off, VSync: Off */
1044 write3CE(PowerStatus,DPMSCont);
1046 t_outb(PMCont,0x83C6);
1050 /* let fbcon do a softblank for us */
1051 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1054 static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id)
1057 unsigned char revision;
1059 err = pci_enable_device(dev);
1063 chip_id = id->device;
1065 if(chip_id == CYBERBLADEi1)
1066 output("*** Please do use cyblafb, Cyberblade/i1 support "
1067 "will soon be removed from tridentfb!\n");
1070 /* If PCI id is 0x9660 then further detect chip type */
1072 if (chip_id == TGUI9660) {
1073 outb(RevisionID,0x3C4);
1074 revision = inb(0x3C5);
1078 case 0x23: chip_id = CYBER9397;break;
1079 case 0x2A: chip_id = CYBER9397DVD;break;
1086 case 0xB3: chip_id = CYBER9385;break;
1087 case 0x40 ... 0x43: chip_id = CYBER9382;break;
1088 case 0x4A: chip_id = CYBER9388;break;
1093 chip3D = is3Dchip(chip_id);
1094 chipcyber = iscyber(chip_id);
1096 if (is_xp(chip_id)) {
1099 if (is_blade(chip_id)) {
1105 /* acceleration is on by default for 3D chips */
1106 defaultaccel = chip3D && !noaccel;
1108 fb_info.par = &default_par;
1110 /* setup MMIO region */
1111 tridentfb_fix.mmio_start = pci_resource_start(dev,1);
1112 tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000;
1114 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1115 debug("request_region failed!\n");
1119 default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1121 if (!default_par.io_virt) {
1122 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1123 debug("ioremap failed\n");
1129 /* setup framebuffer memory */
1130 tridentfb_fix.smem_start = pci_resource_start(dev,0);
1131 tridentfb_fix.smem_len = get_memsize();
1133 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1134 debug("request_mem_region failed!\n");
1139 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1140 tridentfb_fix.smem_len);
1142 if (!fb_info.screen_base) {
1143 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1144 debug("ioremap failed\n");
1149 output("%s board found\n", pci_name(dev));
1151 output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n",
1152 tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt);
1154 displaytype = get_displaytype();
1157 nativex = get_nativex();
1159 fb_info.fix = tridentfb_fix;
1160 fb_info.fbops = &tridentfb_ops;
1163 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1164 #ifdef CONFIG_FB_TRIDENT_ACCEL
1165 fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1167 fb_info.pseudo_palette = pseudo_pal;
1169 if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp)) {
1173 fb_alloc_cmap(&fb_info.cmap,256,0);
1174 if (defaultaccel && acc)
1175 default_var.accel_flags |= FB_ACCELF_TEXT;
1177 default_var.accel_flags &= ~FB_ACCELF_TEXT;
1178 default_var.activate |= FB_ACTIVATE_NOW;
1179 fb_info.var = default_var;
1180 fb_info.device = &dev->dev;
1181 if (register_framebuffer(&fb_info) < 0) {
1182 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1186 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1187 fb_info.node, fb_info.fix.id,default_var.xres,
1188 default_var.yres,default_var.bits_per_pixel);
1192 if (default_par.io_virt)
1193 iounmap(default_par.io_virt);
1194 if (fb_info.screen_base)
1195 iounmap(fb_info.screen_base);
1199 static void __devexit trident_pci_remove(struct pci_dev * dev)
1201 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1202 unregister_framebuffer(&fb_info);
1203 iounmap(par->io_virt);
1204 iounmap(fb_info.screen_base);
1205 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1206 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1209 /* List of boards that we are trying to support */
1210 static struct pci_device_id trident_devices[] = {
1211 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1212 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1213 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1214 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1215 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1216 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1217 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1218 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1219 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1220 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1221 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1222 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1223 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1224 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1225 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1226 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1227 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1228 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1229 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1230 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1234 MODULE_DEVICE_TABLE(pci,trident_devices);
1236 static struct pci_driver tridentfb_pci_driver = {
1237 .name = "tridentfb",
1238 .id_table = trident_devices,
1239 .probe = trident_pci_probe,
1240 .remove = __devexit_p(trident_pci_remove)
1244 * Parse user specified options (`video=trident:')
1246 * video=trident:800x600,bpp=16,noaccel
1249 static int tridentfb_setup(char *options)
1252 if (!options || !*options)
1254 while((opt = strsep(&options,",")) != NULL ) {
1255 if (!*opt) continue;
1256 if (!strncmp(opt,"noaccel",7))
1258 else if (!strncmp(opt,"fp",2))
1259 displaytype = DISPLAY_FP;
1260 else if (!strncmp(opt,"crt",3))
1261 displaytype = DISPLAY_CRT;
1262 else if (!strncmp(opt,"bpp=",4))
1263 bpp = simple_strtoul(opt+4,NULL,0);
1264 else if (!strncmp(opt,"center",6))
1266 else if (!strncmp(opt,"stretch",7))
1268 else if (!strncmp(opt,"memsize=",8))
1269 memsize = simple_strtoul(opt+8,NULL,0);
1270 else if (!strncmp(opt,"memdiff=",8))
1271 memdiff = simple_strtoul(opt+8,NULL,0);
1272 else if (!strncmp(opt,"nativex=",8))
1273 nativex = simple_strtoul(opt+8,NULL,0);
1281 static int __init tridentfb_init(void)
1284 char *option = NULL;
1286 if (fb_get_options("tridentfb", &option))
1288 tridentfb_setup(option);
1290 output("Trident framebuffer %s initializing\n", VERSION);
1291 return pci_register_driver(&tridentfb_pci_driver);
1294 static void __exit tridentfb_exit(void)
1296 pci_unregister_driver(&tridentfb_pci_driver);
1299 static struct fb_ops tridentfb_ops = {
1300 .owner = THIS_MODULE,
1301 .fb_setcolreg = tridentfb_setcolreg,
1302 .fb_pan_display = tridentfb_pan_display,
1303 .fb_blank = tridentfb_blank,
1304 .fb_check_var = tridentfb_check_var,
1305 .fb_set_par = tridentfb_set_par,
1306 .fb_fillrect = tridentfb_fillrect,
1307 .fb_copyarea= tridentfb_copyarea,
1308 .fb_imageblit = cfb_imageblit,
1311 module_init(tridentfb_init);
1312 module_exit(tridentfb_exit);
1314 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1315 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1316 MODULE_LICENSE("GPL");