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 void __iomem * io_virt; //iospace virtual memory address
34 static 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 u32 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_param(mode, charp, 0);
80 module_param(bpp, int, 0);
81 module_param(center, int, 0);
82 module_param(stretch, int, 0);
83 module_param(noaccel, int, 0);
84 module_param(memsize, int, 0);
85 module_param(memdiff, int, 0);
86 module_param(nativex, int, 0);
87 module_param(fp, int, 0);
88 module_param(crt, int, 0);
94 static int is3Dchip(int id)
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));
107 static int iscyber(int id)
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 = ((u32 *)(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 void write3CE(int reg, unsigned char val)
532 static inline void enable_mmio(void)
538 /* Unprotect registers */
539 outb(NewMode1, 0x3C4);
544 outb(inb(0x3D5) | 0x01, 0x3D5);
548 #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
550 /* Return flat panel's maximum x resolution */
551 static int __init get_nativex(void)
558 tmp = (read3CE(VertStretch) >> 4) & 3;
561 case 0: x = 1280; y = 1024; break;
562 case 2: x = 1024; y = 768; break;
563 case 3: x = 800; y = 600; break;
564 case 4: x = 1400; y = 1050; break;
566 default:x = 640; y = 480; break;
569 output("%dx%d flat panel found\n", x, y);
574 static void set_lwidth(int width)
576 write3X4(Offset, width & 0xFF);
577 write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4));
580 /* For resolutions smaller than FP resolution stretch */
581 static void screen_stretch(void)
583 if (chip_id != CYBERBLADEXPAi1)
587 write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1);
588 write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1);
591 /* For resolutions smaller than FP resolution center */
592 static void screen_center(void)
594 write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80);
595 write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80);
598 /* Address of first shown pixel in display memory */
599 static void set_screen_start(int base)
601 write3X4(StartAddrLow, base & 0xFF);
602 write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
603 write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
604 write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
607 /* Use 20.12 fixed-point for NTSC value and frequency calculation */
608 #define calc_freq(n,m,k) ( ((unsigned long)0xE517 * (n+8) / ((m+2)*(1<<k))) >> 12 )
610 /* Set dotclock frequency */
611 static void set_vclk(int freq)
615 unsigned char lo=0,hi=0;
620 for(n = 0;n<128;n++) {
621 fi = calc_freq(n,m,k);
622 if ((di = abs(fi - freq)) < d) {
630 write3C4(ClockHigh,hi);
631 write3C4(ClockLow,lo);
636 debug("VCLK = %X %X\n",hi,lo);
639 /* Set number of lines for flat panels*/
640 static void set_number_of_lines(int lines)
642 int tmp = read3CE(CyberEnhance) & 0x8F;
645 else if (lines > 768)
647 else if (lines > 600)
649 else if (lines > 480)
651 write3CE(CyberEnhance, tmp);
655 * If we see that FP is active we assume we have one.
656 * Otherwise we have a CRT display.User can override.
658 static unsigned int __init get_displaytype(void)
662 if (crt || !chipcyber)
664 return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
667 /* Try detecting the video memory size */
668 static unsigned int __init get_memsize(void)
670 unsigned char tmp, tmp2;
673 /* If memory size provided by user */
678 case CYBER9525DVD: k = 2560 * Kb; break;
680 tmp = read3X4(SPR) & 0x0F;
683 case 0x01: k = 512; break;
684 case 0x02: k = 6 * Mb; break; /* XP */
685 case 0x03: k = 1 * Mb; break;
686 case 0x04: k = 8 * Mb; break;
687 case 0x06: k = 10 * Mb; break; /* XP */
688 case 0x07: k = 2 * Mb; break;
689 case 0x08: k = 12 * Mb; break; /* XP */
690 case 0x0A: k = 14 * Mb; break; /* XP */
691 case 0x0C: k = 16 * Mb; break; /* XP */
694 tmp2 = read3C4(0xC1);
696 case 0x00: k = 20 * Mb; break;
697 case 0x01: k = 24 * Mb; break;
698 case 0x10: k = 28 * Mb; break;
699 case 0x11: k = 32 * Mb; break;
700 default: k = 1 * Mb; break;
704 case 0x0F: k = 4 * Mb; break;
710 output("framebuffer size = %d Kb\n", k/Kb);
714 /* See if we can handle the video mode described in var */
715 static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
717 int bpp = var->bits_per_pixel;
720 /* check color depth */
722 bpp = var->bits_per_pixel = 32;
723 /* check whether resolution fits on panel and in memory*/
724 if (flatpanel && nativex && var->xres > nativex)
726 if (var->xres * var->yres_virtual * bpp/8 > info->fix.smem_len)
732 var->green.offset = 0;
733 var->blue.offset = 0;
735 var->green.length = 6;
736 var->blue.length = 6;
739 var->red.offset = 11;
740 var->green.offset = 5;
741 var->blue.offset = 0;
743 var->green.length = 6;
744 var->blue.length = 5;
747 var->red.offset = 16;
748 var->green.offset = 8;
749 var->blue.offset = 0;
751 var->green.length = 8;
752 var->blue.length = 8;
762 /* Pan the display */
763 static int tridentfb_pan_display(struct fb_var_screeninfo *var,
764 struct fb_info *info)
769 offset = (var->xoffset + (var->yoffset * var->xres))
770 * var->bits_per_pixel/32;
771 info->var.xoffset = var->xoffset;
772 info->var.yoffset = var->yoffset;
773 set_screen_start(offset);
778 #define shadowmode_on() write3CE(CyberControl,read3CE(CyberControl) | 0x81)
779 #define shadowmode_off() write3CE(CyberControl,read3CE(CyberControl) & 0x7E)
781 /* Set the hardware to the requested video mode */
782 static int tridentfb_set_par(struct fb_info *info)
784 struct tridentfb_par * par = (struct tridentfb_par *)(info->par);
785 u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
786 vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
787 struct fb_var_screeninfo *var = &info->var;
788 int bpp = var->bits_per_pixel;
791 htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10;
792 hdispend = var->xres/8 - 1;
793 hsyncstart = (var->xres + var->right_margin)/8;
794 hsyncend = var->hsync_len/8;
795 hblankstart = hdispend + 1;
796 hblankend = htotal + 5;
798 vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len - 2;
799 vdispend = var->yres - 1;
800 vsyncstart = var->yres + var->lower_margin;
801 vsyncend = var->vsync_len;
802 vblankstart = var->yres;
803 vblankend = vtotal + 2;
807 write3CE(CyberControl,8);
809 if (flatpanel && var->xres < nativex) {
811 * on flat panels with native size larger
812 * than requested resolution decide whether
813 * we stretch or center
826 write3CE(CyberControl,8);
829 /* vertical timing values */
830 write3X4(CRTVTotal, vtotal & 0xFF);
831 write3X4(CRTVDispEnd, vdispend & 0xFF);
832 write3X4(CRTVSyncStart, vsyncstart & 0xFF);
833 write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
834 write3X4(CRTVBlankStart, vblankstart & 0xFF);
835 write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/);
837 /* horizontal timing values */
838 write3X4(CRTHTotal, htotal & 0xFF);
839 write3X4(CRTHDispEnd, hdispend & 0xFF);
840 write3X4(CRTHSyncStart, hsyncstart & 0xFF);
841 write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
842 write3X4(CRTHBlankStart, hblankstart & 0xFF);
843 write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/);
845 /* higher bits of vertical timing values */
847 if (vtotal & 0x100) tmp |= 0x01;
848 if (vdispend & 0x100) tmp |= 0x02;
849 if (vsyncstart & 0x100) tmp |= 0x04;
850 if (vblankstart & 0x100) tmp |= 0x08;
852 if (vtotal & 0x200) tmp |= 0x20;
853 if (vdispend & 0x200) tmp |= 0x40;
854 if (vsyncstart & 0x200) tmp |= 0x80;
855 write3X4(CRTOverflow, tmp);
857 tmp = read3X4(CRTHiOrd) | 0x08; //line compare bit 10
858 if (vtotal & 0x400) tmp |= 0x80;
859 if (vblankstart & 0x400) tmp |= 0x40;
860 if (vsyncstart & 0x400) tmp |= 0x20;
861 if (vdispend & 0x400) tmp |= 0x10;
862 write3X4(CRTHiOrd, tmp);
865 if (htotal & 0x800) tmp |= 0x800 >> 11;
866 if (hblankstart & 0x800) tmp |= 0x800 >> 7;
867 write3X4(HorizOverflow, tmp);
870 if (vblankstart & 0x200) tmp |= 0x20;
871 //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; //double scan for 200 line modes
872 write3X4(CRTMaxScanLine, tmp);
874 write3X4(CRTLineCompare,0xFF);
875 write3X4(CRTPRowScan,0);
876 write3X4(CRTModeControl,0xC3);
878 write3X4(LinearAddReg,0x20); //enable linear addressing
880 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80;
881 write3X4(CRTCModuleTest,tmp); //enable access extended memory
883 write3X4(GraphEngReg, 0x80); //enable GE for text acceleration
885 // if (info->var.accel_flags & FB_ACCELF_TEXT)
886 //FIXME acc->init_accel(info->var.xres,bpp);
889 case 8: tmp = 0x00; break;
890 case 16: tmp = 0x05; break;
891 case 24: tmp = 0x29; break;
895 write3X4(PixelBusReg, tmp);
900 write3X4(DRAMControl, tmp); //both IO,linear enable
902 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
903 write3X4(Performance,0x20);
904 write3X4(PCIReg,0x07); //MMIO & PCI read and write burst enable
906 /* convert from picoseconds to MHz */
907 par->vclk = 1000000/info->var.pixclock;
913 write3C4(1,1); //set char clock 8 dots wide
914 write3C4(2,0x0F); //enable 4 maps because needed in chain4 mode
916 write3C4(4,0x0E); //memory mode enable bitmaps ??
918 write3CE(MiscExtFunc,(bpp==32)?0x1A:0x12); //divide clock by 2 if 32bpp
919 //chain4 mode display and CPU path
920 write3CE(0x5,0x40); //no CGA compat,allow 256 col
921 write3CE(0x6,0x05); //graphics mode
922 write3CE(0x7,0x0F); //planes?
924 if (chip_id == CYBERBLADEXPAi1) {
925 /* This fixes snow-effect in 32 bpp */
926 write3X4(CRTHSyncStart,0x84);
929 writeAttr(0x10,0x41); //graphics mode and support 256 color modes
930 writeAttr(0x12,0x0F); //planes
931 writeAttr(0x13,0); //horizontal pel panning
934 for(tmp = 0;tmp < 0x10;tmp++)
936 readb(par->io_virt + CRT + 0x0A); //flip-flop to index
937 t_outb(0x20, 0x3C0); //enable attr
940 case 8: tmp = 0;break; //256 colors
941 case 15: tmp = 0x10;break;
942 case 16: tmp = 0x30;break; //hicolor
944 case 32: tmp = 0xD0;break;
956 set_number_of_lines(info->var.yres);
957 set_lwidth(info->var.xres * bpp/(4*16));
958 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
959 info->fix.line_length = info->var.xres * (bpp >> 3);
960 info->cmap.len = (bpp == 8) ? 256: 16;
965 /* Set one color register */
966 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
967 unsigned blue, unsigned transp,
968 struct fb_info *info)
970 int bpp = info->var.bits_per_pixel;
972 if (regno >= info->cmap.len)
980 t_outb(red>>10,0x3C9);
981 t_outb(green>>10,0x3C9);
982 t_outb(blue>>10,0x3C9);
985 if (bpp == 16) /* RGB 565 */
986 ((u32*)info->pseudo_palette)[regno] = (red & 0xF800) |
987 ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
989 if (bpp == 32) /* ARGB 8888 */
990 ((u32*)info->pseudo_palette)[regno] =
991 ((transp & 0xFF00) <<16) |
992 ((red & 0xFF00) << 8) |
994 ((blue & 0xFF00)>>8);
1000 /* Try blanking the screen.For flat panels it does nothing */
1001 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1003 unsigned char PMCont,DPMSCont;
1008 t_outb(0x04,0x83C8); /* Read DPMS Control */
1009 PMCont = t_inb(0x83C6) & 0xFC;
1010 DPMSCont = read3CE(PowerStatus) & 0xFC;
1013 case FB_BLANK_UNBLANK:
1014 /* Screen: On, HSync: On, VSync: On */
1015 case FB_BLANK_NORMAL:
1016 /* Screen: Off, HSync: On, VSync: On */
1020 case FB_BLANK_HSYNC_SUSPEND:
1021 /* Screen: Off, HSync: Off, VSync: On */
1025 case FB_BLANK_VSYNC_SUSPEND:
1026 /* Screen: Off, HSync: On, VSync: Off */
1030 case FB_BLANK_POWERDOWN:
1031 /* Screen: Off, HSync: Off, VSync: Off */
1037 write3CE(PowerStatus,DPMSCont);
1039 t_outb(PMCont,0x83C6);
1043 /* let fbcon do a softblank for us */
1044 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1047 static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id)
1050 unsigned char revision;
1052 err = pci_enable_device(dev);
1056 chip_id = id->device;
1058 /* If PCI id is 0x9660 then further detect chip type */
1060 if (chip_id == TGUI9660) {
1061 outb(RevisionID,0x3C4);
1062 revision = inb(0x3C5);
1066 case 0x23: chip_id = CYBER9397;break;
1067 case 0x2A: chip_id = CYBER9397DVD;break;
1074 case 0xB3: chip_id = CYBER9385;break;
1075 case 0x40 ... 0x43: chip_id = CYBER9382;break;
1076 case 0x4A: chip_id = CYBER9388;break;
1081 chip3D = is3Dchip(chip_id);
1082 chipcyber = iscyber(chip_id);
1084 if (is_xp(chip_id)) {
1087 if (is_blade(chip_id)) {
1093 /* acceleration is on by default for 3D chips */
1094 defaultaccel = chip3D && !noaccel;
1096 fb_info.par = &default_par;
1098 /* setup MMIO region */
1099 tridentfb_fix.mmio_start = pci_resource_start(dev,1);
1100 tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000;
1102 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1103 debug("request_region failed!\n");
1107 default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1109 if (!default_par.io_virt) {
1110 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1111 debug("ioremap failed\n");
1117 /* setup framebuffer memory */
1118 tridentfb_fix.smem_start = pci_resource_start(dev,0);
1119 tridentfb_fix.smem_len = get_memsize();
1121 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1122 debug("request_mem_region failed!\n");
1126 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1127 tridentfb_fix.smem_len);
1129 if (!fb_info.screen_base) {
1130 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1131 debug("ioremap failed\n");
1135 output("%s board found\n", pci_name(dev));
1137 output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n",
1138 tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt);
1140 displaytype = get_displaytype();
1143 nativex = get_nativex();
1145 fb_info.fix = tridentfb_fix;
1146 fb_info.fbops = &tridentfb_ops;
1149 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1150 #ifdef CONFIG_FB_TRIDENT_ACCEL
1151 fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
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 fb_info.device = &dev->dev;
1165 if (register_framebuffer(&fb_info) < 0) {
1166 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1169 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1170 fb_info.node, fb_info.fix.id,default_var.xres,
1171 default_var.yres,default_var.bits_per_pixel);
1175 static void __devexit trident_pci_remove(struct pci_dev * dev)
1177 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1178 unregister_framebuffer(&fb_info);
1179 iounmap(par->io_virt);
1180 iounmap(fb_info.screen_base);
1181 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1182 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1185 /* List of boards that we are trying to support */
1186 static struct pci_device_id trident_devices[] = {
1187 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1188 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1189 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1190 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1191 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1192 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1193 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1194 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1195 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1196 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1197 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1198 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1199 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1200 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1201 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1202 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1203 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1204 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1205 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1206 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1210 MODULE_DEVICE_TABLE(pci,trident_devices);
1212 static struct pci_driver tridentfb_pci_driver = {
1213 .name = "tridentfb",
1214 .id_table = trident_devices,
1215 .probe = trident_pci_probe,
1216 .remove = __devexit_p(trident_pci_remove)
1220 * Parse user specified options (`video=trident:')
1222 * video=trident:800x600,bpp=16,noaccel
1225 static int tridentfb_setup(char *options)
1228 if (!options || !*options)
1230 while((opt = strsep(&options,",")) != NULL ) {
1231 if (!*opt) continue;
1232 if (!strncmp(opt,"noaccel",7))
1234 else if (!strncmp(opt,"fp",2))
1235 displaytype = DISPLAY_FP;
1236 else if (!strncmp(opt,"crt",3))
1237 displaytype = DISPLAY_CRT;
1238 else if (!strncmp(opt,"bpp=",4))
1239 bpp = simple_strtoul(opt+4,NULL,0);
1240 else if (!strncmp(opt,"center",6))
1242 else if (!strncmp(opt,"stretch",7))
1244 else if (!strncmp(opt,"memsize=",8))
1245 memsize = simple_strtoul(opt+8,NULL,0);
1246 else if (!strncmp(opt,"memdiff=",8))
1247 memdiff = simple_strtoul(opt+8,NULL,0);
1248 else if (!strncmp(opt,"nativex=",8))
1249 nativex = simple_strtoul(opt+8,NULL,0);
1257 static int __init tridentfb_init(void)
1260 char *option = NULL;
1262 if (fb_get_options("tridentfb", &option))
1264 tridentfb_setup(option);
1266 output("Trident framebuffer %s initializing\n", VERSION);
1267 return pci_register_driver(&tridentfb_pci_driver);
1270 static void __exit tridentfb_exit(void)
1272 pci_unregister_driver(&tridentfb_pci_driver);
1275 static struct fb_ops tridentfb_ops = {
1276 .owner = THIS_MODULE,
1277 .fb_setcolreg = tridentfb_setcolreg,
1278 .fb_pan_display = tridentfb_pan_display,
1279 .fb_blank = tridentfb_blank,
1280 .fb_check_var = tridentfb_check_var,
1281 .fb_set_par = tridentfb_set_par,
1282 .fb_fillrect = tridentfb_fillrect,
1283 .fb_copyarea= tridentfb_copyarea,
1284 .fb_imageblit = cfb_imageblit,
1285 .fb_cursor = soft_cursor,
1288 module_init(tridentfb_init);
1289 module_exit(tridentfb_exit);
1291 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1292 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1293 MODULE_LICENSE("GPL");