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 void enable_mmio(void)
575 /* Unprotect registers */
576 outb(NewMode1, 0x3C4);
582 outb(inb(0x3D5) | 0x01, 0x3D5);
584 t_outb(NewMode1, 0x3C4);
588 static void disable_mmio(void)
596 /* Unprotect registers */
597 t_outb(NewMode1, 0x3C4);
602 t_outb(PCIReg, 0x3D4);
603 t_outb(t_inb(0x3D5) & ~0x01, 0x3D5);
605 outb(NewMode1, 0x3C4);
609 #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
611 /* Return flat panel's maximum x resolution */
612 static int __devinit get_nativex(void)
619 tmp = (read3CE(VertStretch) >> 4) & 3;
640 output("%dx%d flat panel found\n", x, y);
645 static void set_lwidth(int width)
647 write3X4(Offset, width & 0xFF);
649 (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >> 4));
652 /* For resolutions smaller than FP resolution stretch */
653 static void screen_stretch(void)
655 if (chip_id != CYBERBLADEXPAi1)
656 write3CE(BiosReg, 0);
658 write3CE(BiosReg, 8);
659 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 1);
660 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 1);
663 /* For resolutions smaller than FP resolution center */
664 static void screen_center(void)
666 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 0x80);
667 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 0x80);
670 /* Address of first shown pixel in display memory */
671 static void set_screen_start(int base)
673 write3X4(StartAddrLow, base & 0xFF);
674 write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
675 write3X4(CRTCModuleTest,
676 (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
678 (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
681 /* Use 20.12 fixed-point for NTSC value and frequency calculation */
682 #define calc_freq(n, m, k) ( ((unsigned long)0xE517 * (n + 8) / ((m + 2) * (1 << k))) >> 12 )
684 /* Set dotclock frequency */
685 static void set_vclk(int freq)
689 unsigned char lo = 0, hi = 0;
692 for (k = 2; k >= 0; k--)
693 for (m = 0; m < 63; m++)
694 for (n = 0; n < 128; n++) {
695 fi = calc_freq(n, m, k);
696 if ((di = abs(fi - freq)) < d) {
704 write3C4(ClockHigh, hi);
705 write3C4(ClockLow, lo);
710 debug("VCLK = %X %X\n", hi, lo);
713 /* Set number of lines for flat panels*/
714 static void set_number_of_lines(int lines)
716 int tmp = read3CE(CyberEnhance) & 0x8F;
719 else if (lines > 768)
721 else if (lines > 600)
723 else if (lines > 480)
725 write3CE(CyberEnhance, tmp);
729 * If we see that FP is active we assume we have one.
730 * Otherwise we have a CRT display.User can override.
732 static unsigned int __devinit get_displaytype(void)
736 if (crt || !chipcyber)
738 return (read3CE(FPConfig) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
741 /* Try detecting the video memory size */
742 static unsigned int __devinit get_memsize(void)
744 unsigned char tmp, tmp2;
747 /* If memory size provided by user */
756 tmp = read3X4(SPR) & 0x0F;
772 k = 10 * Mb; /* XP */
778 k = 12 * Mb; /* XP */
781 k = 14 * Mb; /* XP */
784 k = 16 * Mb; /* XP */
788 tmp2 = read3C4(0xC1);
818 output("framebuffer size = %d Kb\n", k / Kb);
822 /* See if we can handle the video mode described in var */
823 static int tridentfb_check_var(struct fb_var_screeninfo *var,
824 struct fb_info *info)
826 int bpp = var->bits_per_pixel;
829 /* check color depth */
831 bpp = var->bits_per_pixel = 32;
832 /* check whether resolution fits on panel and in memory */
833 if (flatpanel && nativex && var->xres > nativex)
835 if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len)
841 var->green.offset = 0;
842 var->blue.offset = 0;
844 var->green.length = 6;
845 var->blue.length = 6;
848 var->red.offset = 11;
849 var->green.offset = 5;
850 var->blue.offset = 0;
852 var->green.length = 6;
853 var->blue.length = 5;
856 var->red.offset = 16;
857 var->green.offset = 8;
858 var->blue.offset = 0;
860 var->green.length = 8;
861 var->blue.length = 8;
872 /* Pan the display */
873 static int tridentfb_pan_display(struct fb_var_screeninfo *var,
874 struct fb_info *info)
879 offset = (var->xoffset + (var->yoffset * var->xres))
880 * var->bits_per_pixel / 32;
881 info->var.xoffset = var->xoffset;
882 info->var.yoffset = var->yoffset;
883 set_screen_start(offset);
888 #define shadowmode_on() write3CE(CyberControl, read3CE(CyberControl) | 0x81)
889 #define shadowmode_off() write3CE(CyberControl, read3CE(CyberControl) & 0x7E)
891 /* Set the hardware to the requested video mode */
892 static int tridentfb_set_par(struct fb_info *info)
894 struct tridentfb_par *par = (struct tridentfb_par *)(info->par);
895 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend;
896 u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend;
897 struct fb_var_screeninfo *var = &info->var;
898 int bpp = var->bits_per_pixel;
901 hdispend = var->xres / 8 - 1;
902 hsyncstart = (var->xres + var->right_margin) / 8;
903 hsyncend = var->hsync_len / 8;
905 (var->xres + var->left_margin + var->right_margin +
906 var->hsync_len) / 8 - 10;
907 hblankstart = hdispend + 1;
908 hblankend = htotal + 5;
910 vdispend = var->yres - 1;
911 vsyncstart = var->yres + var->lower_margin;
912 vsyncend = var->vsync_len;
913 vtotal = var->upper_margin + vsyncstart + vsyncend - 2;
914 vblankstart = var->yres;
915 vblankend = vtotal + 2;
919 write3CE(CyberControl, 8);
921 if (flatpanel && var->xres < nativex) {
923 * on flat panels with native size larger
924 * than requested resolution decide whether
925 * we stretch or center
938 write3CE(CyberControl, 8);
941 /* vertical timing values */
942 write3X4(CRTVTotal, vtotal & 0xFF);
943 write3X4(CRTVDispEnd, vdispend & 0xFF);
944 write3X4(CRTVSyncStart, vsyncstart & 0xFF);
945 write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
946 write3X4(CRTVBlankStart, vblankstart & 0xFF);
947 write3X4(CRTVBlankEnd, 0 /* p->vblankend & 0xFF */ );
949 /* horizontal timing values */
950 write3X4(CRTHTotal, htotal & 0xFF);
951 write3X4(CRTHDispEnd, hdispend & 0xFF);
952 write3X4(CRTHSyncStart, hsyncstart & 0xFF);
953 write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
954 write3X4(CRTHBlankStart, hblankstart & 0xFF);
955 write3X4(CRTHBlankEnd, 0 /* (p->hblankend & 0x1F) */ );
957 /* higher bits of vertical timing values */
959 if (vtotal & 0x100) tmp |= 0x01;
960 if (vdispend & 0x100) tmp |= 0x02;
961 if (vsyncstart & 0x100) tmp |= 0x04;
962 if (vblankstart & 0x100) tmp |= 0x08;
964 if (vtotal & 0x200) tmp |= 0x20;
965 if (vdispend & 0x200) tmp |= 0x40;
966 if (vsyncstart & 0x200) tmp |= 0x80;
967 write3X4(CRTOverflow, tmp);
969 tmp = read3X4(CRTHiOrd) | 0x08; /* line compare bit 10 */
970 if (vtotal & 0x400) tmp |= 0x80;
971 if (vblankstart & 0x400) tmp |= 0x40;
972 if (vsyncstart & 0x400) tmp |= 0x20;
973 if (vdispend & 0x400) tmp |= 0x10;
974 write3X4(CRTHiOrd, tmp);
977 if (htotal & 0x800) tmp |= 0x800 >> 11;
978 if (hblankstart & 0x800) tmp |= 0x800 >> 7;
979 write3X4(HorizOverflow, tmp);
982 if (vblankstart & 0x200) tmp |= 0x20;
983 //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */
984 write3X4(CRTMaxScanLine, tmp);
986 write3X4(CRTLineCompare, 0xFF);
987 write3X4(CRTPRowScan, 0);
988 write3X4(CRTModeControl, 0xC3);
990 write3X4(LinearAddReg, 0x20); /* enable linear addressing */
992 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80;
993 write3X4(CRTCModuleTest, tmp); /* enable access extended memory */
995 write3X4(GraphEngReg, 0x80); /* enable GE for text acceleration */
997 #ifdef CONFIG_FB_TRIDENT_ACCEL
998 acc->init_accel(info->var.xres, bpp);
1016 write3X4(PixelBusReg, tmp);
1021 write3X4(DRAMControl, tmp); /* both IO, linear enable */
1023 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
1024 write3X4(Performance, 0x92);
1025 write3X4(PCIReg, 0x07); /* MMIO & PCI read and write burst enable */
1027 /* convert from picoseconds to MHz */
1028 par->vclk = 1000000 / info->var.pixclock;
1031 set_vclk(par->vclk);
1034 write3C4(1, 1); /* set char clock 8 dots wide */
1035 write3C4(2, 0x0F); /* enable 4 maps because needed in chain4 mode */
1037 write3C4(4, 0x0E); /* memory mode enable bitmaps ?? */
1039 write3CE(MiscExtFunc, (bpp == 32) ? 0x1A : 0x12); /* divide clock by 2 if 32bpp */
1040 /* chain4 mode display and CPU path */
1041 write3CE(0x5, 0x40); /* no CGA compat, allow 256 col */
1042 write3CE(0x6, 0x05); /* graphics mode */
1043 write3CE(0x7, 0x0F); /* planes? */
1045 if (chip_id == CYBERBLADEXPAi1) {
1046 /* This fixes snow-effect in 32 bpp */
1047 write3X4(CRTHSyncStart, 0x84);
1050 writeAttr(0x10, 0x41); /* graphics mode and support 256 color modes */
1051 writeAttr(0x12, 0x0F); /* planes */
1052 writeAttr(0x13, 0); /* horizontal pel panning */
1055 for (tmp = 0; tmp < 0x10; tmp++)
1056 writeAttr(tmp, tmp);
1057 readb(par->io_virt + CRT + 0x0A); /* flip-flop to index */
1058 t_outb(0x20, 0x3C0); /* enable attr */
1085 set_number_of_lines(info->var.yres);
1086 set_lwidth(info->var.xres * bpp / (4 * 16));
1087 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1088 info->fix.line_length = info->var.xres * (bpp >> 3);
1089 info->cmap.len = (bpp == 8) ? 256 : 16;
1094 /* Set one color register */
1095 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1096 unsigned blue, unsigned transp,
1097 struct fb_info *info)
1099 int bpp = info->var.bits_per_pixel;
1101 if (regno >= info->cmap.len)
1105 t_outb(0xFF, 0x3C6);
1106 t_outb(regno, 0x3C8);
1108 t_outb(red >> 10, 0x3C9);
1109 t_outb(green >> 10, 0x3C9);
1110 t_outb(blue >> 10, 0x3C9);
1112 } else if (regno < 16) {
1113 if (bpp == 16) { /* RGB 565 */
1116 col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
1117 ((blue & 0xF800) >> 11);
1119 ((u32 *)(info->pseudo_palette))[regno] = col;
1120 } else if (bpp == 32) /* ARGB 8888 */
1121 ((u32*)info->pseudo_palette)[regno] =
1122 ((transp & 0xFF00) << 16) |
1123 ((red & 0xFF00) << 8) |
1124 ((green & 0xFF00)) |
1125 ((blue & 0xFF00) >> 8);
1128 /* debug("exit\n"); */
1132 /* Try blanking the screen.For flat panels it does nothing */
1133 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1135 unsigned char PMCont, DPMSCont;
1140 t_outb(0x04, 0x83C8); /* Read DPMS Control */
1141 PMCont = t_inb(0x83C6) & 0xFC;
1142 DPMSCont = read3CE(PowerStatus) & 0xFC;
1143 switch (blank_mode) {
1144 case FB_BLANK_UNBLANK:
1145 /* Screen: On, HSync: On, VSync: On */
1146 case FB_BLANK_NORMAL:
1147 /* Screen: Off, HSync: On, VSync: On */
1151 case FB_BLANK_HSYNC_SUSPEND:
1152 /* Screen: Off, HSync: Off, VSync: On */
1156 case FB_BLANK_VSYNC_SUSPEND:
1157 /* Screen: Off, HSync: On, VSync: Off */
1161 case FB_BLANK_POWERDOWN:
1162 /* Screen: Off, HSync: Off, VSync: Off */
1168 write3CE(PowerStatus, DPMSCont);
1170 t_outb(PMCont, 0x83C6);
1174 /* let fbcon do a softblank for us */
1175 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1178 static struct fb_ops tridentfb_ops = {
1179 .owner = THIS_MODULE,
1180 .fb_setcolreg = tridentfb_setcolreg,
1181 .fb_pan_display = tridentfb_pan_display,
1182 .fb_blank = tridentfb_blank,
1183 .fb_check_var = tridentfb_check_var,
1184 .fb_set_par = tridentfb_set_par,
1185 .fb_fillrect = tridentfb_fillrect,
1186 .fb_copyarea = tridentfb_copyarea,
1187 .fb_imageblit = cfb_imageblit,
1190 static int __devinit trident_pci_probe(struct pci_dev * dev,
1191 const struct pci_device_id * id)
1194 unsigned char revision;
1196 err = pci_enable_device(dev);
1200 chip_id = id->device;
1202 if (chip_id == CYBERBLADEi1)
1203 output("*** Please do use cyblafb, Cyberblade/i1 support "
1204 "will soon be removed from tridentfb!\n");
1207 /* If PCI id is 0x9660 then further detect chip type */
1209 if (chip_id == TGUI9660) {
1210 outb(RevisionID, 0x3C4);
1211 revision = inb(0x3C5);
1216 chip_id = CYBER9397;
1219 chip_id = CYBER9397DVD;
1228 chip_id = CYBER9385;
1231 chip_id = CYBER9382;
1234 chip_id = CYBER9388;
1241 chip3D = is3Dchip(chip_id);
1242 chipcyber = iscyber(chip_id);
1244 if (is_xp(chip_id)) {
1246 } else if (is_blade(chip_id)) {
1252 /* acceleration is on by default for 3D chips */
1253 defaultaccel = chip3D && !noaccel;
1255 fb_info.par = &default_par;
1257 /* setup MMIO region */
1258 tridentfb_fix.mmio_start = pci_resource_start(dev, 1);
1259 tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000;
1261 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1262 debug("request_region failed!\n");
1266 default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1268 if (!default_par.io_virt) {
1269 debug("ioremap failed\n");
1276 /* setup framebuffer memory */
1277 tridentfb_fix.smem_start = pci_resource_start(dev, 0);
1278 tridentfb_fix.smem_len = get_memsize();
1280 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1281 debug("request_mem_region failed!\n");
1287 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1288 tridentfb_fix.smem_len);
1290 if (!fb_info.screen_base) {
1291 debug("ioremap failed\n");
1296 output("%s board found\n", pci_name(dev));
1297 displaytype = get_displaytype();
1300 nativex = get_nativex();
1302 fb_info.fix = tridentfb_fix;
1303 fb_info.fbops = &tridentfb_ops;
1306 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1307 #ifdef CONFIG_FB_TRIDENT_ACCEL
1308 fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1310 fb_info.pseudo_palette = pseudo_pal;
1312 if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) {
1316 err = fb_alloc_cmap(&fb_info.cmap, 256, 0);
1320 if (defaultaccel && acc)
1321 default_var.accel_flags |= FB_ACCELF_TEXT;
1323 default_var.accel_flags &= ~FB_ACCELF_TEXT;
1324 default_var.activate |= FB_ACTIVATE_NOW;
1325 fb_info.var = default_var;
1326 fb_info.device = &dev->dev;
1327 if (register_framebuffer(&fb_info) < 0) {
1328 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1329 fb_dealloc_cmap(&fb_info.cmap);
1333 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1334 fb_info.node, fb_info.fix.id, default_var.xres,
1335 default_var.yres, default_var.bits_per_pixel);
1339 if (fb_info.screen_base)
1340 iounmap(fb_info.screen_base);
1341 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1344 if (default_par.io_virt)
1345 iounmap(default_par.io_virt);
1346 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1350 static void __devexit trident_pci_remove(struct pci_dev *dev)
1352 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1353 unregister_framebuffer(&fb_info);
1354 iounmap(par->io_virt);
1355 iounmap(fb_info.screen_base);
1356 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1357 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1360 /* List of boards that we are trying to support */
1361 static struct pci_device_id trident_devices[] = {
1362 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1363 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1364 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1365 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1366 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1367 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1368 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1369 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1370 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1371 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1372 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1373 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1374 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1375 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1376 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1377 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1378 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1379 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1380 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1381 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1385 MODULE_DEVICE_TABLE(pci, trident_devices);
1387 static struct pci_driver tridentfb_pci_driver = {
1388 .name = "tridentfb",
1389 .id_table = trident_devices,
1390 .probe = trident_pci_probe,
1391 .remove = __devexit_p(trident_pci_remove)
1395 * Parse user specified options (`video=trident:')
1397 * video=trident:800x600,bpp=16,noaccel
1400 static int tridentfb_setup(char *options)
1403 if (!options || !*options)
1405 while ((opt = strsep(&options, ",")) != NULL) {
1408 if (!strncmp(opt, "noaccel", 7))
1410 else if (!strncmp(opt, "fp", 2))
1411 displaytype = DISPLAY_FP;
1412 else if (!strncmp(opt, "crt", 3))
1413 displaytype = DISPLAY_CRT;
1414 else if (!strncmp(opt, "bpp=", 4))
1415 bpp = simple_strtoul(opt + 4, NULL, 0);
1416 else if (!strncmp(opt, "center", 6))
1418 else if (!strncmp(opt, "stretch", 7))
1420 else if (!strncmp(opt, "memsize=", 8))
1421 memsize = simple_strtoul(opt + 8, NULL, 0);
1422 else if (!strncmp(opt, "memdiff=", 8))
1423 memdiff = simple_strtoul(opt + 8, NULL, 0);
1424 else if (!strncmp(opt, "nativex=", 8))
1425 nativex = simple_strtoul(opt + 8, NULL, 0);
1433 static int __init tridentfb_init(void)
1436 char *option = NULL;
1438 if (fb_get_options("tridentfb", &option))
1440 tridentfb_setup(option);
1442 output("Trident framebuffer %s initializing\n", VERSION);
1443 return pci_register_driver(&tridentfb_pci_driver);
1446 static void __exit tridentfb_exit(void)
1448 pci_unregister_driver(&tridentfb_pci_driver);
1451 module_init(tridentfb_init);
1452 module_exit(tridentfb_exit);
1454 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1455 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1456 MODULE_LICENSE("GPL");