diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2007-10-16 04:28:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:15 -0400 |
commit | 92744dd517258181af0637105eed5f72d95e05e7 (patch) | |
tree | 5917dfd6b65813e6d2901f99265ee7e5f3f08052 /drivers | |
parent | 8af1d50f7f679375f579782f2d5eb5e2a1508df8 (diff) |
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: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Antonino Daplas <adaplas@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/tdfxfb.c | 172 |
1 files changed, 108 insertions, 64 deletions
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index e6aced9df52d..2566683cbfef 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c | |||
@@ -502,6 +502,8 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
502 | return -EINVAL; | 502 | return -EINVAL; |
503 | } | 503 | } |
504 | 504 | ||
505 | var->transp.offset = 0; | ||
506 | var->transp.length = 0; | ||
505 | switch (var->bits_per_pixel) { | 507 | switch (var->bits_per_pixel) { |
506 | case 8: | 508 | case 8: |
507 | var->red.length = var->green.length = var->blue.length = 8; | 509 | 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 | var->blue.length = 5; | 517 | var->blue.length = 5; |
516 | break; | 518 | break; |
517 | case 32: | 519 | case 32: |
520 | var->transp.offset = 24; | ||
521 | var->transp.length = 8; | ||
518 | case 24: | 522 | case 24: |
519 | var->red.offset=16; | 523 | var->red.offset = 16; |
520 | var->green.offset=8; | 524 | var->green.offset = 8; |
521 | var->blue.offset=0; | 525 | var->blue.offset = 0; |
522 | var->red.length = var->green.length = var->blue.length = 8; | 526 | var->red.length = var->green.length = var->blue.length = 8; |
523 | break; | 527 | break; |
524 | } | 528 | } |
@@ -874,13 +878,26 @@ static void tdfxfb_fillrect(struct fb_info *info, | |||
874 | u32 stride = info->fix.line_length; | 878 | u32 stride = info->fix.line_length; |
875 | u32 fmt= stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); | 879 | u32 fmt= stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); |
876 | int tdfx_rop; | 880 | int tdfx_rop; |
881 | u32 dx = rect->dx; | ||
882 | u32 dy = rect->dy; | ||
883 | u32 dstbase = 0; | ||
877 | 884 | ||
878 | if (rect->rop == ROP_COPY) | 885 | if (rect->rop == ROP_COPY) |
879 | tdfx_rop = TDFX_ROP_COPY; | 886 | tdfx_rop = TDFX_ROP_COPY; |
880 | else | 887 | else |
881 | tdfx_rop = TDFX_ROP_XOR; | 888 | tdfx_rop = TDFX_ROP_XOR; |
882 | 889 | ||
883 | banshee_make_room(par, 5); | 890 | /* asume always rect->height < 4096 */ |
891 | if (dy + rect->height > 4095) { | ||
892 | dstbase = stride * dy; | ||
893 | dy = 0; | ||
894 | } | ||
895 | /* asume always rect->width < 4096 */ | ||
896 | if (dx + rect->width > 4095) { | ||
897 | dstbase += dx * bpp >> 3; | ||
898 | dx = 0; | ||
899 | } | ||
900 | banshee_make_room(par, 6); | ||
884 | tdfx_outl(par, DSTFORMAT, fmt); | 901 | tdfx_outl(par, DSTFORMAT, fmt); |
885 | if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { | 902 | if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { |
886 | tdfx_outl(par, COLORFORE, rect->color); | 903 | tdfx_outl(par, COLORFORE, rect->color); |
@@ -888,8 +905,9 @@ static void tdfxfb_fillrect(struct fb_info *info, | |||
888 | tdfx_outl(par, COLORFORE, par->palette[rect->color]); | 905 | tdfx_outl(par, COLORFORE, par->palette[rect->color]); |
889 | } | 906 | } |
890 | tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24)); | 907 | tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24)); |
908 | tdfx_outl(par, DSTBASE, dstbase); | ||
891 | tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16)); | 909 | tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16)); |
892 | tdfx_outl(par, LAUNCH_2D, rect->dx | (rect->dy << 16)); | 910 | tdfx_outl(par, LAUNCH_2D, dx | (dy << 16)); |
893 | } | 911 | } |
894 | 912 | ||
895 | /* | 913 | /* |
@@ -904,6 +922,30 @@ static void tdfxfb_copyarea(struct fb_info *info, | |||
904 | u32 stride = info->fix.line_length; | 922 | u32 stride = info->fix.line_length; |
905 | u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24); | 923 | u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24); |
906 | u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); | 924 | u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); |
925 | u32 dstbase = 0; | ||
926 | u32 srcbase = 0; | ||
927 | |||
928 | /* asume always area->height < 4096 */ | ||
929 | if (sy + area->height > 4095) { | ||
930 | srcbase = stride * sy; | ||
931 | sy = 0; | ||
932 | } | ||
933 | /* asume always area->width < 4096 */ | ||
934 | if (sx + area->width > 4095) { | ||
935 | srcbase += sx * bpp >> 3; | ||
936 | sx = 0; | ||
937 | } | ||
938 | /* asume always area->height < 4096 */ | ||
939 | if (dy + area->height > 4095) { | ||
940 | dstbase = stride * dy; | ||
941 | dy = 0; | ||
942 | } | ||
943 | /* asume always area->width < 4096 */ | ||
944 | if (dx + area->width > 4095) { | ||
945 | dstbase += dx * bpp >> 3; | ||
946 | dx = 0; | ||
947 | } | ||
948 | |||
907 | 949 | ||
908 | if (area->sx <= area->dx) { | 950 | if (area->sx <= area->dx) { |
909 | //-X | 951 | //-X |
@@ -918,13 +960,15 @@ static void tdfxfb_copyarea(struct fb_info *info, | |||
918 | dy += area->height - 1; | 960 | dy += area->height - 1; |
919 | } | 961 | } |
920 | 962 | ||
921 | banshee_make_room(par, 6); | 963 | banshee_make_room(par, 8); |
922 | 964 | ||
923 | tdfx_outl(par, SRCFORMAT, fmt); | 965 | tdfx_outl(par, SRCFORMAT, fmt); |
924 | tdfx_outl(par, DSTFORMAT, fmt); | 966 | tdfx_outl(par, DSTFORMAT, fmt); |
925 | tdfx_outl(par, COMMAND_2D, blitcmd); | 967 | tdfx_outl(par, COMMAND_2D, blitcmd); |
926 | tdfx_outl(par, DSTSIZE, area->width | (area->height << 16)); | 968 | tdfx_outl(par, DSTSIZE, area->width | (area->height << 16)); |
927 | tdfx_outl(par, DSTXY, dx | (dy << 16)); | 969 | tdfx_outl(par, DSTXY, dx | (dy << 16)); |
970 | tdfx_outl(par, SRCBASE, srcbase); | ||
971 | tdfx_outl(par, DSTBASE, dstbase); | ||
928 | tdfx_outl(par, LAUNCH_2D, sx | (sy << 16)); | 972 | tdfx_outl(par, LAUNCH_2D, sx | (sy << 16)); |
929 | } | 973 | } |
930 | 974 | ||
@@ -938,35 +982,48 @@ static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
938 | u32 dstfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); | 982 | u32 dstfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); |
939 | u8 *chardata = (u8 *) image->data; | 983 | u8 *chardata = (u8 *) image->data; |
940 | u32 srcfmt; | 984 | u32 srcfmt; |
985 | u32 dx = image->dx; | ||
986 | u32 dy = image->dy; | ||
987 | u32 dstbase = 0; | ||
941 | 988 | ||
942 | if (image->depth != 1) { | 989 | if (image->depth != 1) { |
943 | //banshee_make_room(par, 6 + ((size + 3) >> 2)); | 990 | //banshee_make_room(par, 6 + ((size + 3) >> 2)); |
944 | //srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000; | 991 | //srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000; |
945 | cfb_imageblit(info, image); | 992 | cfb_imageblit(info, image); |
946 | return; | 993 | return; |
947 | } else { | 994 | } |
948 | banshee_make_room(par, 8); | 995 | banshee_make_room(par, 9); |
949 | switch (info->fix.visual) { | 996 | switch (info->fix.visual) { |
950 | case FB_VISUAL_PSEUDOCOLOR: | 997 | case FB_VISUAL_PSEUDOCOLOR: |
951 | tdfx_outl(par, COLORFORE, image->fg_color); | 998 | tdfx_outl(par, COLORFORE, image->fg_color); |
952 | tdfx_outl(par, COLORBACK, image->bg_color); | 999 | tdfx_outl(par, COLORBACK, image->bg_color); |
953 | break; | 1000 | break; |
954 | case FB_VISUAL_TRUECOLOR: | 1001 | case FB_VISUAL_TRUECOLOR: |
955 | default: | 1002 | default: |
956 | tdfx_outl(par, COLORFORE, | 1003 | tdfx_outl(par, COLORFORE, |
957 | par->palette[image->fg_color]); | 1004 | par->palette[image->fg_color]); |
958 | tdfx_outl(par, COLORBACK, | 1005 | tdfx_outl(par, COLORBACK, |
959 | par->palette[image->bg_color]); | 1006 | par->palette[image->bg_color]); |
960 | } | 1007 | } |
961 | #ifdef __BIG_ENDIAN | 1008 | #ifdef __BIG_ENDIAN |
962 | srcfmt = 0x400000 | BIT(20); | 1009 | srcfmt = 0x400000 | BIT(20); |
963 | #else | 1010 | #else |
964 | srcfmt = 0x400000; | 1011 | srcfmt = 0x400000; |
965 | #endif | 1012 | #endif |
1013 | /* asume always image->height < 4096 */ | ||
1014 | if (dy + image->height > 4095) { | ||
1015 | dstbase = stride * dy; | ||
1016 | dy = 0; | ||
1017 | } | ||
1018 | /* asume always image->width < 4096 */ | ||
1019 | if (dx + image->width > 4095) { | ||
1020 | dstbase += dx * bpp >> 3; | ||
1021 | dx = 0; | ||
966 | } | 1022 | } |
967 | 1023 | ||
1024 | tdfx_outl(par, DSTBASE, dstbase); | ||
968 | tdfx_outl(par, SRCXY, 0); | 1025 | tdfx_outl(par, SRCXY, 0); |
969 | tdfx_outl(par, DSTXY, image->dx | (image->dy << 16)); | 1026 | tdfx_outl(par, DSTXY, dx | (dy << 16)); |
970 | tdfx_outl(par, COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24)); | 1027 | tdfx_outl(par, COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24)); |
971 | tdfx_outl(par, SRCFORMAT, srcfmt); | 1028 | tdfx_outl(par, SRCFORMAT, srcfmt); |
972 | tdfx_outl(par, DSTFORMAT, dstfmt); | 1029 | tdfx_outl(par, DSTFORMAT, dstfmt); |
@@ -1211,44 +1268,36 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, | |||
1211 | 1268 | ||
1212 | tdfx_fix.mmio_start = pci_resource_start(pdev, 0); | 1269 | tdfx_fix.mmio_start = pci_resource_start(pdev, 0); |
1213 | tdfx_fix.mmio_len = pci_resource_len(pdev, 0); | 1270 | tdfx_fix.mmio_len = pci_resource_len(pdev, 0); |
1271 | if (!request_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len, | ||
1272 | "tdfx regbase")) { | ||
1273 | printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n"); | ||
1274 | goto out_err; | ||
1275 | } | ||
1276 | |||
1214 | default_par->regbase_virt = | 1277 | default_par->regbase_virt = |
1215 | ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len); | 1278 | ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len); |
1216 | if (!default_par->regbase_virt) { | 1279 | if (!default_par->regbase_virt) { |
1217 | printk("fb: Can't remap %s register area.\n", tdfx_fix.id); | 1280 | printk("fb: Can't remap %s register area.\n", tdfx_fix.id); |
1218 | goto out_err; | 1281 | goto out_err_regbase; |
1219 | } | ||
1220 | |||
1221 | if (!request_mem_region(pci_resource_start(pdev, 0), | ||
1222 | pci_resource_len(pdev, 0), "tdfx regbase")) { | ||
1223 | printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n"); | ||
1224 | goto out_err; | ||
1225 | } | 1282 | } |
1226 | 1283 | ||
1227 | tdfx_fix.smem_start = pci_resource_start(pdev, 1); | 1284 | tdfx_fix.smem_start = pci_resource_start(pdev, 1); |
1228 | if (!(tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device))) { | 1285 | if (!(tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device))) { |
1229 | printk("fb: Can't count %s memory.\n", tdfx_fix.id); | 1286 | printk("fb: Can't count %s memory.\n", tdfx_fix.id); |
1230 | release_mem_region(pci_resource_start(pdev, 0), | 1287 | goto out_err_regbase; |
1231 | pci_resource_len(pdev, 0)); | ||
1232 | goto out_err; | ||
1233 | } | 1288 | } |
1234 | 1289 | ||
1235 | if (!request_mem_region(pci_resource_start(pdev, 1), | 1290 | if (!request_mem_region(tdfx_fix.smem_start, |
1236 | pci_resource_len(pdev, 1), "tdfx smem")) { | 1291 | pci_resource_len(pdev, 1), "tdfx smem")) { |
1237 | printk(KERN_WARNING "tdfxfb: Can't reserve smem\n"); | 1292 | printk(KERN_WARNING "tdfxfb: Can't reserve smem\n"); |
1238 | release_mem_region(pci_resource_start(pdev, 0), | 1293 | goto out_err_regbase; |
1239 | pci_resource_len(pdev, 0)); | ||
1240 | goto out_err; | ||
1241 | } | 1294 | } |
1242 | 1295 | ||
1243 | info->screen_base = ioremap_nocache(tdfx_fix.smem_start, | 1296 | info->screen_base = ioremap_nocache(tdfx_fix.smem_start, |
1244 | tdfx_fix.smem_len); | 1297 | tdfx_fix.smem_len); |
1245 | if (!info->screen_base) { | 1298 | if (!info->screen_base) { |
1246 | printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id); | 1299 | printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id); |
1247 | release_mem_region(pci_resource_start(pdev, 1), | 1300 | goto out_err_screenbase; |
1248 | pci_resource_len(pdev, 1)); | ||
1249 | release_mem_region(pci_resource_start(pdev, 0), | ||
1250 | pci_resource_len(pdev, 0)); | ||
1251 | goto out_err; | ||
1252 | } | 1301 | } |
1253 | 1302 | ||
1254 | default_par->iobase = pci_resource_start(pdev, 2); | 1303 | default_par->iobase = pci_resource_start(pdev, 2); |
@@ -1256,11 +1305,7 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, | |||
1256 | if (!request_region(pci_resource_start(pdev, 2), | 1305 | if (!request_region(pci_resource_start(pdev, 2), |
1257 | pci_resource_len(pdev, 2), "tdfx iobase")) { | 1306 | pci_resource_len(pdev, 2), "tdfx iobase")) { |
1258 | printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n"); | 1307 | printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n"); |
1259 | release_mem_region(pci_resource_start(pdev, 1), | 1308 | goto out_err_screenbase; |
1260 | pci_resource_len(pdev, 1)); | ||
1261 | release_mem_region(pci_resource_start(pdev, 0), | ||
1262 | pci_resource_len(pdev, 0)); | ||
1263 | goto out_err; | ||
1264 | } | 1309 | } |
1265 | 1310 | ||
1266 | printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10); | 1311 | 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 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; | 1319 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; |
1275 | #ifdef CONFIG_FB_3DFX_ACCEL | 1320 | #ifdef CONFIG_FB_3DFX_ACCEL |
1276 | info->flags |= FBINFO_HWACCEL_FILLRECT | | 1321 | info->flags |= FBINFO_HWACCEL_FILLRECT | |
1277 | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_IMAGEBLIT; | 1322 | FBINFO_HWACCEL_COPYAREA | |
1323 | FBINFO_HWACCEL_IMAGEBLIT | | ||
1324 | FBINFO_READS_FAST; | ||
1278 | #endif | 1325 | #endif |
1279 | 1326 | ||
1280 | if (!mode_option) | 1327 | if (!mode_option) |
@@ -1288,27 +1335,17 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, | |||
1288 | lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); | 1335 | lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); |
1289 | info->var.yres_virtual = info->fix.smem_len / lpitch; | 1336 | info->var.yres_virtual = info->fix.smem_len / lpitch; |
1290 | if (info->var.yres_virtual < info->var.yres) | 1337 | if (info->var.yres_virtual < info->var.yres) |
1291 | goto out_err; | 1338 | goto out_err_iobase; |
1292 | |||
1293 | #ifdef CONFIG_FB_3DFX_ACCEL | ||
1294 | /* | ||
1295 | * FIXME: Limit var->yres_virtual to 4096 because of screen artifacts | ||
1296 | * during scrolling. This is only present if 2D acceleration is | ||
1297 | * enabled. | ||
1298 | */ | ||
1299 | if (info->var.yres_virtual > 4096) | ||
1300 | info->var.yres_virtual = 4096; | ||
1301 | #endif /* CONFIG_FB_3DFX_ACCEL */ | ||
1302 | 1339 | ||
1303 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { | 1340 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { |
1304 | printk(KERN_WARNING "tdfxfb: Can't allocate color map\n"); | 1341 | printk(KERN_WARNING "tdfxfb: Can't allocate color map\n"); |
1305 | goto out_err; | 1342 | goto out_err_iobase; |
1306 | } | 1343 | } |
1307 | 1344 | ||
1308 | if (register_framebuffer(info) < 0) { | 1345 | if (register_framebuffer(info) < 0) { |
1309 | printk("tdfxfb: can't register framebuffer\n"); | 1346 | printk("tdfxfb: can't register framebuffer\n"); |
1310 | fb_dealloc_cmap(&info->cmap); | 1347 | fb_dealloc_cmap(&info->cmap); |
1311 | goto out_err; | 1348 | goto out_err_iobase; |
1312 | } | 1349 | } |
1313 | /* | 1350 | /* |
1314 | * Our driver data | 1351 | * Our driver data |
@@ -1316,14 +1353,21 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, | |||
1316 | pci_set_drvdata(pdev, info); | 1353 | pci_set_drvdata(pdev, info); |
1317 | return 0; | 1354 | return 0; |
1318 | 1355 | ||
1319 | out_err: | 1356 | out_err_iobase: |
1357 | release_mem_region(pci_resource_start(pdev, 2), | ||
1358 | pci_resource_len(pdev, 2)); | ||
1359 | out_err_screenbase: | ||
1360 | if (info->screen_base) | ||
1361 | iounmap(info->screen_base); | ||
1362 | release_mem_region(tdfx_fix.smem_start, pci_resource_len(pdev, 1)); | ||
1363 | out_err_regbase: | ||
1320 | /* | 1364 | /* |
1321 | * Cleanup after anything that was remapped/allocated. | 1365 | * Cleanup after anything that was remapped/allocated. |
1322 | */ | 1366 | */ |
1323 | if (default_par->regbase_virt) | 1367 | if (default_par->regbase_virt) |
1324 | iounmap(default_par->regbase_virt); | 1368 | iounmap(default_par->regbase_virt); |
1325 | if (info->screen_base) | 1369 | release_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len); |
1326 | iounmap(info->screen_base); | 1370 | out_err: |
1327 | framebuffer_release(info); | 1371 | framebuffer_release(info); |
1328 | return -ENXIO; | 1372 | return -ENXIO; |
1329 | } | 1373 | } |