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 void __iomem *io_virt; /* iospace virtual memory address */
33 static unsigned char eng_oper; /* engine operation... */
34 static struct fb_ops tridentfb_ops;
36 static struct tridentfb_par default_par;
38 /* FIXME:kmalloc these 3 instead */
39 static struct fb_info fb_info;
40 static u32 pseudo_pal[16];
42 static struct fb_var_screeninfo default_var;
44 static struct fb_fix_screeninfo tridentfb_fix = {
46 .type = FB_TYPE_PACKED_PIXELS,
48 .visual = FB_VISUAL_PSEUDOCOLOR,
49 .accel = FB_ACCEL_NONE,
54 static int defaultaccel;
55 static int displaytype;
57 /* defaults which are normally overriden by user values */
60 static char *mode_option __devinitdata = "640x480";
75 module_param(mode_option, charp, 0);
76 MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
77 module_param_named(mode, mode_option, charp, 0);
78 MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)");
79 module_param(bpp, int, 0);
80 module_param(center, int, 0);
81 module_param(stretch, int, 0);
82 module_param(noaccel, int, 0);
83 module_param(memsize, int, 0);
84 module_param(memdiff, int, 0);
85 module_param(nativex, int, 0);
86 module_param(fp, int, 0);
87 module_param(crt, int, 0);
92 static int is3Dchip(int id)
94 return ((id == BLADE3D) || (id == CYBERBLADEE4) ||
95 (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) ||
96 (id == CYBER9397) || (id == CYBER9397DVD) ||
97 (id == CYBER9520) || (id == CYBER9525DVD) ||
98 (id == IMAGE975) || (id == IMAGE985) ||
99 (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) ||
100 (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) ||
101 (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) ||
102 (id == CYBERBLADEXPAi1));
105 static int iscyber(int id)
121 case CYBERBLADEXPAi1:
129 case CYBERBLADEi7: /* VIA MPV4 integrated version */
132 /* case CYBERBLDAEXPm8: Strange */
133 /* case CYBERBLDAEXPm16: Strange */
138 #define CRT 0x3D0 /* CRTC registers offset for color display */
141 #define TRIDENT_MMIO 1
145 #define t_outb(val, reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg)
146 #define t_inb(reg) readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg)
148 #define t_outb(val, reg) outb(val, reg)
149 #define t_inb(reg) inb(reg)
153 static struct accel_switch {
154 void (*init_accel) (int, int);
155 void (*wait_engine) (void);
156 void (*fill_rect) (u32, u32, u32, u32, u32, u32);
157 void (*copy_rect) (u32, u32, u32, u32, u32, u32);
160 #define writemmr(r, v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r)
161 #define readmmr(r) readl(((struct tridentfb_par *)fb_info.par)->io_virt + r)
164 * Blade specific acceleration.
167 #define point(x, y) ((y) << 16 | (x))
179 static void blade_init_accel(int pitch, int bpp)
181 int v1 = (pitch >> 3) << 20;
198 v2 = v1 | (tmp << 29);
199 writemmr(0x21C0, v2);
200 writemmr(0x21C4, v2);
201 writemmr(0x21B8, v2);
202 writemmr(0x21BC, v2);
203 writemmr(0x21D0, v1);
204 writemmr(0x21D4, v1);
205 writemmr(0x21C8, v1);
206 writemmr(0x21CC, v1);
210 static void blade_wait_engine(void)
212 while (readmmr(STA) & 0xFA800000) ;
215 static void blade_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
218 writemmr(ROP, rop ? 0x66 : ROP_S);
219 writemmr(CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
221 writemmr(DR1, point(x, y));
222 writemmr(DR2, point(x + w - 1, y + h - 1));
225 static void blade_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
230 s2 = point(x1 + w - 1, y1 + h - 1);
232 d2 = point(x2 + w - 1, y2 + h - 1);
234 if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
237 writemmr(ROP, ROP_S);
238 writemmr(CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction);
240 writemmr(SR1, direction ? s2 : s1);
241 writemmr(SR2, direction ? s1 : s2);
242 writemmr(DR1, direction ? d2 : d1);
243 writemmr(DR2, direction ? d1 : d2);
246 static struct accel_switch accel_blade = {
254 * BladeXP specific acceleration functions
258 #define masked_point(x, y) ((y & 0xffff)<<16|(x & 0xffff))
260 static void xp_init_accel(int pitch, int bpp)
280 switch (pitch << (bpp >> 3)) {
316 writemmr(0x2154, v1);
317 writemmr(0x2150, v1);
321 static void xp_wait_engine(void)
329 busy = t_inb(STA) & 0x80;
333 if (count == 10000000) {
339 t_outb(0x00, 0x2120);
346 static void xp_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
348 writemmr(0x2127, ROP_P);
350 writemmr(0x2128, 0x4000);
351 writemmr(0x2140, masked_point(h, w));
352 writemmr(0x2138, masked_point(y, x));
353 t_outb(0x01, 0x2124);
354 t_outb(eng_oper, 0x2125);
357 static void xp_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
360 u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
364 if ((x1 < x2) && (y1 == y2)) {
382 writemmr(0x2128, direction);
383 t_outb(ROP_S, 0x2127);
384 writemmr(0x213C, masked_point(y1_tmp, x1_tmp));
385 writemmr(0x2138, masked_point(y2_tmp, x2_tmp));
386 writemmr(0x2140, masked_point(h, w));
387 t_outb(0x01, 0x2124);
390 static struct accel_switch accel_xp = {
398 * Image specific acceleration functions
400 static void image_init_accel(int pitch, int bpp)
418 writemmr(0x2120, 0xF0000000);
419 writemmr(0x2120, 0x40000000 | tmp);
420 writemmr(0x2120, 0x80000000);
421 writemmr(0x2144, 0x00000000);
422 writemmr(0x2148, 0x00000000);
423 writemmr(0x2150, 0x00000000);
424 writemmr(0x2154, 0x00000000);
425 writemmr(0x2120, 0x60000000 | (pitch << 16) | pitch);
426 writemmr(0x216C, 0x00000000);
427 writemmr(0x2170, 0x00000000);
428 writemmr(0x217C, 0x00000000);
429 writemmr(0x2120, 0x10000000);
430 writemmr(0x2130, (2047 << 16) | 2047);
433 static void image_wait_engine(void)
435 while (readmmr(0x2164) & 0xF0000000) ;
438 static void image_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
440 writemmr(0x2120, 0x80000000);
441 writemmr(0x2120, 0x90000000 | ROP_S);
445 writemmr(DR1, point(x, y));
446 writemmr(DR2, point(x + w - 1, y + h - 1));
448 writemmr(0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9);
451 static void image_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
456 s2 = point(x1 + w - 1, y1 + h - 1);
458 d2 = point(x2 + w - 1, y2 + h - 1);
460 if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
463 writemmr(0x2120, 0x80000000);
464 writemmr(0x2120, 0x90000000 | ROP_S);
466 writemmr(SR1, direction ? s2 : s1);
467 writemmr(SR2, direction ? s1 : s2);
468 writemmr(DR1, direction ? d2 : d1);
469 writemmr(DR2, direction ? d1 : d2);
470 writemmr(0x2124, 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction);
473 static struct accel_switch accel_image = {
481 * Accel functions called by the upper layers
483 #ifdef CONFIG_FB_TRIDENT_ACCEL
484 static void tridentfb_fillrect(struct fb_info *info,
485 const struct fb_fillrect *fr)
487 int bpp = info->var.bits_per_pixel;
498 col = ((u32 *)(info->pseudo_palette))[fr->color];
501 col = ((u32 *)(info->pseudo_palette))[fr->color];
505 acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop);
508 static void tridentfb_copyarea(struct fb_info *info,
509 const struct fb_copyarea *ca)
511 acc->copy_rect(ca->sx, ca->sy, ca->dx, ca->dy, ca->width, ca->height);
514 #else /* !CONFIG_FB_TRIDENT_ACCEL */
515 #define tridentfb_fillrect cfb_fillrect
516 #define tridentfb_copyarea cfb_copyarea
517 #endif /* CONFIG_FB_TRIDENT_ACCEL */
521 * Hardware access functions
524 static inline unsigned char read3X4(int reg)
526 struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par;
527 writeb(reg, par->io_virt + CRT + 4);
528 return readb(par->io_virt + CRT + 5);
531 static inline void write3X4(int reg, unsigned char val)
533 struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par;
534 writeb(reg, par->io_virt + CRT + 4);
535 writeb(val, par->io_virt + CRT + 5);
538 static inline unsigned char read3C4(int reg)
544 static inline void write3C4(int reg, unsigned char val)
550 static inline unsigned char read3CE(int reg)
556 static inline void writeAttr(int reg, unsigned char val)
558 readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); /* flip-flop to index */
563 static inline void write3CE(int reg, unsigned char val)
569 static void enable_mmio(void)
575 /* Unprotect registers */
576 outb(NewMode1, 0x3C4);
581 outb(inb(0x3D5) | 0x01, 0x3D5);
584 static void disable_mmio(void)
590 /* Unprotect registers */
591 t_outb(NewMode1, 0x3C4);
595 t_outb(PCIReg, 0x3D4);
596 t_outb(t_inb(0x3D5) & ~0x01, 0x3D5);
599 #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
601 /* Return flat panel's maximum x resolution */
602 static int __devinit get_nativex(void)
609 tmp = (read3CE(VertStretch) >> 4) & 3;
630 output("%dx%d flat panel found\n", x, y);
635 static void set_lwidth(int width)
637 write3X4(Offset, width & 0xFF);
639 (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >> 4));
642 /* For resolutions smaller than FP resolution stretch */
643 static void screen_stretch(void)
645 if (chip_id != CYBERBLADEXPAi1)
646 write3CE(BiosReg, 0);
648 write3CE(BiosReg, 8);
649 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 1);
650 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 1);
653 /* For resolutions smaller than FP resolution center */
654 static void screen_center(void)
656 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 0x80);
657 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 0x80);
660 /* Address of first shown pixel in display memory */
661 static void set_screen_start(int base)
663 write3X4(StartAddrLow, base & 0xFF);
664 write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
665 write3X4(CRTCModuleTest,
666 (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
668 (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
671 /* Set dotclock frequency */
672 static void set_vclk(unsigned long freq)
675 unsigned long f, fi, d, di;
676 unsigned char lo = 0, hi = 0;
679 for (k = 2; k >= 0; k--)
680 for (m = 0; m < 63; m++)
681 for (n = 0; n < 128; n++) {
682 fi = ((14318l * (n + 8)) / (m + 2)) >> k;
683 if ((di = abs(fi - freq)) < d) {
693 write3C4(ClockHigh, hi);
694 write3C4(ClockLow, lo);
699 debug("VCLK = %X %X\n", hi, lo);
702 /* Set number of lines for flat panels*/
703 static void set_number_of_lines(int lines)
705 int tmp = read3CE(CyberEnhance) & 0x8F;
708 else if (lines > 768)
710 else if (lines > 600)
712 else if (lines > 480)
714 write3CE(CyberEnhance, tmp);
718 * If we see that FP is active we assume we have one.
719 * Otherwise we have a CRT display.User can override.
721 static unsigned int __devinit get_displaytype(void)
725 if (crt || !chipcyber)
727 return (read3CE(FPConfig) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
730 /* Try detecting the video memory size */
731 static unsigned int __devinit get_memsize(void)
733 unsigned char tmp, tmp2;
736 /* If memory size provided by user */
745 tmp = read3X4(SPR) & 0x0F;
761 k = 10 * Mb; /* XP */
767 k = 12 * Mb; /* XP */
770 k = 14 * Mb; /* XP */
773 k = 16 * Mb; /* XP */
777 tmp2 = read3C4(0xC1);
807 output("framebuffer size = %d Kb\n", k / Kb);
811 /* See if we can handle the video mode described in var */
812 static int tridentfb_check_var(struct fb_var_screeninfo *var,
813 struct fb_info *info)
815 int bpp = var->bits_per_pixel;
818 /* check color depth */
820 bpp = var->bits_per_pixel = 32;
821 /* check whether resolution fits on panel and in memory */
822 if (flatpanel && nativex && var->xres > nativex)
824 if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len)
830 var->green.offset = 0;
831 var->blue.offset = 0;
833 var->green.length = 6;
834 var->blue.length = 6;
837 var->red.offset = 11;
838 var->green.offset = 5;
839 var->blue.offset = 0;
841 var->green.length = 6;
842 var->blue.length = 5;
845 var->red.offset = 16;
846 var->green.offset = 8;
847 var->blue.offset = 0;
849 var->green.length = 8;
850 var->blue.length = 8;
861 /* Pan the display */
862 static int tridentfb_pan_display(struct fb_var_screeninfo *var,
863 struct fb_info *info)
868 offset = (var->xoffset + (var->yoffset * var->xres))
869 * var->bits_per_pixel / 32;
870 info->var.xoffset = var->xoffset;
871 info->var.yoffset = var->yoffset;
872 set_screen_start(offset);
877 #define shadowmode_on() write3CE(CyberControl, read3CE(CyberControl) | 0x81)
878 #define shadowmode_off() write3CE(CyberControl, read3CE(CyberControl) & 0x7E)
880 /* Set the hardware to the requested video mode */
881 static int tridentfb_set_par(struct fb_info *info)
883 struct tridentfb_par *par = (struct tridentfb_par *)(info->par);
884 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend;
885 u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend;
886 struct fb_var_screeninfo *var = &info->var;
887 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;
909 write3CE(CyberControl, 8);
911 if (flatpanel && var->xres < nativex) {
913 * on flat panels with native size larger
914 * than requested resolution decide whether
915 * we stretch or center
928 write3CE(CyberControl, 8);
931 /* vertical timing values */
932 write3X4(CRTVTotal, vtotal & 0xFF);
933 write3X4(CRTVDispEnd, vdispend & 0xFF);
934 write3X4(CRTVSyncStart, vsyncstart & 0xFF);
935 write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
936 write3X4(CRTVBlankStart, vblankstart & 0xFF);
937 write3X4(CRTVBlankEnd, 0 /* p->vblankend & 0xFF */ );
939 /* horizontal timing values */
940 write3X4(CRTHTotal, htotal & 0xFF);
941 write3X4(CRTHDispEnd, hdispend & 0xFF);
942 write3X4(CRTHSyncStart, hsyncstart & 0xFF);
943 write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
944 write3X4(CRTHBlankStart, hblankstart & 0xFF);
945 write3X4(CRTHBlankEnd, 0 /* (p->hblankend & 0x1F) */ );
947 /* higher bits of vertical timing values */
949 if (vtotal & 0x100) tmp |= 0x01;
950 if (vdispend & 0x100) tmp |= 0x02;
951 if (vsyncstart & 0x100) tmp |= 0x04;
952 if (vblankstart & 0x100) tmp |= 0x08;
954 if (vtotal & 0x200) tmp |= 0x20;
955 if (vdispend & 0x200) tmp |= 0x40;
956 if (vsyncstart & 0x200) tmp |= 0x80;
957 write3X4(CRTOverflow, tmp);
959 tmp = read3X4(CRTHiOrd) | 0x08; /* line compare bit 10 */
960 if (vtotal & 0x400) tmp |= 0x80;
961 if (vblankstart & 0x400) tmp |= 0x40;
962 if (vsyncstart & 0x400) tmp |= 0x20;
963 if (vdispend & 0x400) tmp |= 0x10;
964 write3X4(CRTHiOrd, tmp);
967 if (htotal & 0x800) tmp |= 0x800 >> 11;
968 if (hblankstart & 0x800) tmp |= 0x800 >> 7;
969 write3X4(HorizOverflow, tmp);
972 if (vblankstart & 0x200) tmp |= 0x20;
973 //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */
974 write3X4(CRTMaxScanLine, tmp);
976 write3X4(CRTLineCompare, 0xFF);
977 write3X4(CRTPRowScan, 0);
978 write3X4(CRTModeControl, 0xC3);
980 write3X4(LinearAddReg, 0x20); /* enable linear addressing */
982 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80;
983 write3X4(CRTCModuleTest, tmp); /* enable access extended memory */
985 write3X4(GraphEngReg, 0x80); /* enable GE for text acceleration */
987 #ifdef CONFIG_FB_TRIDENT_ACCEL
988 acc->init_accel(info->var.xres, bpp);
1006 write3X4(PixelBusReg, tmp);
1011 write3X4(DRAMControl, tmp); /* both IO, linear enable */
1013 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
1014 write3X4(Performance, 0x92);
1015 write3X4(PCIReg, 0x07); /* MMIO & PCI read and write burst enable */
1017 /* convert from picoseconds to kHz */
1018 vclk = PICOS2KHZ(info->var.pixclock);
1024 write3C4(1, 1); /* set char clock 8 dots wide */
1025 write3C4(2, 0x0F); /* enable 4 maps because needed in chain4 mode */
1027 write3C4(4, 0x0E); /* memory mode enable bitmaps ?? */
1029 write3CE(MiscExtFunc, (bpp == 32) ? 0x1A : 0x12); /* divide clock by 2 if 32bpp */
1030 /* chain4 mode display and CPU path */
1031 write3CE(0x5, 0x40); /* no CGA compat, allow 256 col */
1032 write3CE(0x6, 0x05); /* graphics mode */
1033 write3CE(0x7, 0x0F); /* planes? */
1035 if (chip_id == CYBERBLADEXPAi1) {
1036 /* This fixes snow-effect in 32 bpp */
1037 write3X4(CRTHSyncStart, 0x84);
1040 writeAttr(0x10, 0x41); /* graphics mode and support 256 color modes */
1041 writeAttr(0x12, 0x0F); /* planes */
1042 writeAttr(0x13, 0); /* horizontal pel panning */
1045 for (tmp = 0; tmp < 0x10; tmp++)
1046 writeAttr(tmp, tmp);
1047 readb(par->io_virt + CRT + 0x0A); /* flip-flop to index */
1048 t_outb(0x20, 0x3C0); /* enable attr */
1075 set_number_of_lines(info->var.yres);
1076 set_lwidth(info->var.xres * bpp / (4 * 16));
1077 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1078 info->fix.line_length = info->var.xres * (bpp >> 3);
1079 info->cmap.len = (bpp == 8) ? 256 : 16;
1084 /* Set one color register */
1085 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1086 unsigned blue, unsigned transp,
1087 struct fb_info *info)
1089 int bpp = info->var.bits_per_pixel;
1091 if (regno >= info->cmap.len)
1095 t_outb(0xFF, 0x3C6);
1096 t_outb(regno, 0x3C8);
1098 t_outb(red >> 10, 0x3C9);
1099 t_outb(green >> 10, 0x3C9);
1100 t_outb(blue >> 10, 0x3C9);
1102 } else if (regno < 16) {
1103 if (bpp == 16) { /* RGB 565 */
1106 col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
1107 ((blue & 0xF800) >> 11);
1109 ((u32 *)(info->pseudo_palette))[regno] = col;
1110 } else if (bpp == 32) /* ARGB 8888 */
1111 ((u32*)info->pseudo_palette)[regno] =
1112 ((transp & 0xFF00) << 16) |
1113 ((red & 0xFF00) << 8) |
1114 ((green & 0xFF00)) |
1115 ((blue & 0xFF00) >> 8);
1118 /* debug("exit\n"); */
1122 /* Try blanking the screen.For flat panels it does nothing */
1123 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1125 unsigned char PMCont, DPMSCont;
1130 t_outb(0x04, 0x83C8); /* Read DPMS Control */
1131 PMCont = t_inb(0x83C6) & 0xFC;
1132 DPMSCont = read3CE(PowerStatus) & 0xFC;
1133 switch (blank_mode) {
1134 case FB_BLANK_UNBLANK:
1135 /* Screen: On, HSync: On, VSync: On */
1136 case FB_BLANK_NORMAL:
1137 /* Screen: Off, HSync: On, VSync: On */
1141 case FB_BLANK_HSYNC_SUSPEND:
1142 /* Screen: Off, HSync: Off, VSync: On */
1146 case FB_BLANK_VSYNC_SUSPEND:
1147 /* Screen: Off, HSync: On, VSync: Off */
1151 case FB_BLANK_POWERDOWN:
1152 /* Screen: Off, HSync: Off, VSync: Off */
1158 write3CE(PowerStatus, DPMSCont);
1160 t_outb(PMCont, 0x83C6);
1164 /* let fbcon do a softblank for us */
1165 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1168 static struct fb_ops tridentfb_ops = {
1169 .owner = THIS_MODULE,
1170 .fb_setcolreg = tridentfb_setcolreg,
1171 .fb_pan_display = tridentfb_pan_display,
1172 .fb_blank = tridentfb_blank,
1173 .fb_check_var = tridentfb_check_var,
1174 .fb_set_par = tridentfb_set_par,
1175 .fb_fillrect = tridentfb_fillrect,
1176 .fb_copyarea = tridentfb_copyarea,
1177 .fb_imageblit = cfb_imageblit,
1180 static int __devinit trident_pci_probe(struct pci_dev * dev,
1181 const struct pci_device_id * id)
1184 unsigned char revision;
1186 err = pci_enable_device(dev);
1190 chip_id = id->device;
1192 if (chip_id == CYBERBLADEi1)
1193 output("*** Please do use cyblafb, Cyberblade/i1 support "
1194 "will soon be removed from tridentfb!\n");
1197 /* If PCI id is 0x9660 then further detect chip type */
1199 if (chip_id == TGUI9660) {
1200 outb(RevisionID, 0x3C4);
1201 revision = inb(0x3C5);
1206 chip_id = CYBER9397;
1209 chip_id = CYBER9397DVD;
1218 chip_id = CYBER9385;
1221 chip_id = CYBER9382;
1224 chip_id = CYBER9388;
1231 chip3D = is3Dchip(chip_id);
1232 chipcyber = iscyber(chip_id);
1234 if (is_xp(chip_id)) {
1236 } else if (is_blade(chip_id)) {
1242 /* acceleration is on by default for 3D chips */
1243 defaultaccel = chip3D && !noaccel;
1245 fb_info.par = &default_par;
1247 /* setup MMIO region */
1248 tridentfb_fix.mmio_start = pci_resource_start(dev, 1);
1249 tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000;
1251 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1252 debug("request_region failed!\n");
1256 default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1258 if (!default_par.io_virt) {
1259 debug("ioremap failed\n");
1266 /* setup framebuffer memory */
1267 tridentfb_fix.smem_start = pci_resource_start(dev, 0);
1268 tridentfb_fix.smem_len = get_memsize();
1270 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1271 debug("request_mem_region failed!\n");
1277 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1278 tridentfb_fix.smem_len);
1280 if (!fb_info.screen_base) {
1281 debug("ioremap failed\n");
1286 output("%s board found\n", pci_name(dev));
1287 displaytype = get_displaytype();
1290 nativex = get_nativex();
1292 fb_info.fix = tridentfb_fix;
1293 fb_info.fbops = &tridentfb_ops;
1296 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1297 #ifdef CONFIG_FB_TRIDENT_ACCEL
1298 fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1300 fb_info.pseudo_palette = pseudo_pal;
1302 if (!fb_find_mode(&default_var, &fb_info,
1303 mode_option, NULL, 0, NULL, bpp)) {
1307 err = fb_alloc_cmap(&fb_info.cmap, 256, 0);
1311 if (defaultaccel && acc)
1312 default_var.accel_flags |= FB_ACCELF_TEXT;
1314 default_var.accel_flags &= ~FB_ACCELF_TEXT;
1315 default_var.activate |= FB_ACTIVATE_NOW;
1316 fb_info.var = default_var;
1317 fb_info.device = &dev->dev;
1318 if (register_framebuffer(&fb_info) < 0) {
1319 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1320 fb_dealloc_cmap(&fb_info.cmap);
1324 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1325 fb_info.node, fb_info.fix.id, default_var.xres,
1326 default_var.yres, default_var.bits_per_pixel);
1330 if (fb_info.screen_base)
1331 iounmap(fb_info.screen_base);
1332 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1335 if (default_par.io_virt)
1336 iounmap(default_par.io_virt);
1337 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1341 static void __devexit trident_pci_remove(struct pci_dev *dev)
1343 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1344 unregister_framebuffer(&fb_info);
1345 iounmap(par->io_virt);
1346 iounmap(fb_info.screen_base);
1347 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1348 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1351 /* List of boards that we are trying to support */
1352 static struct pci_device_id trident_devices[] = {
1353 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1354 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1355 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1356 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1357 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1358 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1359 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1360 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1361 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1362 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1363 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1364 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1365 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1366 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1367 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1368 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1369 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1370 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1371 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1372 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1376 MODULE_DEVICE_TABLE(pci, trident_devices);
1378 static struct pci_driver tridentfb_pci_driver = {
1379 .name = "tridentfb",
1380 .id_table = trident_devices,
1381 .probe = trident_pci_probe,
1382 .remove = __devexit_p(trident_pci_remove)
1386 * Parse user specified options (`video=trident:')
1388 * video=trident:800x600,bpp=16,noaccel
1391 static int __init tridentfb_setup(char *options)
1394 if (!options || !*options)
1396 while ((opt = strsep(&options, ",")) != NULL) {
1399 if (!strncmp(opt, "noaccel", 7))
1401 else if (!strncmp(opt, "fp", 2))
1402 displaytype = DISPLAY_FP;
1403 else if (!strncmp(opt, "crt", 3))
1404 displaytype = DISPLAY_CRT;
1405 else if (!strncmp(opt, "bpp=", 4))
1406 bpp = simple_strtoul(opt + 4, NULL, 0);
1407 else if (!strncmp(opt, "center", 6))
1409 else if (!strncmp(opt, "stretch", 7))
1411 else if (!strncmp(opt, "memsize=", 8))
1412 memsize = simple_strtoul(opt + 8, NULL, 0);
1413 else if (!strncmp(opt, "memdiff=", 8))
1414 memdiff = simple_strtoul(opt + 8, NULL, 0);
1415 else if (!strncmp(opt, "nativex=", 8))
1416 nativex = simple_strtoul(opt + 8, NULL, 0);
1424 static int __init tridentfb_init(void)
1427 char *option = NULL;
1429 if (fb_get_options("tridentfb", &option))
1431 tridentfb_setup(option);
1433 output("Trident framebuffer %s initializing\n", VERSION);
1434 return pci_register_driver(&tridentfb_pci_driver);
1437 static void __exit tridentfb_exit(void)
1439 pci_unregister_driver(&tridentfb_pci_driver);
1442 module_init(tridentfb_init);
1443 module_exit(tridentfb_exit);
1445 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1446 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1447 MODULE_LICENSE("GPL");