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;
465 case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
468 case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
472 acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop);
475 static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
477 acc->copy_rect(ca->sx,ca->sy,ca->dx,ca->dy,ca->width,ca->height);
480 #else /* !CONFIG_FB_TRIDENT_ACCEL */
481 #define tridentfb_fillrect cfb_fillrect
482 #define tridentfb_copyarea cfb_copyarea
483 #endif /* CONFIG_FB_TRIDENT_ACCEL */
487 * Hardware access functions
490 static inline unsigned char read3X4(int reg)
492 struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
493 writeb(reg, par->io_virt + CRT + 4);
494 return readb( par->io_virt + CRT + 5);
497 static inline void write3X4(int reg, unsigned char val)
499 struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
500 writeb(reg, par->io_virt + CRT + 4);
501 writeb(val, par->io_virt + CRT + 5);
504 static inline unsigned char read3C4(int reg)
510 static inline void write3C4(int reg, unsigned char val)
516 static inline unsigned char read3CE(int reg)
522 static inline void writeAttr(int reg, unsigned char val)
524 readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); //flip-flop to index
529 static inline void write3CE(int reg, unsigned char val)
535 static inline void enable_mmio(void)
541 /* Unprotect registers */
542 outb(NewMode1, 0x3C4);
547 outb(inb(0x3D5) | 0x01, 0x3D5);
551 #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
553 /* Return flat panel's maximum x resolution */
554 static int __init get_nativex(void)
561 tmp = (read3CE(VertStretch) >> 4) & 3;
564 case 0: x = 1280; y = 1024; break;
565 case 2: x = 1024; y = 768; break;
566 case 3: x = 800; y = 600; break;
567 case 4: x = 1400; y = 1050; break;
569 default:x = 640; y = 480; break;
572 output("%dx%d flat panel found\n", x, y);
577 static void set_lwidth(int width)
579 write3X4(Offset, width & 0xFF);
580 write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4));
583 /* For resolutions smaller than FP resolution stretch */
584 static void screen_stretch(void)
586 if (chip_id != CYBERBLADEXPAi1)
590 write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1);
591 write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1);
594 /* For resolutions smaller than FP resolution center */
595 static void screen_center(void)
597 write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80);
598 write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80);
601 /* Address of first shown pixel in display memory */
602 static void set_screen_start(int base)
604 write3X4(StartAddrLow, base & 0xFF);
605 write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
606 write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
607 write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
610 /* Use 20.12 fixed-point for NTSC value and frequency calculation */
611 #define calc_freq(n,m,k) ( ((unsigned long)0xE517 * (n+8) / ((m+2)*(1<<k))) >> 12 )
613 /* Set dotclock frequency */
614 static void set_vclk(int freq)
618 unsigned char lo=0,hi=0;
623 for(n = 0;n<128;n++) {
624 fi = calc_freq(n,m,k);
625 if ((di = abs(fi - freq)) < d) {
633 write3C4(ClockHigh,hi);
634 write3C4(ClockLow,lo);
639 debug("VCLK = %X %X\n",hi,lo);
642 /* Set number of lines for flat panels*/
643 static void set_number_of_lines(int lines)
645 int tmp = read3CE(CyberEnhance) & 0x8F;
648 else if (lines > 768)
650 else if (lines > 600)
652 else if (lines > 480)
654 write3CE(CyberEnhance, tmp);
658 * If we see that FP is active we assume we have one.
659 * Otherwise we have a CRT display.User can override.
661 static unsigned int __init get_displaytype(void)
665 if (crt || !chipcyber)
667 return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
670 /* Try detecting the video memory size */
671 static unsigned int __init get_memsize(void)
673 unsigned char tmp, tmp2;
676 /* If memory size provided by user */
681 case CYBER9525DVD: k = 2560 * Kb; break;
683 tmp = read3X4(SPR) & 0x0F;
686 case 0x01: k = 512; break;
687 case 0x02: k = 6 * Mb; break; /* XP */
688 case 0x03: k = 1 * Mb; break;
689 case 0x04: k = 8 * Mb; break;
690 case 0x06: k = 10 * Mb; break; /* XP */
691 case 0x07: k = 2 * Mb; break;
692 case 0x08: k = 12 * Mb; break; /* XP */
693 case 0x0A: k = 14 * Mb; break; /* XP */
694 case 0x0C: k = 16 * Mb; break; /* XP */
697 tmp2 = read3C4(0xC1);
699 case 0x00: k = 20 * Mb; break;
700 case 0x01: k = 24 * Mb; break;
701 case 0x10: k = 28 * Mb; break;
702 case 0x11: k = 32 * Mb; break;
703 default: k = 1 * Mb; break;
707 case 0x0F: k = 4 * Mb; break;
713 output("framebuffer size = %d Kb\n", k/Kb);
717 /* See if we can handle the video mode described in var */
718 static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
720 int bpp = var->bits_per_pixel;
723 /* check color depth */
725 bpp = var->bits_per_pixel = 32;
726 /* check whether resolution fits on panel and in memory*/
727 if (flatpanel && nativex && var->xres > nativex)
729 if (var->xres * var->yres_virtual * bpp/8 > info->fix.smem_len)
735 var->green.offset = 0;
736 var->blue.offset = 0;
738 var->green.length = 6;
739 var->blue.length = 6;
742 var->red.offset = 11;
743 var->green.offset = 5;
744 var->blue.offset = 0;
746 var->green.length = 6;
747 var->blue.length = 5;
750 var->red.offset = 16;
751 var->green.offset = 8;
752 var->blue.offset = 0;
754 var->green.length = 8;
755 var->blue.length = 8;
765 /* Pan the display */
766 static int tridentfb_pan_display(struct fb_var_screeninfo *var,
767 struct fb_info *info)
772 offset = (var->xoffset + (var->yoffset * var->xres))
773 * var->bits_per_pixel/32;
774 info->var.xoffset = var->xoffset;
775 info->var.yoffset = var->yoffset;
776 set_screen_start(offset);
781 #define shadowmode_on() write3CE(CyberControl,read3CE(CyberControl) | 0x81)
782 #define shadowmode_off() write3CE(CyberControl,read3CE(CyberControl) & 0x7E)
784 /* Set the hardware to the requested video mode */
785 static int tridentfb_set_par(struct fb_info *info)
787 struct tridentfb_par * par = (struct tridentfb_par *)(info->par);
788 u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
789 vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
790 struct fb_var_screeninfo *var = &info->var;
791 int bpp = var->bits_per_pixel;
794 htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10;
795 hdispend = var->xres/8 - 1;
796 hsyncstart = (var->xres + var->right_margin)/8;
797 hsyncend = var->hsync_len/8;
798 hblankstart = hdispend + 1;
799 hblankend = htotal + 5;
801 vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len - 2;
802 vdispend = var->yres - 1;
803 vsyncstart = var->yres + var->lower_margin;
804 vsyncend = var->vsync_len;
805 vblankstart = var->yres;
806 vblankend = vtotal + 2;
810 write3CE(CyberControl,8);
812 if (flatpanel && var->xres < nativex) {
814 * on flat panels with native size larger
815 * than requested resolution decide whether
816 * we stretch or center
829 write3CE(CyberControl,8);
832 /* vertical timing values */
833 write3X4(CRTVTotal, vtotal & 0xFF);
834 write3X4(CRTVDispEnd, vdispend & 0xFF);
835 write3X4(CRTVSyncStart, vsyncstart & 0xFF);
836 write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
837 write3X4(CRTVBlankStart, vblankstart & 0xFF);
838 write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/);
840 /* horizontal timing values */
841 write3X4(CRTHTotal, htotal & 0xFF);
842 write3X4(CRTHDispEnd, hdispend & 0xFF);
843 write3X4(CRTHSyncStart, hsyncstart & 0xFF);
844 write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
845 write3X4(CRTHBlankStart, hblankstart & 0xFF);
846 write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/);
848 /* higher bits of vertical timing values */
850 if (vtotal & 0x100) tmp |= 0x01;
851 if (vdispend & 0x100) tmp |= 0x02;
852 if (vsyncstart & 0x100) tmp |= 0x04;
853 if (vblankstart & 0x100) tmp |= 0x08;
855 if (vtotal & 0x200) tmp |= 0x20;
856 if (vdispend & 0x200) tmp |= 0x40;
857 if (vsyncstart & 0x200) tmp |= 0x80;
858 write3X4(CRTOverflow, tmp);
860 tmp = read3X4(CRTHiOrd) | 0x08; //line compare bit 10
861 if (vtotal & 0x400) tmp |= 0x80;
862 if (vblankstart & 0x400) tmp |= 0x40;
863 if (vsyncstart & 0x400) tmp |= 0x20;
864 if (vdispend & 0x400) tmp |= 0x10;
865 write3X4(CRTHiOrd, tmp);
868 if (htotal & 0x800) tmp |= 0x800 >> 11;
869 if (hblankstart & 0x800) tmp |= 0x800 >> 7;
870 write3X4(HorizOverflow, tmp);
873 if (vblankstart & 0x200) tmp |= 0x20;
874 //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; //double scan for 200 line modes
875 write3X4(CRTMaxScanLine, tmp);
877 write3X4(CRTLineCompare,0xFF);
878 write3X4(CRTPRowScan,0);
879 write3X4(CRTModeControl,0xC3);
881 write3X4(LinearAddReg,0x20); //enable linear addressing
883 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80;
884 write3X4(CRTCModuleTest,tmp); //enable access extended memory
886 write3X4(GraphEngReg, 0x80); //enable GE for text acceleration
888 #ifdef CONFIG_FB_TRIDENT_ACCEL
889 acc->init_accel(info->var.xres,bpp);
893 case 8: tmp = 0x00; break;
894 case 16: tmp = 0x05; break;
895 case 24: tmp = 0x29; break;
899 write3X4(PixelBusReg, tmp);
904 write3X4(DRAMControl, tmp); //both IO,linear enable
906 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
907 write3X4(Performance,0x92);
908 write3X4(PCIReg,0x07); //MMIO & PCI read and write burst enable
910 /* convert from picoseconds to MHz */
911 par->vclk = 1000000/info->var.pixclock;
917 write3C4(1,1); //set char clock 8 dots wide
918 write3C4(2,0x0F); //enable 4 maps because needed in chain4 mode
920 write3C4(4,0x0E); //memory mode enable bitmaps ??
922 write3CE(MiscExtFunc,(bpp==32)?0x1A:0x12); //divide clock by 2 if 32bpp
923 //chain4 mode display and CPU path
924 write3CE(0x5,0x40); //no CGA compat,allow 256 col
925 write3CE(0x6,0x05); //graphics mode
926 write3CE(0x7,0x0F); //planes?
928 if (chip_id == CYBERBLADEXPAi1) {
929 /* This fixes snow-effect in 32 bpp */
930 write3X4(CRTHSyncStart,0x84);
933 writeAttr(0x10,0x41); //graphics mode and support 256 color modes
934 writeAttr(0x12,0x0F); //planes
935 writeAttr(0x13,0); //horizontal pel panning
938 for(tmp = 0;tmp < 0x10;tmp++)
940 readb(par->io_virt + CRT + 0x0A); //flip-flop to index
941 t_outb(0x20, 0x3C0); //enable attr
944 case 8: tmp = 0;break; //256 colors
945 case 15: tmp = 0x10;break;
946 case 16: tmp = 0x30;break; //hicolor
948 case 32: tmp = 0xD0;break;
960 set_number_of_lines(info->var.yres);
961 set_lwidth(info->var.xres * bpp/(4*16));
962 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
963 info->fix.line_length = info->var.xres * (bpp >> 3);
964 info->cmap.len = (bpp == 8) ? 256: 16;
969 /* Set one color register */
970 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
971 unsigned blue, unsigned transp,
972 struct fb_info *info)
974 int bpp = info->var.bits_per_pixel;
976 if (regno >= info->cmap.len)
984 t_outb(red>>10,0x3C9);
985 t_outb(green>>10,0x3C9);
986 t_outb(blue>>10,0x3C9);
988 } else 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);
1006 /* Try blanking the screen.For flat panels it does nothing */
1007 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1009 unsigned char PMCont,DPMSCont;
1014 t_outb(0x04,0x83C8); /* Read DPMS Control */
1015 PMCont = t_inb(0x83C6) & 0xFC;
1016 DPMSCont = read3CE(PowerStatus) & 0xFC;
1019 case FB_BLANK_UNBLANK:
1020 /* Screen: On, HSync: On, VSync: On */
1021 case FB_BLANK_NORMAL:
1022 /* Screen: Off, HSync: On, VSync: On */
1026 case FB_BLANK_HSYNC_SUSPEND:
1027 /* Screen: Off, HSync: Off, VSync: On */
1031 case FB_BLANK_VSYNC_SUSPEND:
1032 /* Screen: Off, HSync: On, VSync: Off */
1036 case FB_BLANK_POWERDOWN:
1037 /* Screen: Off, HSync: Off, VSync: Off */
1043 write3CE(PowerStatus,DPMSCont);
1045 t_outb(PMCont,0x83C6);
1049 /* let fbcon do a softblank for us */
1050 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1053 static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id)
1056 unsigned char revision;
1058 err = pci_enable_device(dev);
1062 chip_id = id->device;
1064 if(chip_id == CYBERBLADEi1)
1065 output("*** Please do use cyblafb, Cyberblade/i1 support "
1066 "will soon be removed from tridentfb!\n");
1069 /* If PCI id is 0x9660 then further detect chip type */
1071 if (chip_id == TGUI9660) {
1072 outb(RevisionID,0x3C4);
1073 revision = inb(0x3C5);
1077 case 0x23: chip_id = CYBER9397;break;
1078 case 0x2A: chip_id = CYBER9397DVD;break;
1085 case 0xB3: chip_id = CYBER9385;break;
1086 case 0x40 ... 0x43: chip_id = CYBER9382;break;
1087 case 0x4A: chip_id = CYBER9388;break;
1092 chip3D = is3Dchip(chip_id);
1093 chipcyber = iscyber(chip_id);
1095 if (is_xp(chip_id)) {
1098 if (is_blade(chip_id)) {
1104 /* acceleration is on by default for 3D chips */
1105 defaultaccel = chip3D && !noaccel;
1107 fb_info.par = &default_par;
1109 /* setup MMIO region */
1110 tridentfb_fix.mmio_start = pci_resource_start(dev,1);
1111 tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000;
1113 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1114 debug("request_region failed!\n");
1118 default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1120 if (!default_par.io_virt) {
1121 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1122 debug("ioremap failed\n");
1128 /* setup framebuffer memory */
1129 tridentfb_fix.smem_start = pci_resource_start(dev,0);
1130 tridentfb_fix.smem_len = get_memsize();
1132 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1133 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");
1146 output("%s board found\n", pci_name(dev));
1148 output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n",
1149 tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt);
1151 displaytype = get_displaytype();
1154 nativex = get_nativex();
1156 fb_info.fix = tridentfb_fix;
1157 fb_info.fbops = &tridentfb_ops;
1160 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1161 #ifdef CONFIG_FB_TRIDENT_ACCEL
1162 fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1164 fb_info.pseudo_palette = pseudo_pal;
1166 if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp))
1168 fb_alloc_cmap(&fb_info.cmap,256,0);
1169 if (defaultaccel && acc)
1170 default_var.accel_flags |= FB_ACCELF_TEXT;
1172 default_var.accel_flags &= ~FB_ACCELF_TEXT;
1173 default_var.activate |= FB_ACTIVATE_NOW;
1174 fb_info.var = default_var;
1175 fb_info.device = &dev->dev;
1176 if (register_framebuffer(&fb_info) < 0) {
1177 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1180 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1181 fb_info.node, fb_info.fix.id,default_var.xres,
1182 default_var.yres,default_var.bits_per_pixel);
1186 static void __devexit trident_pci_remove(struct pci_dev * dev)
1188 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1189 unregister_framebuffer(&fb_info);
1190 iounmap(par->io_virt);
1191 iounmap(fb_info.screen_base);
1192 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1193 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1196 /* List of boards that we are trying to support */
1197 static struct pci_device_id trident_devices[] = {
1198 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1199 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1200 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1201 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1202 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1203 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1204 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1205 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1206 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1207 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1208 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1209 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1210 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1211 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1212 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1213 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1214 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1215 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1216 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1217 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1221 MODULE_DEVICE_TABLE(pci,trident_devices);
1223 static struct pci_driver tridentfb_pci_driver = {
1224 .name = "tridentfb",
1225 .id_table = trident_devices,
1226 .probe = trident_pci_probe,
1227 .remove = __devexit_p(trident_pci_remove)
1231 * Parse user specified options (`video=trident:')
1233 * video=trident:800x600,bpp=16,noaccel
1236 static int tridentfb_setup(char *options)
1239 if (!options || !*options)
1241 while((opt = strsep(&options,",")) != NULL ) {
1242 if (!*opt) continue;
1243 if (!strncmp(opt,"noaccel",7))
1245 else if (!strncmp(opt,"fp",2))
1246 displaytype = DISPLAY_FP;
1247 else if (!strncmp(opt,"crt",3))
1248 displaytype = DISPLAY_CRT;
1249 else if (!strncmp(opt,"bpp=",4))
1250 bpp = simple_strtoul(opt+4,NULL,0);
1251 else if (!strncmp(opt,"center",6))
1253 else if (!strncmp(opt,"stretch",7))
1255 else if (!strncmp(opt,"memsize=",8))
1256 memsize = simple_strtoul(opt+8,NULL,0);
1257 else if (!strncmp(opt,"memdiff=",8))
1258 memdiff = simple_strtoul(opt+8,NULL,0);
1259 else if (!strncmp(opt,"nativex=",8))
1260 nativex = simple_strtoul(opt+8,NULL,0);
1268 static int __init tridentfb_init(void)
1271 char *option = NULL;
1273 if (fb_get_options("tridentfb", &option))
1275 tridentfb_setup(option);
1277 output("Trident framebuffer %s initializing\n", VERSION);
1278 return pci_register_driver(&tridentfb_pci_driver);
1281 static void __exit tridentfb_exit(void)
1283 pci_unregister_driver(&tridentfb_pci_driver);
1286 static struct fb_ops tridentfb_ops = {
1287 .owner = THIS_MODULE,
1288 .fb_setcolreg = tridentfb_setcolreg,
1289 .fb_pan_display = tridentfb_pan_display,
1290 .fb_blank = tridentfb_blank,
1291 .fb_check_var = tridentfb_check_var,
1292 .fb_set_par = tridentfb_set_par,
1293 .fb_fillrect = tridentfb_fillrect,
1294 .fb_copyarea= tridentfb_copyarea,
1295 .fb_imageblit = cfb_imageblit,
1296 .fb_cursor = soft_cursor,
1299 module_init(tridentfb_init);
1300 module_exit(tridentfb_exit);
1302 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1303 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1304 MODULE_LICENSE("GPL");