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
11 * by Alan Hourihane the FreeVGA project
12 * Francesco Salvestrini <salvestrini@users.sf.net> XP support,
15 * timing value tweaking so it looks good on every monitor in every mode
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 {
30 int vclk; /* in MHz */
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];
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;
58 /* defaults which are normally overriden by user values */
61 static char *mode_option __devinitdata = "640x480";
76 module_param(mode_option, charp, 0);
77 MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
78 module_param_named(mode, mode_option, charp, 0);
79 MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)");
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);
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)
165 * Blade specific acceleration.
168 #define point(x, y) ((y) << 16 | (x))
180 static void blade_init_accel(int pitch, int bpp)
182 int v1 = (pitch >> 3) << 20;
199 v2 = v1 | (tmp << 29);
200 writemmr(0x21C0, v2);
201 writemmr(0x21C4, v2);
202 writemmr(0x21B8, v2);
203 writemmr(0x21BC, v2);
204 writemmr(0x21D0, v1);
205 writemmr(0x21D4, v1);
206 writemmr(0x21C8, v1);
207 writemmr(0x21CC, v1);
211 static void blade_wait_engine(void)
213 while (readmmr(STA) & 0xFA800000) ;
216 static void blade_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
219 writemmr(ROP, rop ? 0x66 : ROP_S);
220 writemmr(CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
222 writemmr(DR1, point(x, y));
223 writemmr(DR2, point(x + w - 1, y + h - 1));
226 static void blade_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
231 s2 = point(x1 + w - 1, y1 + h - 1);
233 d2 = point(x2 + w - 1, y2 + h - 1);
235 if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
238 writemmr(ROP, ROP_S);
239 writemmr(CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction);
241 writemmr(SR1, direction ? s2 : s1);
242 writemmr(SR2, direction ? s1 : s2);
243 writemmr(DR1, direction ? d2 : d1);
244 writemmr(DR2, direction ? d1 : d2);
247 static struct accel_switch accel_blade = {
255 * BladeXP specific acceleration functions
259 #define masked_point(x, y) ((y & 0xffff)<<16|(x & 0xffff))
261 static void xp_init_accel(int pitch, int bpp)
281 switch (pitch << (bpp >> 3)) {
317 writemmr(0x2154, v1);
318 writemmr(0x2150, v1);
322 static void xp_wait_engine(void)
330 busy = t_inb(STA) & 0x80;
334 if (count == 10000000) {
340 t_outb(0x00, 0x2120);
347 static void xp_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
349 writemmr(0x2127, ROP_P);
351 writemmr(0x2128, 0x4000);
352 writemmr(0x2140, masked_point(h, w));
353 writemmr(0x2138, masked_point(y, x));
354 t_outb(0x01, 0x2124);
355 t_outb(eng_oper, 0x2125);
358 static void xp_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
361 u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
365 if ((x1 < x2) && (y1 == y2)) {
383 writemmr(0x2128, direction);
384 t_outb(ROP_S, 0x2127);
385 writemmr(0x213C, masked_point(y1_tmp, x1_tmp));
386 writemmr(0x2138, masked_point(y2_tmp, x2_tmp));
387 writemmr(0x2140, masked_point(h, w));
388 t_outb(0x01, 0x2124);
391 static struct accel_switch accel_xp = {
399 * Image specific acceleration functions
401 static void image_init_accel(int pitch, int bpp)
419 writemmr(0x2120, 0xF0000000);
420 writemmr(0x2120, 0x40000000 | tmp);
421 writemmr(0x2120, 0x80000000);
422 writemmr(0x2144, 0x00000000);
423 writemmr(0x2148, 0x00000000);
424 writemmr(0x2150, 0x00000000);
425 writemmr(0x2154, 0x00000000);
426 writemmr(0x2120, 0x60000000 | (pitch << 16) | pitch);
427 writemmr(0x216C, 0x00000000);
428 writemmr(0x2170, 0x00000000);
429 writemmr(0x217C, 0x00000000);
430 writemmr(0x2120, 0x10000000);
431 writemmr(0x2130, (2047 << 16) | 2047);
434 static void image_wait_engine(void)
436 while (readmmr(0x2164) & 0xF0000000) ;
439 static void image_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
441 writemmr(0x2120, 0x80000000);
442 writemmr(0x2120, 0x90000000 | ROP_S);
446 writemmr(DR1, point(x, y));
447 writemmr(DR2, point(x + w - 1, y + h - 1));
449 writemmr(0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9);
452 static void image_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
457 s2 = point(x1 + w - 1, y1 + h - 1);
459 d2 = point(x2 + w - 1, y2 + h - 1);
461 if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
464 writemmr(0x2120, 0x80000000);
465 writemmr(0x2120, 0x90000000 | ROP_S);
467 writemmr(SR1, direction ? s2 : s1);
468 writemmr(SR2, direction ? s1 : s2);
469 writemmr(DR1, direction ? d2 : d1);
470 writemmr(DR2, direction ? d1 : d2);
471 writemmr(0x2124, 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction);
474 static struct accel_switch accel_image = {
482 * Accel functions called by the upper layers
484 #ifdef CONFIG_FB_TRIDENT_ACCEL
485 static void tridentfb_fillrect(struct fb_info *info,
486 const struct fb_fillrect *fr)
488 int bpp = info->var.bits_per_pixel;
499 col = ((u32 *)(info->pseudo_palette))[fr->color];
502 col = ((u32 *)(info->pseudo_palette))[fr->color];
506 acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop);
509 static void tridentfb_copyarea(struct fb_info *info,
510 const struct fb_copyarea *ca)
512 acc->copy_rect(ca->sx, ca->sy, ca->dx, ca->dy, ca->width, ca->height);
515 #else /* !CONFIG_FB_TRIDENT_ACCEL */
516 #define tridentfb_fillrect cfb_fillrect
517 #define tridentfb_copyarea cfb_copyarea
518 #endif /* CONFIG_FB_TRIDENT_ACCEL */
522 * Hardware access functions
525 static inline unsigned char read3X4(int reg)
527 struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par;
528 writeb(reg, par->io_virt + CRT + 4);
529 return readb(par->io_virt + CRT + 5);
532 static inline void write3X4(int reg, unsigned char val)
534 struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par;
535 writeb(reg, par->io_virt + CRT + 4);
536 writeb(val, par->io_virt + CRT + 5);
539 static inline unsigned char read3C4(int reg)
545 static inline void write3C4(int reg, unsigned char val)
551 static inline unsigned char read3CE(int reg)
557 static inline void writeAttr(int reg, unsigned char val)
559 readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); /* flip-flop to index */
564 static inline void write3CE(int reg, unsigned char val)
570 static void enable_mmio(void)
576 /* Unprotect registers */
577 outb(NewMode1, 0x3C4);
582 outb(inb(0x3D5) | 0x01, 0x3D5);
585 static void disable_mmio(void)
591 /* Unprotect registers */
592 t_outb(NewMode1, 0x3C4);
596 t_outb(PCIReg, 0x3D4);
597 t_outb(t_inb(0x3D5) & ~0x01, 0x3D5);
600 #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
602 /* Return flat panel's maximum x resolution */
603 static int __devinit get_nativex(void)
610 tmp = (read3CE(VertStretch) >> 4) & 3;
631 output("%dx%d flat panel found\n", x, y);
636 static void set_lwidth(int width)
638 write3X4(Offset, width & 0xFF);
640 (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >> 4));
643 /* For resolutions smaller than FP resolution stretch */
644 static void screen_stretch(void)
646 if (chip_id != CYBERBLADEXPAi1)
647 write3CE(BiosReg, 0);
649 write3CE(BiosReg, 8);
650 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 1);
651 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 1);
654 /* For resolutions smaller than FP resolution center */
655 static void screen_center(void)
657 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 0x80);
658 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 0x80);
661 /* Address of first shown pixel in display memory */
662 static void set_screen_start(int base)
664 write3X4(StartAddrLow, base & 0xFF);
665 write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
666 write3X4(CRTCModuleTest,
667 (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
669 (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
672 /* Use 20.12 fixed-point for NTSC value and frequency calculation */
673 #define calc_freq(n, m, k) ( ((unsigned long)0xE517 * (n + 8) / ((m + 2) * (1 << k))) >> 12 )
675 /* Set dotclock frequency */
676 static void set_vclk(int freq)
680 unsigned char lo = 0, hi = 0;
683 for (k = 2; k >= 0; k--)
684 for (m = 0; m < 63; m++)
685 for (n = 0; n < 128; n++) {
686 fi = calc_freq(n, m, k);
687 if ((di = abs(fi - freq)) < d) {
695 write3C4(ClockHigh, hi);
696 write3C4(ClockLow, lo);
701 debug("VCLK = %X %X\n", hi, lo);
704 /* Set number of lines for flat panels*/
705 static void set_number_of_lines(int lines)
707 int tmp = read3CE(CyberEnhance) & 0x8F;
710 else if (lines > 768)
712 else if (lines > 600)
714 else if (lines > 480)
716 write3CE(CyberEnhance, tmp);
720 * If we see that FP is active we assume we have one.
721 * Otherwise we have a CRT display.User can override.
723 static unsigned int __devinit get_displaytype(void)
727 if (crt || !chipcyber)
729 return (read3CE(FPConfig) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
732 /* Try detecting the video memory size */
733 static unsigned int __devinit get_memsize(void)
735 unsigned char tmp, tmp2;
738 /* If memory size provided by user */
747 tmp = read3X4(SPR) & 0x0F;
763 k = 10 * Mb; /* XP */
769 k = 12 * Mb; /* XP */
772 k = 14 * Mb; /* XP */
775 k = 16 * Mb; /* XP */
779 tmp2 = read3C4(0xC1);
809 output("framebuffer size = %d Kb\n", k / Kb);
813 /* See if we can handle the video mode described in var */
814 static int tridentfb_check_var(struct fb_var_screeninfo *var,
815 struct fb_info *info)
817 int bpp = var->bits_per_pixel;
820 /* check color depth */
822 bpp = var->bits_per_pixel = 32;
823 /* check whether resolution fits on panel and in memory */
824 if (flatpanel && nativex && var->xres > nativex)
826 if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len)
832 var->green.offset = 0;
833 var->blue.offset = 0;
835 var->green.length = 6;
836 var->blue.length = 6;
839 var->red.offset = 11;
840 var->green.offset = 5;
841 var->blue.offset = 0;
843 var->green.length = 6;
844 var->blue.length = 5;
847 var->red.offset = 16;
848 var->green.offset = 8;
849 var->blue.offset = 0;
851 var->green.length = 8;
852 var->blue.length = 8;
863 /* Pan the display */
864 static int tridentfb_pan_display(struct fb_var_screeninfo *var,
865 struct fb_info *info)
870 offset = (var->xoffset + (var->yoffset * var->xres))
871 * var->bits_per_pixel / 32;
872 info->var.xoffset = var->xoffset;
873 info->var.yoffset = var->yoffset;
874 set_screen_start(offset);
879 #define shadowmode_on() write3CE(CyberControl, read3CE(CyberControl) | 0x81)
880 #define shadowmode_off() write3CE(CyberControl, read3CE(CyberControl) & 0x7E)
882 /* Set the hardware to the requested video mode */
883 static int tridentfb_set_par(struct fb_info *info)
885 struct tridentfb_par *par = (struct tridentfb_par *)(info->par);
886 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend;
887 u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend;
888 struct fb_var_screeninfo *var = &info->var;
889 int bpp = var->bits_per_pixel;
892 hdispend = var->xres / 8 - 1;
893 hsyncstart = (var->xres + var->right_margin) / 8;
894 hsyncend = var->hsync_len / 8;
896 (var->xres + var->left_margin + var->right_margin +
897 var->hsync_len) / 8 - 10;
898 hblankstart = hdispend + 1;
899 hblankend = htotal + 5;
901 vdispend = var->yres - 1;
902 vsyncstart = var->yres + var->lower_margin;
903 vsyncend = var->vsync_len;
904 vtotal = var->upper_margin + vsyncstart + vsyncend - 2;
905 vblankstart = var->yres;
906 vblankend = vtotal + 2;
910 write3CE(CyberControl, 8);
912 if (flatpanel && var->xres < nativex) {
914 * on flat panels with native size larger
915 * than requested resolution decide whether
916 * we stretch or center
929 write3CE(CyberControl, 8);
932 /* vertical timing values */
933 write3X4(CRTVTotal, vtotal & 0xFF);
934 write3X4(CRTVDispEnd, vdispend & 0xFF);
935 write3X4(CRTVSyncStart, vsyncstart & 0xFF);
936 write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
937 write3X4(CRTVBlankStart, vblankstart & 0xFF);
938 write3X4(CRTVBlankEnd, 0 /* p->vblankend & 0xFF */ );
940 /* horizontal timing values */
941 write3X4(CRTHTotal, htotal & 0xFF);
942 write3X4(CRTHDispEnd, hdispend & 0xFF);
943 write3X4(CRTHSyncStart, hsyncstart & 0xFF);
944 write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
945 write3X4(CRTHBlankStart, hblankstart & 0xFF);
946 write3X4(CRTHBlankEnd, 0 /* (p->hblankend & 0x1F) */ );
948 /* higher bits of vertical timing values */
950 if (vtotal & 0x100) tmp |= 0x01;
951 if (vdispend & 0x100) tmp |= 0x02;
952 if (vsyncstart & 0x100) tmp |= 0x04;
953 if (vblankstart & 0x100) tmp |= 0x08;
955 if (vtotal & 0x200) tmp |= 0x20;
956 if (vdispend & 0x200) tmp |= 0x40;
957 if (vsyncstart & 0x200) tmp |= 0x80;
958 write3X4(CRTOverflow, tmp);
960 tmp = read3X4(CRTHiOrd) | 0x08; /* line compare bit 10 */
961 if (vtotal & 0x400) tmp |= 0x80;
962 if (vblankstart & 0x400) tmp |= 0x40;
963 if (vsyncstart & 0x400) tmp |= 0x20;
964 if (vdispend & 0x400) tmp |= 0x10;
965 write3X4(CRTHiOrd, tmp);
968 if (htotal & 0x800) tmp |= 0x800 >> 11;
969 if (hblankstart & 0x800) tmp |= 0x800 >> 7;
970 write3X4(HorizOverflow, tmp);
973 if (vblankstart & 0x200) tmp |= 0x20;
974 //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */
975 write3X4(CRTMaxScanLine, tmp);
977 write3X4(CRTLineCompare, 0xFF);
978 write3X4(CRTPRowScan, 0);
979 write3X4(CRTModeControl, 0xC3);
981 write3X4(LinearAddReg, 0x20); /* enable linear addressing */
983 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80;
984 write3X4(CRTCModuleTest, tmp); /* enable access extended memory */
986 write3X4(GraphEngReg, 0x80); /* enable GE for text acceleration */
988 #ifdef CONFIG_FB_TRIDENT_ACCEL
989 acc->init_accel(info->var.xres, bpp);
1007 write3X4(PixelBusReg, tmp);
1012 write3X4(DRAMControl, tmp); /* both IO, linear enable */
1014 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
1015 write3X4(Performance, 0x92);
1016 write3X4(PCIReg, 0x07); /* MMIO & PCI read and write burst enable */
1018 /* convert from picoseconds to MHz */
1019 par->vclk = 1000000 / info->var.pixclock;
1022 set_vclk(par->vclk);
1025 write3C4(1, 1); /* set char clock 8 dots wide */
1026 write3C4(2, 0x0F); /* enable 4 maps because needed in chain4 mode */
1028 write3C4(4, 0x0E); /* memory mode enable bitmaps ?? */
1030 write3CE(MiscExtFunc, (bpp == 32) ? 0x1A : 0x12); /* divide clock by 2 if 32bpp */
1031 /* chain4 mode display and CPU path */
1032 write3CE(0x5, 0x40); /* no CGA compat, allow 256 col */
1033 write3CE(0x6, 0x05); /* graphics mode */
1034 write3CE(0x7, 0x0F); /* planes? */
1036 if (chip_id == CYBERBLADEXPAi1) {
1037 /* This fixes snow-effect in 32 bpp */
1038 write3X4(CRTHSyncStart, 0x84);
1041 writeAttr(0x10, 0x41); /* graphics mode and support 256 color modes */
1042 writeAttr(0x12, 0x0F); /* planes */
1043 writeAttr(0x13, 0); /* horizontal pel panning */
1046 for (tmp = 0; tmp < 0x10; tmp++)
1047 writeAttr(tmp, tmp);
1048 readb(par->io_virt + CRT + 0x0A); /* flip-flop to index */
1049 t_outb(0x20, 0x3C0); /* enable attr */
1076 set_number_of_lines(info->var.yres);
1077 set_lwidth(info->var.xres * bpp / (4 * 16));
1078 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1079 info->fix.line_length = info->var.xres * (bpp >> 3);
1080 info->cmap.len = (bpp == 8) ? 256 : 16;
1085 /* Set one color register */
1086 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1087 unsigned blue, unsigned transp,
1088 struct fb_info *info)
1090 int bpp = info->var.bits_per_pixel;
1092 if (regno >= info->cmap.len)
1096 t_outb(0xFF, 0x3C6);
1097 t_outb(regno, 0x3C8);
1099 t_outb(red >> 10, 0x3C9);
1100 t_outb(green >> 10, 0x3C9);
1101 t_outb(blue >> 10, 0x3C9);
1103 } else if (regno < 16) {
1104 if (bpp == 16) { /* RGB 565 */
1107 col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
1108 ((blue & 0xF800) >> 11);
1110 ((u32 *)(info->pseudo_palette))[regno] = col;
1111 } else if (bpp == 32) /* ARGB 8888 */
1112 ((u32*)info->pseudo_palette)[regno] =
1113 ((transp & 0xFF00) << 16) |
1114 ((red & 0xFF00) << 8) |
1115 ((green & 0xFF00)) |
1116 ((blue & 0xFF00) >> 8);
1119 /* debug("exit\n"); */
1123 /* Try blanking the screen.For flat panels it does nothing */
1124 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1126 unsigned char PMCont, DPMSCont;
1131 t_outb(0x04, 0x83C8); /* Read DPMS Control */
1132 PMCont = t_inb(0x83C6) & 0xFC;
1133 DPMSCont = read3CE(PowerStatus) & 0xFC;
1134 switch (blank_mode) {
1135 case FB_BLANK_UNBLANK:
1136 /* Screen: On, HSync: On, VSync: On */
1137 case FB_BLANK_NORMAL:
1138 /* Screen: Off, HSync: On, VSync: On */
1142 case FB_BLANK_HSYNC_SUSPEND:
1143 /* Screen: Off, HSync: Off, VSync: On */
1147 case FB_BLANK_VSYNC_SUSPEND:
1148 /* Screen: Off, HSync: On, VSync: Off */
1152 case FB_BLANK_POWERDOWN:
1153 /* Screen: Off, HSync: Off, VSync: Off */
1159 write3CE(PowerStatus, DPMSCont);
1161 t_outb(PMCont, 0x83C6);
1165 /* let fbcon do a softblank for us */
1166 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1169 static struct fb_ops tridentfb_ops = {
1170 .owner = THIS_MODULE,
1171 .fb_setcolreg = tridentfb_setcolreg,
1172 .fb_pan_display = tridentfb_pan_display,
1173 .fb_blank = tridentfb_blank,
1174 .fb_check_var = tridentfb_check_var,
1175 .fb_set_par = tridentfb_set_par,
1176 .fb_fillrect = tridentfb_fillrect,
1177 .fb_copyarea = tridentfb_copyarea,
1178 .fb_imageblit = cfb_imageblit,
1181 static int __devinit trident_pci_probe(struct pci_dev * dev,
1182 const struct pci_device_id * id)
1185 unsigned char revision;
1187 err = pci_enable_device(dev);
1191 chip_id = id->device;
1193 if (chip_id == CYBERBLADEi1)
1194 output("*** Please do use cyblafb, Cyberblade/i1 support "
1195 "will soon be removed from tridentfb!\n");
1198 /* If PCI id is 0x9660 then further detect chip type */
1200 if (chip_id == TGUI9660) {
1201 outb(RevisionID, 0x3C4);
1202 revision = inb(0x3C5);
1207 chip_id = CYBER9397;
1210 chip_id = CYBER9397DVD;
1219 chip_id = CYBER9385;
1222 chip_id = CYBER9382;
1225 chip_id = CYBER9388;
1232 chip3D = is3Dchip(chip_id);
1233 chipcyber = iscyber(chip_id);
1235 if (is_xp(chip_id)) {
1237 } else if (is_blade(chip_id)) {
1243 /* acceleration is on by default for 3D chips */
1244 defaultaccel = chip3D && !noaccel;
1246 fb_info.par = &default_par;
1248 /* setup MMIO region */
1249 tridentfb_fix.mmio_start = pci_resource_start(dev, 1);
1250 tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000;
1252 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1253 debug("request_region failed!\n");
1257 default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1259 if (!default_par.io_virt) {
1260 debug("ioremap failed\n");
1267 /* setup framebuffer memory */
1268 tridentfb_fix.smem_start = pci_resource_start(dev, 0);
1269 tridentfb_fix.smem_len = get_memsize();
1271 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1272 debug("request_mem_region failed!\n");
1278 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1279 tridentfb_fix.smem_len);
1281 if (!fb_info.screen_base) {
1282 debug("ioremap failed\n");
1287 output("%s board found\n", pci_name(dev));
1288 displaytype = get_displaytype();
1291 nativex = get_nativex();
1293 fb_info.fix = tridentfb_fix;
1294 fb_info.fbops = &tridentfb_ops;
1297 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1298 #ifdef CONFIG_FB_TRIDENT_ACCEL
1299 fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1301 fb_info.pseudo_palette = pseudo_pal;
1303 if (!fb_find_mode(&default_var, &fb_info,
1304 mode_option, NULL, 0, NULL, bpp)) {
1308 err = fb_alloc_cmap(&fb_info.cmap, 256, 0);
1312 if (defaultaccel && acc)
1313 default_var.accel_flags |= FB_ACCELF_TEXT;
1315 default_var.accel_flags &= ~FB_ACCELF_TEXT;
1316 default_var.activate |= FB_ACTIVATE_NOW;
1317 fb_info.var = default_var;
1318 fb_info.device = &dev->dev;
1319 if (register_framebuffer(&fb_info) < 0) {
1320 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1321 fb_dealloc_cmap(&fb_info.cmap);
1325 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1326 fb_info.node, fb_info.fix.id, default_var.xres,
1327 default_var.yres, default_var.bits_per_pixel);
1331 if (fb_info.screen_base)
1332 iounmap(fb_info.screen_base);
1333 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1336 if (default_par.io_virt)
1337 iounmap(default_par.io_virt);
1338 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1342 static void __devexit trident_pci_remove(struct pci_dev *dev)
1344 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1345 unregister_framebuffer(&fb_info);
1346 iounmap(par->io_virt);
1347 iounmap(fb_info.screen_base);
1348 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1349 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1352 /* List of boards that we are trying to support */
1353 static struct pci_device_id trident_devices[] = {
1354 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1355 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1356 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1357 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1358 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1359 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1360 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1361 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1362 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1363 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1364 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1365 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1366 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1367 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1368 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1369 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1370 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1371 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1372 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1373 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1377 MODULE_DEVICE_TABLE(pci, trident_devices);
1379 static struct pci_driver tridentfb_pci_driver = {
1380 .name = "tridentfb",
1381 .id_table = trident_devices,
1382 .probe = trident_pci_probe,
1383 .remove = __devexit_p(trident_pci_remove)
1387 * Parse user specified options (`video=trident:')
1389 * video=trident:800x600,bpp=16,noaccel
1392 static int __init tridentfb_setup(char *options)
1395 if (!options || !*options)
1397 while ((opt = strsep(&options, ",")) != NULL) {
1400 if (!strncmp(opt, "noaccel", 7))
1402 else if (!strncmp(opt, "fp", 2))
1403 displaytype = DISPLAY_FP;
1404 else if (!strncmp(opt, "crt", 3))
1405 displaytype = DISPLAY_CRT;
1406 else if (!strncmp(opt, "bpp=", 4))
1407 bpp = simple_strtoul(opt + 4, NULL, 0);
1408 else if (!strncmp(opt, "center", 6))
1410 else if (!strncmp(opt, "stretch", 7))
1412 else if (!strncmp(opt, "memsize=", 8))
1413 memsize = simple_strtoul(opt + 8, NULL, 0);
1414 else if (!strncmp(opt, "memdiff=", 8))
1415 memdiff = simple_strtoul(opt + 8, NULL, 0);
1416 else if (!strncmp(opt, "nativex=", 8))
1417 nativex = simple_strtoul(opt + 8, NULL, 0);
1425 static int __init tridentfb_init(void)
1428 char *option = NULL;
1430 if (fb_get_options("tridentfb", &option))
1432 tridentfb_setup(option);
1434 output("Trident framebuffer %s initializing\n", VERSION);
1435 return pci_register_driver(&tridentfb_pci_driver);
1438 static void __exit tridentfb_exit(void)
1440 pci_unregister_driver(&tridentfb_pci_driver);
1443 module_init(tridentfb_init);
1444 module_exit(tridentfb_exit);
1446 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1447 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1448 MODULE_LICENSE("GPL");