diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/tridentfb.c | 261 |
1 files changed, 89 insertions, 172 deletions
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 9b87c08..4a1258f 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -1,5 +1,5 @@ /* - * Frame buffer driver for Trident Blade and Image series + * Frame buffer driver for Trident TGUI, Blade and Image series * * Copyright 2001, 2002 - Jani Monoses <jani@iv.ro> * @@ -13,7 +13,6 @@ * code, suggestions * TODO: * timing value tweaking so it looks good on every monitor in every mode - * TGUI acceleration */ #include <linux/module.h> @@ -193,37 +192,13 @@ static inline u32 readmmr(struct tridentfb_par *par, u16 r) */ #define point(x, y) ((y) << 16 | (x)) -#define STA 0x2120 -#define CMD 0x2144 -#define ROP 0x2148 -#define CLR 0x2160 -#define SR1 0x2100 -#define SR2 0x2104 -#define DR1 0x2108 -#define DR2 0x210C - -#define ROP_S 0xCC static void blade_init_accel(struct tridentfb_par *par, int pitch, int bpp) { int v1 = (pitch >> 3) << 20; - int tmp = 0, v2; - switch (bpp) { - case 8: - tmp = 0; - break; - case 15: - tmp = 5; - break; - case 16: - tmp = 1; - break; - case 24: - case 32: - tmp = 2; - break; - } - v2 = v1 | (tmp << 29); + int tmp = bpp == 24 ? 2 : (bpp >> 4); + int v2 = v1 | (tmp << 29); + writemmr(par, 0x21C0, v2); writemmr(par, 0x21C4, v2); writemmr(par, 0x21B8, v2); @@ -237,29 +212,29 @@ static void blade_init_accel(struct tridentfb_par *par, int pitch, int bpp) static void blade_wait_engine(struct tridentfb_par *par) { - while (readmmr(par, STA) & 0xFA800000) ; + while (readmmr(par, STATUS) & 0xFA800000) + cpu_relax(); } static void blade_fill_rect(struct tridentfb_par *par, u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) { - writemmr(par, CLR, c); - writemmr(par, ROP, rop ? 0x66 : ROP_S); + writemmr(par, COLOR, c); + writemmr(par, ROP, rop ? ROP_X : ROP_S); writemmr(par, CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2); - writemmr(par, DR1, point(x, y)); - writemmr(par, DR2, point(x + w - 1, y + h - 1)); + writemmr(par, DST1, point(x, y)); + writemmr(par, DST2, point(x + w - 1, y + h - 1)); } static void blade_copy_rect(struct tridentfb_par *par, u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) { - u32 s1, s2, d1, d2; int direction = 2; - s1 = point(x1, y1); - s2 = point(x1 + w - 1, y1 + h - 1); - d1 = point(x2, y2); - d2 = point(x2 + w - 1, y2 + h - 1); + u32 s1 = point(x1, y1); + u32 s2 = point(x1 + w - 1, y1 + h - 1); + u32 d1 = point(x2, y2); + u32 d2 = point(x2 + w - 1, y2 + h - 1); if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) direction = 0; @@ -267,38 +242,20 @@ static void blade_copy_rect(struct tridentfb_par *par, writemmr(par, ROP, ROP_S); writemmr(par, CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction); - writemmr(par, SR1, direction ? s2 : s1); - writemmr(par, SR2, direction ? s1 : s2); - writemmr(par, DR1, direction ? d2 : d1); - writemmr(par, DR2, direction ? d1 : d2); + writemmr(par, SRC1, direction ? s2 : s1); + writemmr(par, SRC2, direction ? s1 : s2); + writemmr(par, DST1, direction ? d2 : d1); + writemmr(par, DST2, direction ? d1 : d2); } /* * BladeXP specific acceleration functions */ -#define ROP_P 0xF0 -#define masked_point(x, y) ((y & 0xffff)<<16|(x & 0xffff)) - static void xp_init_accel(struct tridentfb_par *par, int pitch, int bpp) { - int tmp = 0, v1; - unsigned char x = 0; - - switch (bpp) { - case 8: - x = 0; - break; - case 16: - x = 1; - break; - case 24: - x = 3; - break; - case 32: - x = 2; - break; - } + unsigned char x = bpp == 24 ? 3 : (bpp >> 4); + int v1 = pitch << (bpp == 24 ? 20 : (18 + x)); switch (pitch << (bpp >> 3)) { case 8192: @@ -320,22 +277,6 @@ static void xp_init_accel(struct tridentfb_par *par, int pitch, int bpp) eng_oper = x | 0x40; - switch (bpp) { - case 8: - tmp = 18; - break; - case 15: - case 16: - tmp = 19; - break; - case 24: - case 32: - tmp = 20; - break; - } - - v1 = pitch << tmp; - writemmr(par, 0x2154, v1); writemmr(par, 0x2150, v1); t_outb(par, 3, 0x2126); @@ -343,15 +284,11 @@ static void xp_init_accel(struct tridentfb_par *par, int pitch, int bpp) static void xp_wait_engine(struct tridentfb_par *par) { - int busy; int count, timeout; count = 0; timeout = 0; - for (;;) { - busy = t_inb(par, STA) & 0x80; - if (busy != 0x80) - return; + while (t_inb(par, STATUS) & 0x80) { count++; if (count == 10000000) { /* Timeout */ @@ -359,10 +296,11 @@ static void xp_wait_engine(struct tridentfb_par *par) timeout++; if (timeout == 8) { /* Reset engine */ - t_outb(par, 0x00, 0x2120); + t_outb(par, 0x00, STATUS); return; } } + cpu_relax(); } } @@ -371,10 +309,10 @@ static void xp_fill_rect(struct tridentfb_par *par, { writemmr(par, 0x2127, ROP_P); writemmr(par, 0x2158, c); - writemmr(par, 0x2128, 0x4000); - writemmr(par, 0x2140, masked_point(h, w)); - writemmr(par, 0x2138, masked_point(y, x)); - t_outb(par, 0x01, 0x2124); + writemmr(par, DRAWFL, 0x4000); + writemmr(par, OLDDIM, point(h, w)); + writemmr(par, OLDDST, point(y, x)); + t_outb(par, 0x01, OLDCMD); t_outb(par, eng_oper, 0x2125); } @@ -404,12 +342,12 @@ static void xp_copy_rect(struct tridentfb_par *par, y2_tmp = y2; } - writemmr(par, 0x2128, direction); + writemmr(par, DRAWFL, direction); t_outb(par, ROP_S, 0x2127); - writemmr(par, 0x213C, masked_point(y1_tmp, x1_tmp)); - writemmr(par, 0x2138, masked_point(y2_tmp, x2_tmp)); - writemmr(par, 0x2140, masked_point(h, w)); - t_outb(par, 0x01, 0x2124); + writemmr(par, OLDSRC, point(y1_tmp, x1_tmp)); + writemmr(par, OLDDST, point(y2_tmp, x2_tmp)); + writemmr(par, OLDDIM, point(h, w)); + t_outb(par, 0x01, OLDCMD); } /* @@ -417,22 +355,8 @@ static void xp_copy_rect(struct tridentfb_par *par, */ static void image_init_accel(struct tridentfb_par *par, int pitch, int bpp) { - int tmp = 0; - switch (bpp) { - case 8: - tmp = 0; - break; - case 15: - tmp = 5; - break; - case 16: - tmp = 1; - break; - case 24: - case 32: - tmp = 2; - break; - } + int tmp = bpp == 24 ? 2: (bpp >> 4); + writemmr(par, 0x2120, 0xF0000000); writemmr(par, 0x2120, 0x40000000 | tmp); writemmr(par, 0x2120, 0x80000000); @@ -450,7 +374,8 @@ static void image_init_accel(struct tridentfb_par *par, int pitch, int bpp) static void image_wait_engine(struct tridentfb_par *par) { - while (readmmr(par, 0x2164) & 0xF0000000) ; + while (readmmr(par, 0x2164) & 0xF0000000) + cpu_relax(); } static void image_fill_rect(struct tridentfb_par *par, @@ -461,8 +386,8 @@ static void image_fill_rect(struct tridentfb_par *par, writemmr(par, 0x2144, c); - writemmr(par, DR1, point(x, y)); - writemmr(par, DR2, point(x + w - 1, y + h - 1)); + writemmr(par, DST1, point(x, y)); + writemmr(par, DST2, point(x + w - 1, y + h - 1)); writemmr(par, 0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9); } @@ -470,12 +395,11 @@ static void image_fill_rect(struct tridentfb_par *par, static void image_copy_rect(struct tridentfb_par *par, u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) { - u32 s1, s2, d1, d2; int direction = 2; - s1 = point(x1, y1); - s2 = point(x1 + w - 1, y1 + h - 1); - d1 = point(x2, y2); - d2 = point(x2 + w - 1, y2 + h - 1); + u32 s1 = point(x1, y1); + u32 s2 = point(x1 + w - 1, y1 + h - 1); + u32 d1 = point(x2, y2); + u32 d2 = point(x2 + w - 1, y2 + h - 1); if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) direction = 0; @@ -483,10 +407,10 @@ static void image_copy_rect(struct tridentfb_par *par, writemmr(par, 0x2120, 0x80000000); writemmr(par, 0x2120, 0x90000000 | ROP_S); - writemmr(par, SR1, direction ? s2 : s1); - writemmr(par, SR2, direction ? s1 : s2); - writemmr(par, DR1, direction ? d2 : d1); - writemmr(par, DR2, direction ? d1 : d2); + writemmr(par, SRC1, direction ? s2 : s1); + writemmr(par, SRC2, direction ? s1 : s2); + writemmr(par, DST1, direction ? d2 : d1); + writemmr(par, DST2, direction ? d1 : d2); writemmr(par, 0x2124, 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction); } @@ -497,27 +421,12 @@ static void image_copy_rect(struct tridentfb_par *par, static void tgui_init_accel(struct tridentfb_par *par, int pitch, int bpp) { - unsigned char x = 0; + unsigned char x = bpp == 24 ? 3 : (bpp >> 4); /* disable clipping */ writemmr(par, 0x2148, 0); writemmr(par, 0x214C, point(4095, 2047)); - switch (bpp) { - case 8: - x = 0; - break; - case 16: - x = 1; - break; - case 24: - x = 3; - break; - case 32: - x = 2; - break; - } - switch ((pitch * bpp) / 8) { case 8192: case 512: @@ -541,11 +450,11 @@ static void tgui_fill_rect(struct tridentfb_par *par, u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) { t_outb(par, ROP_P, 0x2127); - writemmr(par, 0x212c, c); - writemmr(par, 0x2128, 0x4020); - writemmr(par, 0x2140, point(w - 1, h - 1)); - writemmr(par, 0x2138, point(x, y)); - t_outb(par, 1, 0x2124); + writemmr(par, OLDCLR, c); + writemmr(par, DRAWFL, 0x4020); + writemmr(par, OLDDIM, point(w - 1, h - 1)); + writemmr(par, OLDDST, point(x, y)); + t_outb(par, 1, OLDCMD); } static void tgui_copy_rect(struct tridentfb_par *par, @@ -572,12 +481,12 @@ static void tgui_copy_rect(struct tridentfb_par *par, y2_tmp = y2; } - writemmr(par, 0x2128, 0x4 | flags); + writemmr(par, DRAWFL, 0x4 | flags); t_outb(par, ROP_S, 0x2127); - writemmr(par, 0x213C, point(x1_tmp, y1_tmp)); - writemmr(par, 0x2138, point(x2_tmp, y2_tmp)); - writemmr(par, 0x2140, point(w - 1, h - 1)); - t_outb(par, 1, 0x2124); + writemmr(par, OLDSRC, point(x1_tmp, y1_tmp)); + writemmr(par, OLDDST, point(x2_tmp, y2_tmp)); + writemmr(par, OLDDIM, point(w - 1, h - 1)); + t_outb(par, 1, OLDCMD); } /* @@ -588,37 +497,40 @@ static void tridentfb_fillrect(struct fb_info *info, const struct fb_fillrect *fr) { struct tridentfb_par *par = info->par; - int bpp = info->var.bits_per_pixel; - int col = 0; + int col; - switch (bpp) { - default: - case 8: - col |= fr->color; + if (info->var.bits_per_pixel == 8) { + col = fr->color; col |= col << 8; col |= col << 16; - break; - case 16: - col = ((u32 *)(info->pseudo_palette))[fr->color]; - break; - case 32: + } else col = ((u32 *)(info->pseudo_palette))[fr->color]; - break; - } + par->wait_engine(par); par->fill_rect(par, fr->dx, fr->dy, fr->width, fr->height, col, fr->rop); - par->wait_engine(par); } + static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *ca) { struct tridentfb_par *par = info->par; + par->wait_engine(par); par->copy_rect(par, ca->sx, ca->sy, ca->dx, ca->dy, ca->width, ca->height); +} + +static int tridentfb_sync(struct fb_info *info) +{ + struct tridentfb_par *par = info->par; + par->wait_engine(par); + return 0; } +#else +#define tridentfb_fillrect cfb_fillrect +#define tridentfb_copyarea cfb_copyarea #endif /* CONFIG_FB_TRIDENT_ACCEL */ /* @@ -921,6 +833,8 @@ static int tridentfb_check_var(struct fb_var_screeninfo *var, /* check color depth */ if (bpp == 24) bpp = var->bits_per_pixel = 32; + if (bpp != 8 && bpp != 16 && bpp != 32) + return -EINVAL; if (par->chip_id == TGUI9440 && bpp == 32) return -EINVAL; /* check whether resolution fits on panel and in memory */ @@ -928,8 +842,15 @@ static int tridentfb_check_var(struct fb_var_screeninfo *var, return -EINVAL; /* various resolution checks */ var->xres = (var->xres + 7) & ~0x7; - if (var->xres != var->xres_virtual) + if (var->xres > var->xres_virtual) var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual) + var->yres_virtual = var->yres; + if (var->xres_virtual > 4095 || var->yres > 2048) + return -EINVAL; + /* prevent from position overflow for acceleration */ + if (var->yres_virtual > 0xffff) + return -EINVAL; line_length = var->xres_virtual * bpp / 8; #ifdef CONFIG_FB_TRIDENT_ACCEL if (!is3Dchip(par->chip_id)) { @@ -944,6 +865,8 @@ static int tridentfb_check_var(struct fb_var_screeninfo *var, var->xres_virtual = 4096 * 8 / bpp; else if (line_length <= 8192) var->xres_virtual = 8192 * 8 / bpp; + else + return -EINVAL; line_length = var->xres_virtual * bpp / 8; } @@ -1229,9 +1152,6 @@ static int tridentfb_set_par(struct fb_info *info) case 8: tmp = 0; break; - case 15: - tmp = 0x10; - break; case 16: tmp = 0x30; break; @@ -1352,10 +1272,11 @@ static struct fb_ops tridentfb_ops = { .fb_blank = tridentfb_blank, .fb_check_var = tridentfb_check_var, .fb_set_par = tridentfb_set_par, -#ifdef CONFIG_FB_TRIDENT_ACCEL .fb_fillrect = tridentfb_fillrect, .fb_copyarea = tridentfb_copyarea, .fb_imageblit = cfb_imageblit, +#ifdef CONFIG_FB_TRIDENT_ACCEL + .fb_sync = tridentfb_sync, #endif }; @@ -1366,7 +1287,6 @@ static int __devinit trident_pci_probe(struct pci_dev *dev, unsigned char revision; struct fb_info *info; struct tridentfb_par *default_par; - int defaultaccel; int chip3D; int chip_id; @@ -1448,9 +1368,6 @@ static int __devinit trident_pci_probe(struct pci_dev *dev, default_par->chip_id = chip_id; - /* acceleration is on by default for 3D chips */ - defaultaccel = chip3D && !noaccel; - /* setup MMIO region */ tridentfb_fix.mmio_start = pci_resource_start(dev, 1); tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000; @@ -1515,7 +1432,7 @@ static int __devinit trident_pci_probe(struct pci_dev *dev, if (err < 0) goto out_unmap2; - if (defaultaccel && default_par->init_accel) + if (!noaccel && default_par->init_accel) info->var.accel_flags |= FB_ACCELF_TEXT; else info->var.accel_flags &= ~FB_ACCELF_TEXT; |