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)
573 /* Unprotect registers */
574 outb(NewMode1, 0x3C4);
579 outb(inb(0x3D5) | 0x01, 0x3D5);
582 static void disable_mmio(void)
588 /* Unprotect registers */
589 t_outb(NewMode1, 0x3C4);
593 t_outb(PCIReg, 0x3D4);
594 t_outb(t_inb(0x3D5) & ~0x01, 0x3D5);
597 #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
599 /* Return flat panel's maximum x resolution */
600 static int __devinit get_nativex(void)
607 tmp = (read3CE(VertStretch) >> 4) & 3;
628 output("%dx%d flat panel found\n", x, y);
633 static void set_lwidth(int width)
635 write3X4(Offset, width & 0xFF);
637 (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >> 4));
640 /* For resolutions smaller than FP resolution stretch */
641 static void screen_stretch(void)
643 if (chip_id != CYBERBLADEXPAi1)
644 write3CE(BiosReg, 0);
646 write3CE(BiosReg, 8);
647 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 1);
648 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 1);
651 /* For resolutions smaller than FP resolution center */
652 static void screen_center(void)
654 write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 0x80);
655 write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 0x80);
658 /* Address of first shown pixel in display memory */
659 static void set_screen_start(int base)
661 write3X4(StartAddrLow, base & 0xFF);
662 write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
663 write3X4(CRTCModuleTest,
664 (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
666 (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
669 /* Use 20.12 fixed-point for NTSC value and frequency calculation */
670 #define calc_freq(n, m, k) ( ((unsigned long)0xE517 * (n + 8) / ((m + 2) * (1 << k))) >> 12 )
672 /* Set dotclock frequency */
673 static void set_vclk(int freq)
677 unsigned char lo = 0, hi = 0;
680 for (k = 2; k >= 0; k--)
681 for (m = 0; m < 63; m++)
682 for (n = 0; n < 128; n++) {
683 fi = calc_freq(n, m, k);
684 if ((di = abs(fi - freq)) < d) {
692 write3C4(ClockHigh, hi);
693 write3C4(ClockLow, lo);
698 debug("VCLK = %X %X\n", hi, lo);
701 /* Set number of lines for flat panels*/
702 static void set_number_of_lines(int lines)
704 int tmp = read3CE(CyberEnhance) & 0x8F;
707 else if (lines > 768)
709 else if (lines > 600)
711 else if (lines > 480)
713 write3CE(CyberEnhance, tmp);
717 * If we see that FP is active we assume we have one.
718 * Otherwise we have a CRT display.User can override.
720 static unsigned int __devinit get_displaytype(void)
724 if (crt || !chipcyber)
726 return (read3CE(FPConfig) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
729 /* Try detecting the video memory size */
730 static unsigned int __devinit get_memsize(void)
732 unsigned char tmp, tmp2;
735 /* If memory size provided by user */
744 tmp = read3X4(SPR) & 0x0F;
760 k = 10 * Mb; /* XP */
766 k = 12 * Mb; /* XP */
769 k = 14 * Mb; /* XP */
772 k = 16 * Mb; /* XP */
776 tmp2 = read3C4(0xC1);
806 output("framebuffer size = %d Kb\n", k / Kb);
810 /* See if we can handle the video mode described in var */
811 static int tridentfb_check_var(struct fb_var_screeninfo *var,
812 struct fb_info *info)
814 int bpp = var->bits_per_pixel;
817 /* check color depth */
819 bpp = var->bits_per_pixel = 32;
820 /* check whether resolution fits on panel and in memory */
821 if (flatpanel && nativex && var->xres > nativex)
823 if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len)
829 var->green.offset = 0;
830 var->blue.offset = 0;
832 var->green.length = 6;
833 var->blue.length = 6;
836 var->red.offset = 11;
837 var->green.offset = 5;
838 var->blue.offset = 0;
840 var->green.length = 6;
841 var->blue.length = 5;
844 var->red.offset = 16;
845 var->green.offset = 8;
846 var->blue.offset = 0;
848 var->green.length = 8;
849 var->blue.length = 8;
860 /* Pan the display */
861 static int tridentfb_pan_display(struct fb_var_screeninfo *var,
862 struct fb_info *info)
867 offset = (var->xoffset + (var->yoffset * var->xres))
868 * var->bits_per_pixel / 32;
869 info->var.xoffset = var->xoffset;
870 info->var.yoffset = var->yoffset;
871 set_screen_start(offset);
876 #define shadowmode_on() write3CE(CyberControl, read3CE(CyberControl) | 0x81)
877 #define shadowmode_off() write3CE(CyberControl, read3CE(CyberControl) & 0x7E)
879 /* Set the hardware to the requested video mode */
880 static int tridentfb_set_par(struct fb_info *info)
882 struct tridentfb_par *par = (struct tridentfb_par *)(info->par);
883 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend;
884 u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend;
885 struct fb_var_screeninfo *var = &info->var;
886 int bpp = var->bits_per_pixel;
889 hdispend = var->xres / 8 - 1;
890 hsyncstart = (var->xres + var->right_margin) / 8;
891 hsyncend = var->hsync_len / 8;
893 (var->xres + var->left_margin + var->right_margin +
894 var->hsync_len) / 8 - 10;
895 hblankstart = hdispend + 1;
896 hblankend = htotal + 5;
898 vdispend = var->yres - 1;
899 vsyncstart = var->yres + var->lower_margin;
900 vsyncend = var->vsync_len;
901 vtotal = var->upper_margin + vsyncstart + vsyncend - 2;
902 vblankstart = var->yres;
903 vblankend = vtotal + 2;
907 write3CE(CyberControl, 8);
909 if (flatpanel && var->xres < nativex) {
911 * on flat panels with native size larger
912 * than requested resolution decide whether
913 * we stretch or center
926 write3CE(CyberControl, 8);
929 /* vertical timing values */
930 write3X4(CRTVTotal, vtotal & 0xFF);
931 write3X4(CRTVDispEnd, vdispend & 0xFF);
932 write3X4(CRTVSyncStart, vsyncstart & 0xFF);
933 write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
934 write3X4(CRTVBlankStart, vblankstart & 0xFF);
935 write3X4(CRTVBlankEnd, 0 /* p->vblankend & 0xFF */ );
937 /* horizontal timing values */
938 write3X4(CRTHTotal, htotal & 0xFF);
939 write3X4(CRTHDispEnd, hdispend & 0xFF);
940 write3X4(CRTHSyncStart, hsyncstart & 0xFF);
941 write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
942 write3X4(CRTHBlankStart, hblankstart & 0xFF);
943 write3X4(CRTHBlankEnd, 0 /* (p->hblankend & 0x1F) */ );
945 /* higher bits of vertical timing values */
947 if (vtotal & 0x100) tmp |= 0x01;
948 if (vdispend & 0x100) tmp |= 0x02;
949 if (vsyncstart & 0x100) tmp |= 0x04;
950 if (vblankstart & 0x100) tmp |= 0x08;
952 if (vtotal & 0x200) tmp |= 0x20;
953 if (vdispend & 0x200) tmp |= 0x40;
954 if (vsyncstart & 0x200) tmp |= 0x80;
955 write3X4(CRTOverflow, tmp);
957 tmp = read3X4(CRTHiOrd) | 0x08; /* line compare bit 10 */
958 if (vtotal & 0x400) tmp |= 0x80;
959 if (vblankstart & 0x400) tmp |= 0x40;
960 if (vsyncstart & 0x400) tmp |= 0x20;
961 if (vdispend & 0x400) tmp |= 0x10;
962 write3X4(CRTHiOrd, tmp);
965 if (htotal & 0x800) tmp |= 0x800 >> 11;
966 if (hblankstart & 0x800) tmp |= 0x800 >> 7;
967 write3X4(HorizOverflow, tmp);
970 if (vblankstart & 0x200) tmp |= 0x20;
971 //FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */
972 write3X4(CRTMaxScanLine, tmp);
974 write3X4(CRTLineCompare, 0xFF);
975 write3X4(CRTPRowScan, 0);
976 write3X4(CRTModeControl, 0xC3);
978 write3X4(LinearAddReg, 0x20); /* enable linear addressing */
980 tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80;
981 write3X4(CRTCModuleTest, tmp); /* enable access extended memory */
983 write3X4(GraphEngReg, 0x80); /* enable GE for text acceleration */
985 #ifdef CONFIG_FB_TRIDENT_ACCEL
986 acc->init_accel(info->var.xres, bpp);
1004 write3X4(PixelBusReg, tmp);
1009 write3X4(DRAMControl, tmp); /* both IO, linear enable */
1011 write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
1012 write3X4(Performance, 0x92);
1013 write3X4(PCIReg, 0x07); /* MMIO & PCI read and write burst enable */
1015 /* convert from picoseconds to MHz */
1016 par->vclk = 1000000 / info->var.pixclock;
1019 set_vclk(par->vclk);
1022 write3C4(1, 1); /* set char clock 8 dots wide */
1023 write3C4(2, 0x0F); /* enable 4 maps because needed in chain4 mode */
1025 write3C4(4, 0x0E); /* memory mode enable bitmaps ?? */
1027 write3CE(MiscExtFunc, (bpp == 32) ? 0x1A : 0x12); /* divide clock by 2 if 32bpp */
1028 /* chain4 mode display and CPU path */
1029 write3CE(0x5, 0x40); /* no CGA compat, allow 256 col */
1030 write3CE(0x6, 0x05); /* graphics mode */
1031 write3CE(0x7, 0x0F); /* planes? */
1033 if (chip_id == CYBERBLADEXPAi1) {
1034 /* This fixes snow-effect in 32 bpp */
1035 write3X4(CRTHSyncStart, 0x84);
1038 writeAttr(0x10, 0x41); /* graphics mode and support 256 color modes */
1039 writeAttr(0x12, 0x0F); /* planes */
1040 writeAttr(0x13, 0); /* horizontal pel panning */
1043 for (tmp = 0; tmp < 0x10; tmp++)
1044 writeAttr(tmp, tmp);
1045 readb(par->io_virt + CRT + 0x0A); /* flip-flop to index */
1046 t_outb(0x20, 0x3C0); /* enable attr */
1073 set_number_of_lines(info->var.yres);
1074 set_lwidth(info->var.xres * bpp / (4 * 16));
1075 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1076 info->fix.line_length = info->var.xres * (bpp >> 3);
1077 info->cmap.len = (bpp == 8) ? 256 : 16;
1082 /* Set one color register */
1083 static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1084 unsigned blue, unsigned transp,
1085 struct fb_info *info)
1087 int bpp = info->var.bits_per_pixel;
1089 if (regno >= info->cmap.len)
1093 t_outb(0xFF, 0x3C6);
1094 t_outb(regno, 0x3C8);
1096 t_outb(red >> 10, 0x3C9);
1097 t_outb(green >> 10, 0x3C9);
1098 t_outb(blue >> 10, 0x3C9);
1100 } else if (regno < 16) {
1101 if (bpp == 16) { /* RGB 565 */
1104 col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
1105 ((blue & 0xF800) >> 11);
1107 ((u32 *)(info->pseudo_palette))[regno] = col;
1108 } else if (bpp == 32) /* ARGB 8888 */
1109 ((u32*)info->pseudo_palette)[regno] =
1110 ((transp & 0xFF00) << 16) |
1111 ((red & 0xFF00) << 8) |
1112 ((green & 0xFF00)) |
1113 ((blue & 0xFF00) >> 8);
1116 /* debug("exit\n"); */
1120 /* Try blanking the screen.For flat panels it does nothing */
1121 static int tridentfb_blank(int blank_mode, struct fb_info *info)
1123 unsigned char PMCont, DPMSCont;
1128 t_outb(0x04, 0x83C8); /* Read DPMS Control */
1129 PMCont = t_inb(0x83C6) & 0xFC;
1130 DPMSCont = read3CE(PowerStatus) & 0xFC;
1131 switch (blank_mode) {
1132 case FB_BLANK_UNBLANK:
1133 /* Screen: On, HSync: On, VSync: On */
1134 case FB_BLANK_NORMAL:
1135 /* Screen: Off, HSync: On, VSync: On */
1139 case FB_BLANK_HSYNC_SUSPEND:
1140 /* Screen: Off, HSync: Off, VSync: On */
1144 case FB_BLANK_VSYNC_SUSPEND:
1145 /* Screen: Off, HSync: On, VSync: Off */
1149 case FB_BLANK_POWERDOWN:
1150 /* Screen: Off, HSync: Off, VSync: Off */
1156 write3CE(PowerStatus, DPMSCont);
1158 t_outb(PMCont, 0x83C6);
1162 /* let fbcon do a softblank for us */
1163 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1166 static struct fb_ops tridentfb_ops = {
1167 .owner = THIS_MODULE,
1168 .fb_setcolreg = tridentfb_setcolreg,
1169 .fb_pan_display = tridentfb_pan_display,
1170 .fb_blank = tridentfb_blank,
1171 .fb_check_var = tridentfb_check_var,
1172 .fb_set_par = tridentfb_set_par,
1173 .fb_fillrect = tridentfb_fillrect,
1174 .fb_copyarea = tridentfb_copyarea,
1175 .fb_imageblit = cfb_imageblit,
1178 static int __devinit trident_pci_probe(struct pci_dev * dev,
1179 const struct pci_device_id * id)
1182 unsigned char revision;
1184 err = pci_enable_device(dev);
1188 chip_id = id->device;
1190 if (chip_id == CYBERBLADEi1)
1191 output("*** Please do use cyblafb, Cyberblade/i1 support "
1192 "will soon be removed from tridentfb!\n");
1195 /* If PCI id is 0x9660 then further detect chip type */
1197 if (chip_id == TGUI9660) {
1198 outb(RevisionID, 0x3C4);
1199 revision = inb(0x3C5);
1204 chip_id = CYBER9397;
1207 chip_id = CYBER9397DVD;
1216 chip_id = CYBER9385;
1219 chip_id = CYBER9382;
1222 chip_id = CYBER9388;
1229 chip3D = is3Dchip(chip_id);
1230 chipcyber = iscyber(chip_id);
1232 if (is_xp(chip_id)) {
1234 } else if (is_blade(chip_id)) {
1240 /* acceleration is on by default for 3D chips */
1241 defaultaccel = chip3D && !noaccel;
1243 fb_info.par = &default_par;
1245 /* setup MMIO region */
1246 tridentfb_fix.mmio_start = pci_resource_start(dev, 1);
1247 tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000;
1249 if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
1250 debug("request_region failed!\n");
1254 default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1256 if (!default_par.io_virt) {
1257 debug("ioremap failed\n");
1264 /* setup framebuffer memory */
1265 tridentfb_fix.smem_start = pci_resource_start(dev, 0);
1266 tridentfb_fix.smem_len = get_memsize();
1268 if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
1269 debug("request_mem_region failed!\n");
1275 fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
1276 tridentfb_fix.smem_len);
1278 if (!fb_info.screen_base) {
1279 debug("ioremap failed\n");
1284 output("%s board found\n", pci_name(dev));
1285 displaytype = get_displaytype();
1288 nativex = get_nativex();
1290 fb_info.fix = tridentfb_fix;
1291 fb_info.fbops = &tridentfb_ops;
1294 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1295 #ifdef CONFIG_FB_TRIDENT_ACCEL
1296 fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1298 fb_info.pseudo_palette = pseudo_pal;
1300 if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) {
1304 err = fb_alloc_cmap(&fb_info.cmap, 256, 0);
1308 if (defaultaccel && acc)
1309 default_var.accel_flags |= FB_ACCELF_TEXT;
1311 default_var.accel_flags &= ~FB_ACCELF_TEXT;
1312 default_var.activate |= FB_ACTIVATE_NOW;
1313 fb_info.var = default_var;
1314 fb_info.device = &dev->dev;
1315 if (register_framebuffer(&fb_info) < 0) {
1316 printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
1317 fb_dealloc_cmap(&fb_info.cmap);
1321 output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
1322 fb_info.node, fb_info.fix.id, default_var.xres,
1323 default_var.yres, default_var.bits_per_pixel);
1327 if (fb_info.screen_base)
1328 iounmap(fb_info.screen_base);
1329 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1332 if (default_par.io_virt)
1333 iounmap(default_par.io_virt);
1334 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1338 static void __devexit trident_pci_remove(struct pci_dev *dev)
1340 struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
1341 unregister_framebuffer(&fb_info);
1342 iounmap(par->io_virt);
1343 iounmap(fb_info.screen_base);
1344 release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
1345 release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
1348 /* List of boards that we are trying to support */
1349 static struct pci_device_id trident_devices[] = {
1350 {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1351 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1352 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1353 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1354 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1355 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1356 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1357 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1358 {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1359 {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1360 {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1361 {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1362 {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1363 {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1364 {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1365 {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1366 {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1367 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1368 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1369 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1373 MODULE_DEVICE_TABLE(pci, trident_devices);
1375 static struct pci_driver tridentfb_pci_driver = {
1376 .name = "tridentfb",
1377 .id_table = trident_devices,
1378 .probe = trident_pci_probe,
1379 .remove = __devexit_p(trident_pci_remove)
1383 * Parse user specified options (`video=trident:')
1385 * video=trident:800x600,bpp=16,noaccel
1388 static int tridentfb_setup(char *options)
1391 if (!options || !*options)
1393 while ((opt = strsep(&options, ",")) != NULL) {
1396 if (!strncmp(opt, "noaccel", 7))
1398 else if (!strncmp(opt, "fp", 2))
1399 displaytype = DISPLAY_FP;
1400 else if (!strncmp(opt, "crt", 3))
1401 displaytype = DISPLAY_CRT;
1402 else if (!strncmp(opt, "bpp=", 4))
1403 bpp = simple_strtoul(opt + 4, NULL, 0);
1404 else if (!strncmp(opt, "center", 6))
1406 else if (!strncmp(opt, "stretch", 7))
1408 else if (!strncmp(opt, "memsize=", 8))
1409 memsize = simple_strtoul(opt + 8, NULL, 0);
1410 else if (!strncmp(opt, "memdiff=", 8))
1411 memdiff = simple_strtoul(opt + 8, NULL, 0);
1412 else if (!strncmp(opt, "nativex=", 8))
1413 nativex = simple_strtoul(opt + 8, NULL, 0);
1421 static int __init tridentfb_init(void)
1424 char *option = NULL;
1426 if (fb_get_options("tridentfb", &option))
1428 tridentfb_setup(option);
1430 output("Trident framebuffer %s initializing\n", VERSION);
1431 return pci_register_driver(&tridentfb_pci_driver);
1434 static void __exit tridentfb_exit(void)
1436 pci_unregister_driver(&tridentfb_pci_driver);
1439 module_init(tridentfb_init);
1440 module_exit(tridentfb_exit);
1442 MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
1443 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
1444 MODULE_LICENSE("GPL");