Commit 92744dd5 authored by Krzysztof Helt's avatar Krzysztof Helt Committed by Linus Torvalds

tdfxfb: 3 fixes

This patch fixes 3 issues:
- transparency handling in tdfxfb
- panning with more than 4096 virtual height and acceleration (acceleration
with x & y > 4096)
- exit paths on errors in tdfxfb_probe()

Additionally it sets a FBINFO_READS_FAST flag to use smart blitter scrolling
(speed up on tdfxfb).
Signed-off-by: default avatarKrzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: default avatarAntonino Daplas <adaplas@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8af1d50f
...@@ -502,6 +502,8 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -502,6 +502,8 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
return -EINVAL; return -EINVAL;
} }
var->transp.offset = 0;
var->transp.length = 0;
switch (var->bits_per_pixel) { switch (var->bits_per_pixel) {
case 8: case 8:
var->red.length = var->green.length = var->blue.length = 8; var->red.length = var->green.length = var->blue.length = 8;
...@@ -515,10 +517,12 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -515,10 +517,12 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->blue.length = 5; var->blue.length = 5;
break; break;
case 32: case 32:
var->transp.offset = 24;
var->transp.length = 8;
case 24: case 24:
var->red.offset=16; var->red.offset = 16;
var->green.offset=8; var->green.offset = 8;
var->blue.offset=0; var->blue.offset = 0;
var->red.length = var->green.length = var->blue.length = 8; var->red.length = var->green.length = var->blue.length = 8;
break; break;
} }
...@@ -874,13 +878,26 @@ static void tdfxfb_fillrect(struct fb_info *info, ...@@ -874,13 +878,26 @@ static void tdfxfb_fillrect(struct fb_info *info,
u32 stride = info->fix.line_length; u32 stride = info->fix.line_length;
u32 fmt= stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); u32 fmt= stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
int tdfx_rop; int tdfx_rop;
u32 dx = rect->dx;
u32 dy = rect->dy;
u32 dstbase = 0;
if (rect->rop == ROP_COPY) if (rect->rop == ROP_COPY)
tdfx_rop = TDFX_ROP_COPY; tdfx_rop = TDFX_ROP_COPY;
else else
tdfx_rop = TDFX_ROP_XOR; tdfx_rop = TDFX_ROP_XOR;
banshee_make_room(par, 5); /* asume always rect->height < 4096 */
if (dy + rect->height > 4095) {
dstbase = stride * dy;
dy = 0;
}
/* asume always rect->width < 4096 */
if (dx + rect->width > 4095) {
dstbase += dx * bpp >> 3;
dx = 0;
}
banshee_make_room(par, 6);
tdfx_outl(par, DSTFORMAT, fmt); tdfx_outl(par, DSTFORMAT, fmt);
if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
tdfx_outl(par, COLORFORE, rect->color); tdfx_outl(par, COLORFORE, rect->color);
...@@ -888,8 +905,9 @@ static void tdfxfb_fillrect(struct fb_info *info, ...@@ -888,8 +905,9 @@ static void tdfxfb_fillrect(struct fb_info *info,
tdfx_outl(par, COLORFORE, par->palette[rect->color]); tdfx_outl(par, COLORFORE, par->palette[rect->color]);
} }
tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24)); tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));
tdfx_outl(par, DSTBASE, dstbase);
tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16)); tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16));
tdfx_outl(par, LAUNCH_2D, rect->dx | (rect->dy << 16)); tdfx_outl(par, LAUNCH_2D, dx | (dy << 16));
} }
/* /*
...@@ -904,6 +922,30 @@ static void tdfxfb_copyarea(struct fb_info *info, ...@@ -904,6 +922,30 @@ static void tdfxfb_copyarea(struct fb_info *info,
u32 stride = info->fix.line_length; u32 stride = info->fix.line_length;
u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24); u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
u32 dstbase = 0;
u32 srcbase = 0;
/* asume always area->height < 4096 */
if (sy + area->height > 4095) {
srcbase = stride * sy;
sy = 0;
}
/* asume always area->width < 4096 */
if (sx + area->width > 4095) {
srcbase += sx * bpp >> 3;
sx = 0;
}
/* asume always area->height < 4096 */
if (dy + area->height > 4095) {
dstbase = stride * dy;
dy = 0;
}
/* asume always area->width < 4096 */
if (dx + area->width > 4095) {
dstbase += dx * bpp >> 3;
dx = 0;
}
if (area->sx <= area->dx) { if (area->sx <= area->dx) {
//-X //-X
...@@ -918,13 +960,15 @@ static void tdfxfb_copyarea(struct fb_info *info, ...@@ -918,13 +960,15 @@ static void tdfxfb_copyarea(struct fb_info *info,
dy += area->height - 1; dy += area->height - 1;
} }
banshee_make_room(par, 6); banshee_make_room(par, 8);
tdfx_outl(par, SRCFORMAT, fmt); tdfx_outl(par, SRCFORMAT, fmt);
tdfx_outl(par, DSTFORMAT, fmt); tdfx_outl(par, DSTFORMAT, fmt);
tdfx_outl(par, COMMAND_2D, blitcmd); tdfx_outl(par, COMMAND_2D, blitcmd);
tdfx_outl(par, DSTSIZE, area->width | (area->height << 16)); tdfx_outl(par, DSTSIZE, area->width | (area->height << 16));
tdfx_outl(par, DSTXY, dx | (dy << 16)); tdfx_outl(par, DSTXY, dx | (dy << 16));
tdfx_outl(par, SRCBASE, srcbase);
tdfx_outl(par, DSTBASE, dstbase);
tdfx_outl(par, LAUNCH_2D, sx | (sy << 16)); tdfx_outl(par, LAUNCH_2D, sx | (sy << 16));
} }
...@@ -938,14 +982,17 @@ static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) ...@@ -938,14 +982,17 @@ static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image)
u32 dstfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); u32 dstfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
u8 *chardata = (u8 *) image->data; u8 *chardata = (u8 *) image->data;
u32 srcfmt; u32 srcfmt;
u32 dx = image->dx;
u32 dy = image->dy;
u32 dstbase = 0;
if (image->depth != 1) { if (image->depth != 1) {
//banshee_make_room(par, 6 + ((size + 3) >> 2)); //banshee_make_room(par, 6 + ((size + 3) >> 2));
//srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000; //srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000;
cfb_imageblit(info, image); cfb_imageblit(info, image);
return; return;
} else { }
banshee_make_room(par, 8); banshee_make_room(par, 9);
switch (info->fix.visual) { switch (info->fix.visual) {
case FB_VISUAL_PSEUDOCOLOR: case FB_VISUAL_PSEUDOCOLOR:
tdfx_outl(par, COLORFORE, image->fg_color); tdfx_outl(par, COLORFORE, image->fg_color);
...@@ -963,10 +1010,20 @@ static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) ...@@ -963,10 +1010,20 @@ static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image)
#else #else
srcfmt = 0x400000; srcfmt = 0x400000;
#endif #endif
/* asume always image->height < 4096 */
if (dy + image->height > 4095) {
dstbase = stride * dy;
dy = 0;
}
/* asume always image->width < 4096 */
if (dx + image->width > 4095) {
dstbase += dx * bpp >> 3;
dx = 0;
} }
tdfx_outl(par, DSTBASE, dstbase);
tdfx_outl(par, SRCXY, 0); tdfx_outl(par, SRCXY, 0);
tdfx_outl(par, DSTXY, image->dx | (image->dy << 16)); tdfx_outl(par, DSTXY, dx | (dy << 16));
tdfx_outl(par, COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24)); tdfx_outl(par, COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
tdfx_outl(par, SRCFORMAT, srcfmt); tdfx_outl(par, SRCFORMAT, srcfmt);
tdfx_outl(par, DSTFORMAT, dstfmt); tdfx_outl(par, DSTFORMAT, dstfmt);
...@@ -1211,44 +1268,36 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, ...@@ -1211,44 +1268,36 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
tdfx_fix.mmio_start = pci_resource_start(pdev, 0); tdfx_fix.mmio_start = pci_resource_start(pdev, 0);
tdfx_fix.mmio_len = pci_resource_len(pdev, 0); tdfx_fix.mmio_len = pci_resource_len(pdev, 0);
if (!request_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len,
"tdfx regbase")) {
printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n");
goto out_err;
}
default_par->regbase_virt = default_par->regbase_virt =
ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len); ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
if (!default_par->regbase_virt) { if (!default_par->regbase_virt) {
printk("fb: Can't remap %s register area.\n", tdfx_fix.id); printk("fb: Can't remap %s register area.\n", tdfx_fix.id);
goto out_err; goto out_err_regbase;
}
if (!request_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0), "tdfx regbase")) {
printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n");
goto out_err;
} }
tdfx_fix.smem_start = pci_resource_start(pdev, 1); tdfx_fix.smem_start = pci_resource_start(pdev, 1);
if (!(tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device))) { if (!(tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device))) {
printk("fb: Can't count %s memory.\n", tdfx_fix.id); printk("fb: Can't count %s memory.\n", tdfx_fix.id);
release_mem_region(pci_resource_start(pdev, 0), goto out_err_regbase;
pci_resource_len(pdev, 0));
goto out_err;
} }
if (!request_mem_region(pci_resource_start(pdev, 1), if (!request_mem_region(tdfx_fix.smem_start,
pci_resource_len(pdev, 1), "tdfx smem")) { pci_resource_len(pdev, 1), "tdfx smem")) {
printk(KERN_WARNING "tdfxfb: Can't reserve smem\n"); printk(KERN_WARNING "tdfxfb: Can't reserve smem\n");
release_mem_region(pci_resource_start(pdev, 0), goto out_err_regbase;
pci_resource_len(pdev, 0));
goto out_err;
} }
info->screen_base = ioremap_nocache(tdfx_fix.smem_start, info->screen_base = ioremap_nocache(tdfx_fix.smem_start,
tdfx_fix.smem_len); tdfx_fix.smem_len);
if (!info->screen_base) { if (!info->screen_base) {
printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id); printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id);
release_mem_region(pci_resource_start(pdev, 1), goto out_err_screenbase;
pci_resource_len(pdev, 1));
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
goto out_err;
} }
default_par->iobase = pci_resource_start(pdev, 2); default_par->iobase = pci_resource_start(pdev, 2);
...@@ -1256,11 +1305,7 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, ...@@ -1256,11 +1305,7 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
if (!request_region(pci_resource_start(pdev, 2), if (!request_region(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2), "tdfx iobase")) { pci_resource_len(pdev, 2), "tdfx iobase")) {
printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n"); printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n");
release_mem_region(pci_resource_start(pdev, 1), goto out_err_screenbase;
pci_resource_len(pdev, 1));
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
goto out_err;
} }
printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10); printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10);
...@@ -1274,7 +1319,9 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, ...@@ -1274,7 +1319,9 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
#ifdef CONFIG_FB_3DFX_ACCEL #ifdef CONFIG_FB_3DFX_ACCEL
info->flags |= FBINFO_HWACCEL_FILLRECT | info->flags |= FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_IMAGEBLIT; FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_READS_FAST;
#endif #endif
if (!mode_option) if (!mode_option)
...@@ -1288,27 +1335,17 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, ...@@ -1288,27 +1335,17 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3);
info->var.yres_virtual = info->fix.smem_len / lpitch; info->var.yres_virtual = info->fix.smem_len / lpitch;
if (info->var.yres_virtual < info->var.yres) if (info->var.yres_virtual < info->var.yres)
goto out_err; goto out_err_iobase;
#ifdef CONFIG_FB_3DFX_ACCEL
/*
* FIXME: Limit var->yres_virtual to 4096 because of screen artifacts
* during scrolling. This is only present if 2D acceleration is
* enabled.
*/
if (info->var.yres_virtual > 4096)
info->var.yres_virtual = 4096;
#endif /* CONFIG_FB_3DFX_ACCEL */
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
printk(KERN_WARNING "tdfxfb: Can't allocate color map\n"); printk(KERN_WARNING "tdfxfb: Can't allocate color map\n");
goto out_err; goto out_err_iobase;
} }
if (register_framebuffer(info) < 0) { if (register_framebuffer(info) < 0) {
printk("tdfxfb: can't register framebuffer\n"); printk("tdfxfb: can't register framebuffer\n");
fb_dealloc_cmap(&info->cmap); fb_dealloc_cmap(&info->cmap);
goto out_err; goto out_err_iobase;
} }
/* /*
* Our driver data * Our driver data
...@@ -1316,14 +1353,21 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, ...@@ -1316,14 +1353,21 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, info); pci_set_drvdata(pdev, info);
return 0; return 0;
out_err: out_err_iobase:
release_mem_region(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2));
out_err_screenbase:
if (info->screen_base)
iounmap(info->screen_base);
release_mem_region(tdfx_fix.smem_start, pci_resource_len(pdev, 1));
out_err_regbase:
/* /*
* Cleanup after anything that was remapped/allocated. * Cleanup after anything that was remapped/allocated.
*/ */
if (default_par->regbase_virt) if (default_par->regbase_virt)
iounmap(default_par->regbase_virt); iounmap(default_par->regbase_virt);
if (info->screen_base) release_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
iounmap(info->screen_base); out_err:
framebuffer_release(info); framebuffer_release(info);
return -ENXIO; return -ENXIO;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment