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
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);
479 * Hardware access functions
482 static inline unsigned char read3X4(int reg)
484 struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
485 writeb(reg, par->io_virt + CRT + 4);
486 return readb( par->io_virt + CRT + 5);
489 static inline void write3X4(int reg, unsigned char val)
491 struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
492 writeb(reg, par->io_virt + CRT + 4);
493 writeb(val, par->io_virt + CRT + 5);
496 static inline unsigned char read3C4(int reg)
502 static inline void write3C4(int reg, unsigned char val)
508 static inline unsigned char read3CE(int reg)
514 static inline void writeAttr(int reg, unsigned char val)
516 readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); //flip-flop to index
521 static inline unsigned char readAttr(int reg)
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 __init 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 __init 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 __init 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 // if (info->var.accel_flags & FB_ACCELF_TEXT)
888 //FIXME acc->init_accel(info->var.xres,bpp);
891 case 8: tmp = 0x00; break;
892 case 16: tmp = 0x05; break;
893 case 24: tmp = 0x29; break;
897 write3X4(PixelBusReg, tmp);
902 write3X4(DRAMControl, tmp); //both IO,linear enable
904 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
905 write3X4(Performance,0x20);
906 write3X4(PCIReg,0x07); //MMIO & PCI read and write burst enable
908 /* convert from picoseconds to MHz */
909 par->vclk = 1000000/info->var.pixclock;
915 write3C4(1,1); //set char clock 8 dots wide
916 write3C4(2,0x0F); //enable 4 maps because needed in chain4 mode
918 write3C4(4,0x0E); //memory mode enable bitmaps ??
920 write3CE(MiscExtFunc,(bpp==32)?0x1A:0x12); //divide clock by 2 if 32bpp
921 //chain4 mode display and CPU path
922 write3CE(0x5,0x40); //no CGA compat,allow 256 col
923 write3CE(0x6,0x05); //graphics mode
924 write3CE(0x7,0x0F); //planes?
926 if (chip_id == CYBERBLADEXPAi1) {
927 /* This fixes snow-effect in 32 bpp */
928 write3X4(CRTHSyncStart,0x84);
931 writeAttr(0x10,0x41); //graphics mode and support 256 color modes
932 writeAttr(0x12,0x0F); //planes
933 writeAttr(0x13,0); //horizontal pel panning
936 for(tmp = 0;tmp < 0x10;tmp++)
938 readb(par->io_virt + CRT + 0x0A); //flip-flop to index
939 t_outb(0x20, 0x3C0); //enable attr
942 case 8: tmp = 0;break; //256 colors
943 case 15: tmp = 0x10;break;
944 case 16: tmp = 0x30;break; //hicolor
946 case 32: tmp = 0xD0;break;
958 set_number_of_lines(info->var.yres);
959 set_lwidth(info->var.xres * bpp/(4*16));
960 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
961 info->fix.line_length = info->var.xres * (bpp >> 3);
962 info->cmap.len = (bpp == 8) ? 256: 16;
967 /* Set one color register */
968 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
969 unsigned blue, unsigned transp,
970 struct fb_info *info)
972 int bpp = info->var.bits_per_pixel;
974 if (regno >= info->cmap.len)
982 t_outb(red>>10,0x3C9);
983 t_outb(green>>10,0x3C9);
984 t_outb(blue>>10,0x3C9);
987 if (bpp == 16) /* RGB 565 */
988 ((u16*)info->pseudo_palette)[regno] = (red & 0xF800) |
989 ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
991 if (bpp == 32) /* ARGB 8888 */
992 ((u32*)info->pseudo_palette)[regno] =
993 ((transp & 0xFF00) <<16) |
994 ((red & 0xFF00) << 8) |
996 ((blue & 0xFF00)>>8);
1002 /* Try blanking the screen.For flat panels it does nothing */
1003 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1005 unsigned char PMCont,DPMSCont;
1010 t_outb(0x04,0x83C8); /* Read DPMS Control */
1011 PMCont = t_inb(0x83C6) & 0xFC;
1012 DPMSCont = read3CE(PowerStatus) & 0xFC;
1015 case VESA_NO_BLANKING:
1016 /* Screen: On, HSync: On, VSync: On */
1020 case VESA_HSYNC_SUSPEND:
1021 /* Screen: Off, HSync: Off, VSync: On */
1025 case VESA_VSYNC_SUSPEND:
1026 /* Screen: Off, HSync: On, VSync: Off */
1030 case VESA_POWERDOWN:
1031 /* Screen: Off, HSync: Off, VSync: Off */
1037 write3CE(PowerStatus,DPMSCont);
1039 t_outb(PMCont,0x83C6);
1045 static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id)
1048 unsigned char revision;
1050 err = pci_enable_device(dev);
1054 chip_id = id->device;
1056 /* If PCI id is 0x9660 then further detect chip type */
1058 if (chip_id == TGUI9660) {
1059 outb(RevisionID,0x3C4);
1060 revision = inb(0x3C5);
1064 case 0x23: chip_id = CYBER9397;break;
1065 case 0x2A: chip_id = CYBER9397DVD;break;
1072 case 0xB3: chip_id = CYBER9385;break;
1073 case 0x40 ... 0x43: chip_id = CYBER9382;break;
1074 case 0x4A: chip_id = CYBER9388;break;
1079 chip3D = is3Dchip(chip_id);
1080 chipcyber = iscyber(chip_id);
1082 if (is_xp(chip_id)) {
1085 if (is_blade(chip_id)) {
1091 /* acceleration is on by default for 3D chips */
1092 defaultaccel = chip3D && !noaccel;
1094 fb_info.par = &default_par;
1096 /* setup MMIO region */
1097 tridentfb_fix.mmio_start = pci_resource_start(dev,1);
1098 tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000;
1100 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1101 debug("request_region failed!\n");
1105 default_par.io_virt = (unsigned long)ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1107 if (!default_par.io_virt) {
1108 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1109 debug("ioremap failed\n");
1115 /* setup framebuffer memory */
1116 tridentfb_fix.smem_start = pci_resource_start(dev,0);
1117 tridentfb_fix.smem_len = get_memsize();
1119 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1120 debug("request_mem_region failed!\n");
1124 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1125 tridentfb_fix.smem_len);
1127 if (!fb_info.screen_base) {
1128 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1129 debug("ioremap failed\n");
1133 output("%s board found\n", pci_name(dev));
1135 output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n",
1136 tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt);
1138 displaytype = get_displaytype();
1141 nativex = get_nativex();
1143 fb_info.fix = tridentfb_fix;
1144 fb_info.fbops = &tridentfb_ops;
1147 fb_info.flags = FBINFO_FLAG_DEFAULT;
1148 fb_info.pseudo_palette = pseudo_pal;
1150 if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp))
1152 fb_alloc_cmap(&fb_info.cmap,256,0);
1153 if (defaultaccel && acc)
1154 default_var.accel_flags |= FB_ACCELF_TEXT;
1156 default_var.accel_flags &= ~FB_ACCELF_TEXT;
1157 default_var.activate |= FB_ACTIVATE_NOW;
1158 fb_info.var = default_var;
1159 if (register_framebuffer(&fb_info) < 0) {
1160 output("Could not register Trident framebuffer\n");
1163 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1164 fb_info.node, fb_info.fix.id,default_var.xres,
1165 default_var.yres,default_var.bits_per_pixel);
1169 static void __devexit trident_pci_remove(struct pci_dev * dev)
1171 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1172 unregister_framebuffer(&fb_info);
1173 iounmap((void *)par->io_virt);
1174 iounmap((void*)fb_info.screen_base);
1175 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1176 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1179 /* List of boards that we are trying to support */
1180 static struct pci_device_id trident_devices[] = {
1181 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1182 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1183 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1184 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1185 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1186 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1187 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1188 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1189 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1190 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1191 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1192 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1193 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1194 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1195 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1196 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1197 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1198 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1199 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1200 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1204 MODULE_DEVICE_TABLE(pci,trident_devices);
1206 static struct pci_driver tridentfb_pci_driver = {
1207 .name = "tridentfb",
1208 .id_table = trident_devices,
1209 .probe = trident_pci_probe,
1210 .remove = __devexit_p(trident_pci_remove)
1213 int __init tridentfb_init(void)
1215 output("Trident framebuffer %s initializing\n", VERSION);
1216 return pci_module_init(&tridentfb_pci_driver);
1219 void __exit tridentfb_exit(void)
1221 pci_unregister_driver(&tridentfb_pci_driver);
1226 * Parse user specified options (`video=trident:')
1228 * video=trident:800x600,bpp=16,noaccel
1230 int tridentfb_setup(char *options)
1233 if (!options || !*options)
1235 while((opt = strsep(&options,",")) != NULL ) {
1236 if (!*opt) continue;
1237 if (!strncmp(opt,"noaccel",7))
1239 else if (!strncmp(opt,"fp",2))
1240 displaytype = DISPLAY_FP;
1241 else if (!strncmp(opt,"crt",3))
1242 displaytype = DISPLAY_CRT;
1243 else if (!strncmp(opt,"bpp=",4))
1244 bpp = simple_strtoul(opt+4,NULL,0);
1245 else if (!strncmp(opt,"center",6))
1247 else if (!strncmp(opt,"stretch",7))
1249 else if (!strncmp(opt,"memsize=",8))
1250 memsize = simple_strtoul(opt+8,NULL,0);
1251 else if (!strncmp(opt,"memdiff=",8))
1252 memdiff = simple_strtoul(opt+8,NULL,0);
1253 else if (!strncmp(opt,"nativex=",8))
1254 nativex = simple_strtoul(opt+8,NULL,0);
1261 static struct fb_ops tridentfb_ops = {
1262 .owner = THIS_MODULE,
1263 .fb_setcolreg = tridentfb_setcolreg,
1264 .fb_pan_display = tridentfb_pan_display,
1265 .fb_blank = tridentfb_blank,
1266 .fb_check_var = tridentfb_check_var,
1267 .fb_set_par = tridentfb_set_par,
1268 // .fb_fillrect = tridentfb_fillrect,
1269 // .fb_copyarea= tridentfb_copyarea,
1270 .fb_fillrect = cfb_fillrect,
1271 .fb_copyarea= cfb_copyarea,
1272 .fb_imageblit = cfb_imageblit,
1273 .fb_cursor = soft_cursor,
1277 module_init(tridentfb_init);
1279 module_exit(tridentfb_exit);
1281 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1282 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1283 MODULE_LICENSE("GPL");