diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index ed1b32a1cef5..9b87c08e517d 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -491,6 +491,95 @@ static void image_copy_rect(struct tridentfb_par *par, 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction); } +/* + * TGUI 9440/96XX acceleration + */ + +static void tgui_init_accel(struct tridentfb_par *par, int pitch, int bpp) +{ + unsigned char x = 0; + + /* 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: + x |= 0x00; + break; + case 1024: + x |= 0x04; + break; + case 2048: + x |= 0x08; + break; + case 4096: + x |= 0x0C; + break; + } + + fb_writew(x, par->io_virt + 0x2122); +} + +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); +} + +static void tgui_copy_rect(struct tridentfb_par *par, + u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) +{ + int flags = 0; + u16 x1_tmp, x2_tmp, y1_tmp, y2_tmp; + + if ((x1 < x2) && (y1 == y2)) { + flags |= 0x0200; + x1_tmp = x1 + w - 1; + x2_tmp = x2 + w - 1; + } else { + x1_tmp = x1; + x2_tmp = x2; + } + + if (y1 < y2) { + flags |= 0x0100; + y1_tmp = y1 + h - 1; + y2_tmp = y2 + h - 1; + } else { + y1_tmp = y1; + y2_tmp = y2; + } + + writemmr(par, 0x2128, 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); +} + /* * Accel functions called by the upper layers */ @@ -530,12 +619,8 @@ static void tridentfb_copyarea(struct fb_info *info, ca->width, ca->height); par->wait_engine(par); } -#else /* !CONFIG_FB_TRIDENT_ACCEL */ -#define tridentfb_fillrect cfb_fillrect -#define tridentfb_copyarea cfb_copyarea #endif /* CONFIG_FB_TRIDENT_ACCEL */ - /* * Hardware access functions */ @@ -829,6 +914,7 @@ static int tridentfb_check_var(struct fb_var_screeninfo *var, { struct tridentfb_par *par = info->par; int bpp = var->bits_per_pixel; + int line_length; int ramdac = 230000; /* 230MHz for most 3D chips */ debug("enter\n"); @@ -844,9 +930,27 @@ static int tridentfb_check_var(struct fb_var_screeninfo *var, var->xres = (var->xres + 7) & ~0x7; if (var->xres != var->xres_virtual) var->xres_virtual = var->xres; + line_length = var->xres_virtual * bpp / 8; +#ifdef CONFIG_FB_TRIDENT_ACCEL + if (!is3Dchip(par->chip_id)) { + /* acceleration requires line length to be power of 2 */ + if (line_length <= 512) + var->xres_virtual = 512 * 8 / bpp; + else if (line_length <= 1024) + var->xres_virtual = 1024 * 8 / bpp; + else if (line_length <= 2048) + var->xres_virtual = 2048 * 8 / bpp; + else if (line_length <= 4096) + var->xres_virtual = 4096 * 8 / bpp; + else if (line_length <= 8192) + var->xres_virtual = 8192 * 8 / bpp; + + line_length = var->xres_virtual * bpp / 8; + } +#endif if (var->yres > var->yres_virtual) var->yres_virtual = var->yres; - if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len) + if (line_length * var->yres_virtual > info->fix.smem_len) return -EINVAL; switch (bpp) { @@ -918,7 +1022,7 @@ static int tridentfb_pan_display(struct fb_var_screeninfo *var, unsigned int offset; debug("enter\n"); - offset = (var->xoffset + (var->yoffset * var->xres)) + offset = (var->xoffset + (var->yoffset * var->xres_virtual)) * var->bits_per_pixel / 32; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; @@ -1049,7 +1153,7 @@ static int tridentfb_set_par(struct fb_info *info) write3X4(par, GraphEngReg, 0x80); #ifdef CONFIG_FB_TRIDENT_ACCEL - par->init_accel(par, info->var.xres, bpp); + par->init_accel(par, info->var.xres_virtual, bpp); #endif switch (bpp) { @@ -1147,9 +1251,9 @@ static int tridentfb_set_par(struct fb_info *info) if (par->flatpanel) set_number_of_lines(par, info->var.yres); - set_lwidth(par, info->var.xres * bpp / (4 * 16)); + info->fix.line_length = info->var.xres_virtual * bpp / 8; + set_lwidth(par, info->fix.line_length / 8); info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - info->fix.line_length = info->var.xres * (bpp >> 3); info->cmap.len = (bpp == 8) ? 256 : 16; debug("exit\n"); return 0; @@ -1248,9 +1352,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, +#endif }; static int __devinit trident_pci_probe(struct pci_dev *dev, @@ -1328,11 +1434,16 @@ static int __devinit trident_pci_probe(struct pci_dev *dev, default_par->wait_engine = blade_wait_engine; default_par->fill_rect = blade_fill_rect; default_par->copy_rect = blade_copy_rect; - } else { + } else if (chip3D) { /* 3DImage family left */ default_par->init_accel = image_init_accel; default_par->wait_engine = image_wait_engine; default_par->fill_rect = image_fill_rect; default_par->copy_rect = image_copy_rect; + } else { /* TGUI 9440/96XX family */ + default_par->init_accel = tgui_init_accel; + default_par->wait_engine = xp_wait_engine; + default_par->fill_rect = tgui_fill_rect; + default_par->copy_rect = tgui_copy_rect; } default_par->chip_id = chip_id; @@ -1359,12 +1470,12 @@ static int __devinit trident_pci_probe(struct pci_dev *dev, goto out_unmap1; } + enable_mmio(); + /* setup framebuffer memory */ tridentfb_fix.smem_start = pci_resource_start(dev, 0); tridentfb_fix.smem_len = get_memsize(default_par); - enable_mmio(); - if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) { debug("request_mem_region failed!\n"); disable_mmio(info->par);