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 = "640x480";
76 module_param(mode, charp, 0);
77 module_param(bpp, int, 0);
78 module_param(center, int, 0);
79 module_param(stretch, int, 0);
80 module_param(noaccel, int, 0);
81 module_param(memsize, int, 0);
82 module_param(memdiff, int, 0);
83 module_param(nativex, int, 0);
84 module_param(fp, int, 0);
85 module_param(crt, int, 0);
90 static int is3Dchip(int id)
92 return ((id == BLADE3D) || (id == CYBERBLADEE4) ||
93 (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) ||
94 (id == CYBER9397) || (id == CYBER9397DVD) ||
95 (id == CYBER9520) || (id == CYBER9525DVD) ||
96 (id == IMAGE975) || (id == IMAGE985) ||
97 (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) ||
98 (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) ||
99 (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) ||
100 (id == CYBERBLADEXPAi1));
103 static int iscyber(int id)
119 case CYBERBLADEXPAi1:
127 case CYBERBLADEi7: /* VIA MPV4 integrated version */
130 /* case CYBERBLDAEXPm8: Strange */
131 /* case CYBERBLDAEXPm16: Strange */
136 #define CRT 0x3D0 /* CRTC registers offset for color display */
139 #define TRIDENT_MMIO 1
143 #define t_outb(val, reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg)
144 #define t_inb(reg) readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg)
146 #define t_outb(val, reg) outb(val, reg)
147 #define t_inb(reg) inb(reg)
151 static struct accel_switch {
152 void (*init_accel) (int, int);
153 void (*wait_engine) (void);
154 void (*fill_rect) (u32, u32, u32, u32, u32, u32);
155 void (*copy_rect) (u32, u32, u32, u32, u32, u32);
158 #define writemmr(r, v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r)
159 #define readmmr(r) readl(((struct tridentfb_par *)fb_info.par)->io_virt + r)
162 * Blade specific acceleration.
165 #define point(x, y) ((y) << 16 | (x))
177 static void blade_init_accel(int pitch, int bpp)
179 int v1 = (pitch >> 3) << 20;
196 v2 = v1 | (tmp << 29);
197 writemmr(0x21C0, v2);
198 writemmr(0x21C4, v2);
199 writemmr(0x21B8, v2);
200 writemmr(0x21BC, v2);
201 writemmr(0x21D0, v1);
202 writemmr(0x21D4, v1);
203 writemmr(0x21C8, v1);
204 writemmr(0x21CC, v1);
208 static void blade_wait_engine(void)
210 while (readmmr(STA) & 0xFA800000) ;
213 static void blade_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
216 writemmr(ROP, rop ? 0x66 : ROP_S);
217 writemmr(CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
219 writemmr(DR1, point(x, y));
220 writemmr(DR2, point(x + w - 1, y + h - 1));
223 static void blade_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
228 s2 = point(x1 + w - 1, y1 + h - 1);
230 d2 = point(x2 + w - 1, y2 + h - 1);
232 if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
235 writemmr(ROP, ROP_S);
236 writemmr(CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction);
238 writemmr(SR1, direction ? s2 : s1);
239 writemmr(SR2, direction ? s1 : s2);
240 writemmr(DR1, direction ? d2 : d1);
241 writemmr(DR2, direction ? d1 : d2);
244 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)
278 switch (pitch << (bpp >> 3)) {
314 writemmr(0x2154, v1);
315 writemmr(0x2150, v1);
319 static void xp_wait_engine(void)
327 busy = t_inb(STA) & 0x80;
331 if (count == 10000000) {
337 t_outb(0x00, 0x2120);
344 static void xp_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
346 writemmr(0x2127, ROP_P);
348 writemmr(0x2128, 0x4000);
349 writemmr(0x2140, masked_point(h, w));
350 writemmr(0x2138, masked_point(y, x));
351 t_outb(0x01, 0x2124);
352 t_outb(eng_oper, 0x2125);
355 static void xp_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
358 u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
362 if ((x1 < x2) && (y1 == y2)) {
380 writemmr(0x2128, direction);
381 t_outb(ROP_S, 0x2127);
382 writemmr(0x213C, masked_point(y1_tmp, x1_tmp));
383 writemmr(0x2138, masked_point(y2_tmp, x2_tmp));
384 writemmr(0x2140, masked_point(h, w));
385 t_outb(0x01, 0x2124);
388 static struct accel_switch accel_xp = {
396 * Image specific acceleration functions
398 static void image_init_accel(int pitch, int bpp)
416 writemmr(0x2120, 0xF0000000);
417 writemmr(0x2120, 0x40000000 | tmp);
418 writemmr(0x2120, 0x80000000);
419 writemmr(0x2144, 0x00000000);
420 writemmr(0x2148, 0x00000000);
421 writemmr(0x2150, 0x00000000);
422 writemmr(0x2154, 0x00000000);
423 writemmr(0x2120, 0x60000000 | (pitch << 16) | pitch);
424 writemmr(0x216C, 0x00000000);
425 writemmr(0x2170, 0x00000000);
426 writemmr(0x217C, 0x00000000);
427 writemmr(0x2120, 0x10000000);
428 writemmr(0x2130, (2047 << 16) | 2047);
431 static void image_wait_engine(void)
433 while (readmmr(0x2164) & 0xF0000000) ;
436 static void image_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
438 writemmr(0x2120, 0x80000000);
439 writemmr(0x2120, 0x90000000 | ROP_S);
443 writemmr(DR1, point(x, y));
444 writemmr(DR2, point(x + w - 1, y + h - 1));
446 writemmr(0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9);
449 static void image_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
454 s2 = point(x1 + w - 1, y1 + h - 1);
456 d2 = point(x2 + w - 1, y2 + h - 1);
458 if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
461 writemmr(0x2120, 0x80000000);
462 writemmr(0x2120, 0x90000000 | ROP_S);
464 writemmr(SR1, direction ? s2 : s1);
465 writemmr(SR2, direction ? s1 : s2);
466 writemmr(DR1, direction ? d2 : d1);
467 writemmr(DR2, direction ? d1 : d2);
468 writemmr(0x2124, 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction);
471 static struct accel_switch accel_image = {
479 * Accel functions called by the upper layers
481 #ifdef CONFIG_FB_TRIDENT_ACCEL
482 static void tridentfb_fillrect(struct fb_info *info,
483 const struct fb_fillrect *fr)
485 int bpp = info->var.bits_per_pixel;
496 col = ((u32 *)(info->pseudo_palette))[fr->color];
499 col = ((u32 *)(info->pseudo_palette))[fr->color];
503 acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop);
506 static void tridentfb_copyarea(struct fb_info *info,
507 const struct fb_copyarea *ca)
509 acc->copy_rect(ca->sx, ca->sy, ca->dx, ca->dy, ca->width, ca->height);
512 #else /* !CONFIG_FB_TRIDENT_ACCEL */
513 #define tridentfb_fillrect cfb_fillrect
514 #define tridentfb_copyarea cfb_copyarea
515 #endif /* CONFIG_FB_TRIDENT_ACCEL */
519 * Hardware access functions
522 static inline unsigned char read3X4(int reg)
524 struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par;
525 writeb(reg, par->io_virt + CRT + 4);
526 return readb(par->io_virt + CRT + 5);
529 static inline void write3X4(int reg, unsigned char val)
531 struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par;
532 writeb(reg, par->io_virt + CRT + 4);
533 writeb(val, par->io_virt + CRT + 5);
536 static inline unsigned char read3C4(int reg)
542 static inline void write3C4(int reg, unsigned char val)
548 static inline unsigned char read3CE(int reg)
554 static inline void writeAttr(int reg, unsigned char val)
556 readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); /* flip-flop to index */
561 static inline void write3CE(int reg, unsigned char val)
567 static inline void enable_mmio(void)
573 /* Unprotect registers */
574 outb(NewMode1, 0x3C4);
579 outb(inb(0x3D5) | 0x01, 0x3D5);
582 #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
584 /* Return flat panel's maximum x resolution */
585 static int __devinit get_nativex(void)
592 tmp = (read3CE(VertStretch) >> 4) & 3;
613 output("%dx%d flat panel found\n", x, y);
618 static void set_lwidth(int width)
620 write3X4(Offset, width & 0xFF);
622 (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >> 4));
625 /* For resolutions smaller than FP resolution stretch */
626 static void screen_stretch(void)
628 if (chip_id != CYBERBLADEXPAi1)
629 write3CE(BiosReg, 0);
631 write3CE(BiosReg, 8);
632 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 1);
633 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 1);
636 /* For resolutions smaller than FP resolution center */
637 static void screen_center(void)
639 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 0x80);
640 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 0x80);
643 /* Address of first shown pixel in display memory */
644 static void set_screen_start(int base)
646 write3X4(StartAddrLow, base & 0xFF);
647 write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
648 write3X4(CRTCModuleTest,
649 (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
651 (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
654 /* Use 20.12 fixed-point for NTSC value and frequency calculation */
655 #define calc_freq(n, m, k) ( ((unsigned long)0xE517 * (n + 8) / ((m + 2) * (1 << k))) >> 12 )
657 /* Set dotclock frequency */
658 static void set_vclk(int freq)
662 unsigned char lo = 0, hi = 0;
665 for (k = 2; k >= 0; k--)
666 for (m = 0; m < 63; m++)
667 for (n = 0; n < 128; n++) {
668 fi = calc_freq(n, m, k);
669 if ((di = abs(fi - freq)) < d) {
677 write3C4(ClockHigh, hi);
678 write3C4(ClockLow, lo);
683 debug("VCLK = %X %X\n", hi, lo);
686 /* Set number of lines for flat panels*/
687 static void set_number_of_lines(int lines)
689 int tmp = read3CE(CyberEnhance) & 0x8F;
692 else if (lines > 768)
694 else if (lines > 600)
696 else if (lines > 480)
698 write3CE(CyberEnhance, tmp);
702 * If we see that FP is active we assume we have one.
703 * Otherwise we have a CRT display.User can override.
705 static unsigned int __devinit get_displaytype(void)
709 if (crt || !chipcyber)
711 return (read3CE(FPConfig) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
714 /* Try detecting the video memory size */
715 static unsigned int __devinit get_memsize(void)
717 unsigned char tmp, tmp2;
720 /* If memory size provided by user */
729 tmp = read3X4(SPR) & 0x0F;
745 k = 10 * Mb; /* XP */
751 k = 12 * Mb; /* XP */
754 k = 14 * Mb; /* XP */
757 k = 16 * Mb; /* XP */
761 tmp2 = read3C4(0xC1);
791 output("framebuffer size = %d Kb\n", k / Kb);
795 /* See if we can handle the video mode described in var */
796 static int tridentfb_check_var(struct fb_var_screeninfo *var,
797 struct fb_info *info)
799 int bpp = var->bits_per_pixel;
802 /* check color depth */
804 bpp = var->bits_per_pixel = 32;
805 /* check whether resolution fits on panel and in memory */
806 if (flatpanel && nativex && var->xres > nativex)
808 if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len)
814 var->green.offset = 0;
815 var->blue.offset = 0;
817 var->green.length = 6;
818 var->blue.length = 6;
821 var->red.offset = 11;
822 var->green.offset = 5;
823 var->blue.offset = 0;
825 var->green.length = 6;
826 var->blue.length = 5;
829 var->red.offset = 16;
830 var->green.offset = 8;
831 var->blue.offset = 0;
833 var->green.length = 8;
834 var->blue.length = 8;
845 /* Pan the display */
846 static int tridentfb_pan_display(struct fb_var_screeninfo *var,
847 struct fb_info *info)
852 offset = (var->xoffset + (var->yoffset * var->xres))
853 * var->bits_per_pixel / 32;
854 info->var.xoffset = var->xoffset;
855 info->var.yoffset = var->yoffset;
856 set_screen_start(offset);
861 #define shadowmode_on() write3CE(CyberControl, read3CE(CyberControl) | 0x81)
862 #define shadowmode_off() write3CE(CyberControl, read3CE(CyberControl) & 0x7E)
864 /* Set the hardware to the requested video mode */
865 static int tridentfb_set_par(struct fb_info *info)
867 struct tridentfb_par *par = (struct tridentfb_par *)(info->par);
868 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend;
869 u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend;
870 struct fb_var_screeninfo *var = &info->var;
871 int bpp = var->bits_per_pixel;
874 hdispend = var->xres / 8 - 1;
875 hsyncstart = (var->xres + var->right_margin) / 8;
876 hsyncend = var->hsync_len / 8;
878 (var->xres + var->left_margin + var->right_margin +
879 var->hsync_len) / 8 - 10;
880 hblankstart = hdispend + 1;
881 hblankend = htotal + 5;
883 vdispend = var->yres - 1;
884 vsyncstart = var->yres + var->lower_margin;
885 vsyncend = var->vsync_len;
886 vtotal = var->upper_margin + vsyncstart + vsyncend - 2;
887 vblankstart = var->yres;
888 vblankend = vtotal + 2;
892 write3CE(CyberControl, 8);
894 if (flatpanel && var->xres < nativex) {
896 * on flat panels with native size larger
897 * than requested resolution decide whether
898 * we stretch or center
911 write3CE(CyberControl, 8);
914 /* vertical timing values */
915 write3X4(CRTVTotal, vtotal & 0xFF);
916 write3X4(CRTVDispEnd, vdispend & 0xFF);
917 write3X4(CRTVSyncStart, vsyncstart & 0xFF);
918 write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
919 write3X4(CRTVBlankStart, vblankstart & 0xFF);
920 write3X4(CRTVBlankEnd, 0 /* p->vblankend & 0xFF */ );
922 /* horizontal timing values */
923 write3X4(CRTHTotal, htotal & 0xFF);
924 write3X4(CRTHDispEnd, hdispend & 0xFF);
925 write3X4(CRTHSyncStart, hsyncstart & 0xFF);
926 write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
927 write3X4(CRTHBlankStart, hblankstart & 0xFF);
928 write3X4(CRTHBlankEnd, 0 /* (p->hblankend & 0x1F) */ );
930 /* higher bits of vertical timing values */
932 if (vtotal & 0x100) tmp |= 0x01;
933 if (vdispend & 0x100) tmp |= 0x02;
934 if (vsyncstart & 0x100) tmp |= 0x04;
935 if (vblankstart & 0x100) tmp |= 0x08;
937 if (vtotal & 0x200) tmp |= 0x20;
938 if (vdispend & 0x200) tmp |= 0x40;
939 if (vsyncstart & 0x200) tmp |= 0x80;
940 write3X4(CRTOverflow, tmp);
942 tmp = read3X4(CRTHiOrd) | 0x08; /* line compare bit 10 */
943 if (vtotal & 0x400) tmp |= 0x80;
944 if (vblankstart & 0x400) tmp |= 0x40;
945 if (vsyncstart & 0x400) tmp |= 0x20;
946 if (vdispend & 0x400) tmp |= 0x10;
947 write3X4(CRTHiOrd, tmp);
950 if (htotal & 0x800) tmp |= 0x800 >> 11;
951 if (hblankstart & 0x800) tmp |= 0x800 >> 7;
952 write3X4(HorizOverflow, tmp);
955 if (vblankstart & 0x200) tmp |= 0x20;
956 //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */
957 write3X4(CRTMaxScanLine, tmp);
959 write3X4(CRTLineCompare, 0xFF);
960 write3X4(CRTPRowScan, 0);
961 write3X4(CRTModeControl, 0xC3);
963 write3X4(LinearAddReg, 0x20); /* enable linear addressing */
965 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80;
966 write3X4(CRTCModuleTest, tmp); /* enable access extended memory */
968 write3X4(GraphEngReg, 0x80); /* enable GE for text acceleration */
970 #ifdef CONFIG_FB_TRIDENT_ACCEL
971 acc->init_accel(info->var.xres, bpp);
989 write3X4(PixelBusReg, tmp);
994 write3X4(DRAMControl, tmp); /* both IO, linear enable */
996 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
997 write3X4(Performance, 0x92);
998 write3X4(PCIReg, 0x07); /* MMIO & PCI read and write burst enable */
1000 /* convert from picoseconds to MHz */
1001 par->vclk = 1000000 / info->var.pixclock;
1004 set_vclk(par->vclk);
1007 write3C4(1, 1); /* set char clock 8 dots wide */
1008 write3C4(2, 0x0F); /* enable 4 maps because needed in chain4 mode */
1010 write3C4(4, 0x0E); /* memory mode enable bitmaps ?? */
1012 write3CE(MiscExtFunc, (bpp == 32) ? 0x1A : 0x12); /* divide clock by 2 if 32bpp */
1013 /* chain4 mode display and CPU path */
1014 write3CE(0x5, 0x40); /* no CGA compat, allow 256 col */
1015 write3CE(0x6, 0x05); /* graphics mode */
1016 write3CE(0x7, 0x0F); /* planes? */
1018 if (chip_id == CYBERBLADEXPAi1) {
1019 /* This fixes snow-effect in 32 bpp */
1020 write3X4(CRTHSyncStart, 0x84);
1023 writeAttr(0x10, 0x41); /* graphics mode and support 256 color modes */
1024 writeAttr(0x12, 0x0F); /* planes */
1025 writeAttr(0x13, 0); /* horizontal pel panning */
1028 for (tmp = 0; tmp < 0x10; tmp++)
1029 writeAttr(tmp, tmp);
1030 readb(par->io_virt + CRT + 0x0A); /* flip-flop to index */
1031 t_outb(0x20, 0x3C0); /* enable attr */
1058 set_number_of_lines(info->var.yres);
1059 set_lwidth(info->var.xres * bpp / (4 * 16));
1060 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1061 info->fix.line_length = info->var.xres * (bpp >> 3);
1062 info->cmap.len = (bpp == 8) ? 256 : 16;
1067 /* Set one color register */
1068 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1069 unsigned blue, unsigned transp,
1070 struct fb_info *info)
1072 int bpp = info->var.bits_per_pixel;
1074 if (regno >= info->cmap.len)
1078 t_outb(0xFF, 0x3C6);
1079 t_outb(regno, 0x3C8);
1081 t_outb(red >> 10, 0x3C9);
1082 t_outb(green >> 10, 0x3C9);
1083 t_outb(blue >> 10, 0x3C9);
1085 } else if (regno < 16) {
1086 if (bpp == 16) { /* RGB 565 */
1089 col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
1090 ((blue & 0xF800) >> 11);
1092 ((u32 *)(info->pseudo_palette))[regno] = col;
1093 } else if (bpp == 32) /* ARGB 8888 */
1094 ((u32*)info->pseudo_palette)[regno] =
1095 ((transp & 0xFF00) << 16) |
1096 ((red & 0xFF00) << 8) |
1097 ((green & 0xFF00)) |
1098 ((blue & 0xFF00) >> 8);
1101 /* debug("exit\n"); */
1105 /* Try blanking the screen.For flat panels it does nothing */
1106 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1108 unsigned char PMCont, DPMSCont;
1113 t_outb(0x04, 0x83C8); /* Read DPMS Control */
1114 PMCont = t_inb(0x83C6) & 0xFC;
1115 DPMSCont = read3CE(PowerStatus) & 0xFC;
1116 switch (blank_mode) {
1117 case FB_BLANK_UNBLANK:
1118 /* Screen: On, HSync: On, VSync: On */
1119 case FB_BLANK_NORMAL:
1120 /* Screen: Off, HSync: On, VSync: On */
1124 case FB_BLANK_HSYNC_SUSPEND:
1125 /* Screen: Off, HSync: Off, VSync: On */
1129 case FB_BLANK_VSYNC_SUSPEND:
1130 /* Screen: Off, HSync: On, VSync: Off */
1134 case FB_BLANK_POWERDOWN:
1135 /* Screen: Off, HSync: Off, VSync: Off */
1141 write3CE(PowerStatus, DPMSCont);
1143 t_outb(PMCont, 0x83C6);
1147 /* let fbcon do a softblank for us */
1148 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1151 static struct fb_ops tridentfb_ops = {
1152 .owner = THIS_MODULE,
1153 .fb_setcolreg = tridentfb_setcolreg,
1154 .fb_pan_display = tridentfb_pan_display,
1155 .fb_blank = tridentfb_blank,
1156 .fb_check_var = tridentfb_check_var,
1157 .fb_set_par = tridentfb_set_par,
1158 .fb_fillrect = tridentfb_fillrect,
1159 .fb_copyarea = tridentfb_copyarea,
1160 .fb_imageblit = cfb_imageblit,
1163 static int __devinit trident_pci_probe(struct pci_dev * dev,
1164 const struct pci_device_id * id)
1167 unsigned char revision;
1169 err = pci_enable_device(dev);
1173 chip_id = id->device;
1175 if (chip_id == CYBERBLADEi1)
1176 output("*** Please do use cyblafb, Cyberblade/i1 support "
1177 "will soon be removed from tridentfb!\n");
1180 /* If PCI id is 0x9660 then further detect chip type */
1182 if (chip_id == TGUI9660) {
1183 outb(RevisionID, 0x3C4);
1184 revision = inb(0x3C5);
1189 chip_id = CYBER9397;
1192 chip_id = CYBER9397DVD;
1201 chip_id = CYBER9385;
1204 chip_id = CYBER9382;
1207 chip_id = CYBER9388;
1214 chip3D = is3Dchip(chip_id);
1215 chipcyber = iscyber(chip_id);
1217 if (is_xp(chip_id)) {
1219 } else if (is_blade(chip_id)) {
1225 /* acceleration is on by default for 3D chips */
1226 defaultaccel = chip3D && !noaccel;
1228 fb_info.par = &default_par;
1230 /* setup MMIO region */
1231 tridentfb_fix.mmio_start = pci_resource_start(dev, 1);
1232 tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000;
1234 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1235 debug("request_region failed!\n");
1239 default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1241 if (!default_par.io_virt) {
1242 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1243 debug("ioremap failed\n");
1249 /* setup framebuffer memory */
1250 tridentfb_fix.smem_start = pci_resource_start(dev, 0);
1251 tridentfb_fix.smem_len = get_memsize();
1253 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1254 debug("request_mem_region failed!\n");
1259 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1260 tridentfb_fix.smem_len);
1262 if (!fb_info.screen_base) {
1263 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1264 debug("ioremap failed\n");
1269 output("%s board found\n", pci_name(dev));
1271 output("Trident board found : mem = %X, io = %X, mem_v = %X, io_v = %X\n",
1272 tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt);
1274 displaytype = get_displaytype();
1277 nativex = get_nativex();
1279 fb_info.fix = tridentfb_fix;
1280 fb_info.fbops = &tridentfb_ops;
1283 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1284 #ifdef CONFIG_FB_TRIDENT_ACCEL
1285 fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1287 fb_info.pseudo_palette = pseudo_pal;
1289 if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) {
1293 fb_alloc_cmap(&fb_info.cmap, 256, 0);
1294 if (defaultaccel && acc)
1295 default_var.accel_flags |= FB_ACCELF_TEXT;
1297 default_var.accel_flags &= ~FB_ACCELF_TEXT;
1298 default_var.activate |= FB_ACTIVATE_NOW;
1299 fb_info.var = default_var;
1300 fb_info.device = &dev->dev;
1301 if (register_framebuffer(&fb_info) < 0) {
1302 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1306 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1307 fb_info.node, fb_info.fix.id, default_var.xres,
1308 default_var.yres, default_var.bits_per_pixel);
1312 if (default_par.io_virt)
1313 iounmap(default_par.io_virt);
1314 if (fb_info.screen_base)
1315 iounmap(fb_info.screen_base);
1319 static void __devexit trident_pci_remove(struct pci_dev *dev)
1321 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1322 unregister_framebuffer(&fb_info);
1323 iounmap(par->io_virt);
1324 iounmap(fb_info.screen_base);
1325 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1326 release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1329 /* List of boards that we are trying to support */
1330 static struct pci_device_id trident_devices[] = {
1331 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1332 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1333 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1334 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1335 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1336 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1337 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1338 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1339 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1340 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1341 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1342 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1343 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1344 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1345 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1346 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1347 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1348 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1349 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1350 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1354 MODULE_DEVICE_TABLE(pci, trident_devices);
1356 static struct pci_driver tridentfb_pci_driver = {
1357 .name = "tridentfb",
1358 .id_table = trident_devices,
1359 .probe = trident_pci_probe,
1360 .remove = __devexit_p(trident_pci_remove)
1364 * Parse user specified options (`video=trident:')
1366 * video=trident:800x600,bpp=16,noaccel
1369 static int tridentfb_setup(char *options)
1372 if (!options || !*options)
1374 while ((opt = strsep(&options, ",")) != NULL) {
1377 if (!strncmp(opt, "noaccel", 7))
1379 else if (!strncmp(opt, "fp", 2))
1380 displaytype = DISPLAY_FP;
1381 else if (!strncmp(opt, "crt", 3))
1382 displaytype = DISPLAY_CRT;
1383 else if (!strncmp(opt, "bpp=", 4))
1384 bpp = simple_strtoul(opt + 4, NULL, 0);
1385 else if (!strncmp(opt, "center", 6))
1387 else if (!strncmp(opt, "stretch", 7))
1389 else if (!strncmp(opt, "memsize=", 8))
1390 memsize = simple_strtoul(opt + 8, NULL, 0);
1391 else if (!strncmp(opt, "memdiff=", 8))
1392 memdiff = simple_strtoul(opt + 8, NULL, 0);
1393 else if (!strncmp(opt, "nativex=", 8))
1394 nativex = simple_strtoul(opt + 8, NULL, 0);
1402 static int __init tridentfb_init(void)
1405 char *option = NULL;
1407 if (fb_get_options("tridentfb", &option))
1409 tridentfb_setup(option);
1411 output("Trident framebuffer %s initializing\n", VERSION);
1412 return pci_register_driver(&tridentfb_pci_driver);
1415 static void __exit tridentfb_exit(void)
1417 pci_unregister_driver(&tridentfb_pci_driver);
1420 module_init(tridentfb_init);
1421 module_exit(tridentfb_exit);
1423 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1424 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1425 MODULE_LICENSE("GPL");