diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2007-10-16 04:28:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:15 -0400 |
commit | 90b0f08536531abbbe7b5d4944792da08cadde01 (patch) | |
tree | c6379621f90d4a9b1d01df3060c00d196549ca95 /drivers/video | |
parent | 4f05b53b28cc7a2b868bc13d19d88cd858e759b6 (diff) |
tdfxfb: hardware cursor
This patch adds hardware cursor support to the tdfxfb driver.
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/video')
-rw-r--r-- | drivers/video/tdfxfb.c | 169 |
1 files changed, 74 insertions, 95 deletions
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 7d0c50e3a40b..c5ba6477dfe2 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c | |||
@@ -67,7 +67,6 @@ | |||
67 | #include <linux/init.h> | 67 | #include <linux/init.h> |
68 | #include <linux/pci.h> | 68 | #include <linux/pci.h> |
69 | #include <asm/io.h> | 69 | #include <asm/io.h> |
70 | #include <linux/timer.h> | ||
71 | #include <linux/spinlock.h> | 70 | #include <linux/spinlock.h> |
72 | 71 | ||
73 | #include <video/tdfx.h> | 72 | #include <video/tdfx.h> |
@@ -148,8 +147,9 @@ MODULE_DEVICE_TABLE(pci, tdfxfb_id_table); | |||
148 | /* | 147 | /* |
149 | * Driver data | 148 | * Driver data |
150 | */ | 149 | */ |
151 | static int nopan = 0; | 150 | static int nopan; |
152 | static int nowrap = 1; // not implemented (yet) | 151 | static int nowrap = 1; /* not implemented (yet) */ |
152 | static int hwcursor = 1; | ||
153 | static char *mode_option __devinitdata = NULL; | 153 | static char *mode_option __devinitdata = NULL; |
154 | 154 | ||
155 | /* ------------------------------------------------------------------------- | 155 | /* ------------------------------------------------------------------------- |
@@ -378,7 +378,7 @@ static void do_write_regs(struct fb_info *info, struct banshee_reg *reg) | |||
378 | tdfx_outl(par, VGAINIT0, reg->vgainit0); | 378 | tdfx_outl(par, VGAINIT0, reg->vgainit0); |
379 | tdfx_outl(par, DACMODE, reg->dacmode); | 379 | tdfx_outl(par, DACMODE, reg->dacmode); |
380 | tdfx_outl(par, VIDDESKSTRIDE, reg->stride); | 380 | tdfx_outl(par, VIDDESKSTRIDE, reg->stride); |
381 | tdfx_outl(par, HWCURPATADDR, 0); | 381 | tdfx_outl(par, HWCURPATADDR, reg->curspataddr); |
382 | 382 | ||
383 | tdfx_outl(par, VIDSCREENSIZE, reg->screensize); | 383 | tdfx_outl(par, VIDSCREENSIZE, reg->screensize); |
384 | tdfx_outl(par, VIDDESKSTART, reg->startaddr); | 384 | tdfx_outl(par, VIDDESKSTART, reg->startaddr); |
@@ -453,6 +453,7 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
453 | DPRINTK("xoffset not supported\n"); | 453 | DPRINTK("xoffset not supported\n"); |
454 | return -EINVAL; | 454 | return -EINVAL; |
455 | } | 455 | } |
456 | var->yoffset = 0; | ||
456 | 457 | ||
457 | /* Banshee doesn't support interlace, but Voodoo4/5 and probably Voodoo3 do. */ | 458 | /* Banshee doesn't support interlace, but Voodoo4/5 and probably Voodoo3 do. */ |
458 | /* no direct information about device id now? use max_pixclock for this... */ | 459 | /* no direct information about device id now? use max_pixclock for this... */ |
@@ -663,6 +664,9 @@ static int tdfxfb_set_par(struct fb_info *info) | |||
663 | VGAINIT0_EXTSHIFTOUT; | 664 | VGAINIT0_EXTSHIFTOUT; |
664 | reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff; | 665 | reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff; |
665 | 666 | ||
667 | if (hwcursor) | ||
668 | reg.curspataddr = info->fix.smem_len; | ||
669 | |||
666 | reg.cursloc = 0; | 670 | reg.cursloc = 0; |
667 | 671 | ||
668 | reg.cursc0 = 0; | 672 | reg.cursc0 = 0; |
@@ -1012,11 +1016,25 @@ static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
1012 | } | 1016 | } |
1013 | #endif /* CONFIG_FB_3DFX_ACCEL */ | 1017 | #endif /* CONFIG_FB_3DFX_ACCEL */ |
1014 | 1018 | ||
1015 | #ifdef TDFX_HARDWARE_CURSOR | ||
1016 | static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | 1019 | static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) |
1017 | { | 1020 | { |
1018 | struct tdfx_par *par = info->par; | 1021 | struct tdfx_par *par = info->par; |
1019 | unsigned long flags; | 1022 | u32 vidcfg; |
1023 | |||
1024 | if (!hwcursor) | ||
1025 | return -EINVAL; /* just to force soft_cursor() call */ | ||
1026 | |||
1027 | /* Too large of a cursor or wrong bpp :-( */ | ||
1028 | if (cursor->image.width > 64 || | ||
1029 | cursor->image.height > 64 || | ||
1030 | cursor->image.depth > 1) | ||
1031 | return -EINVAL; | ||
1032 | |||
1033 | vidcfg = tdfx_inl(par, VIDPROCCFG); | ||
1034 | if (cursor->enable) | ||
1035 | tdfx_outl(par, VIDPROCCFG, vidcfg | VIDCFG_HWCURSOR_ENABLE); | ||
1036 | else | ||
1037 | tdfx_outl(par, VIDPROCCFG, vidcfg & ~VIDCFG_HWCURSOR_ENABLE); | ||
1020 | 1038 | ||
1021 | /* | 1039 | /* |
1022 | * If the cursor is not be changed this means either we want the | 1040 | * If the cursor is not be changed this means either we want the |
@@ -1026,69 +1044,34 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
1026 | if (!cursor->set) | 1044 | if (!cursor->set) |
1027 | return 0; | 1045 | return 0; |
1028 | 1046 | ||
1029 | /* Too large of a cursor :-( */ | ||
1030 | if (cursor->image.width > 64 || cursor->image.height > 64) | ||
1031 | return -ENXIO; | ||
1032 | |||
1033 | /* | ||
1034 | * If we are going to be changing things we should disable | ||
1035 | * the cursor first | ||
1036 | */ | ||
1037 | if (info->cursor.enable) { | ||
1038 | spin_lock_irqsave(&par->DAClock, flags); | ||
1039 | info->cursor.enable = 0; | ||
1040 | del_timer(&(par->hwcursor.timer)); | ||
1041 | tdfx_outl(par, VIDPROCCFG, par->hwcursor.disable); | ||
1042 | spin_unlock_irqrestore(&par->DAClock, flags); | ||
1043 | } | ||
1044 | |||
1045 | /* Disable the Cursor */ | ||
1046 | if ((cursor->set && FB_CUR_SETCUR) && !cursor->enable) | ||
1047 | return 0; | ||
1048 | |||
1049 | /* fix cursor color - XFree86 forgets to restore it properly */ | 1047 | /* fix cursor color - XFree86 forgets to restore it properly */ |
1050 | if (cursor->set && FB_CUR_SETCMAP) { | 1048 | if (cursor->set & FB_CUR_SETCMAP) { |
1051 | struct fb_cmap cmap = cursor->image.cmap; | 1049 | struct fb_cmap cmap = info->cmap; |
1050 | u32 bg_idx = cursor->image.bg_color; | ||
1051 | u32 fg_idx = cursor->image.fg_color; | ||
1052 | unsigned long bg_color, fg_color; | 1052 | unsigned long bg_color, fg_color; |
1053 | 1053 | ||
1054 | cmap.len = 2; /* Voodoo 3+ only support 2 color cursors */ | 1054 | fg_color = (((u32)cmap.red[fg_idx] & 0xff00) << 8) | |
1055 | fg_color = ((cmap.red[cmap.start] << 16) | | 1055 | (((u32)cmap.green[fg_idx] & 0xff00) << 0) | |
1056 | (cmap.green[cmap.start] << 8) | | 1056 | (((u32)cmap.blue[fg_idx] & 0xff00) >> 8); |
1057 | (cmap.blue[cmap.start])); | 1057 | bg_color = (((u32)cmap.red[bg_idx] & 0xff00) << 8) | |
1058 | bg_color = ((cmap.red[cmap.start + 1] << 16) | | 1058 | (((u32)cmap.green[bg_idx] & 0xff00) << 0) | |
1059 | (cmap.green[cmap.start + 1] << 8) | | 1059 | (((u32)cmap.blue[bg_idx] & 0xff00) >> 8); |
1060 | (cmap.blue[cmap.start + 1])); | ||
1061 | fb_copy_cmap(&cmap, &info->cursor.image.cmap); | ||
1062 | spin_lock_irqsave(&par->DAClock, flags); | ||
1063 | banshee_make_room(par, 2); | 1060 | banshee_make_room(par, 2); |
1064 | tdfx_outl(par, HWCURC0, bg_color); | 1061 | tdfx_outl(par, HWCURC0, bg_color); |
1065 | tdfx_outl(par, HWCURC1, fg_color); | 1062 | tdfx_outl(par, HWCURC1, fg_color); |
1066 | spin_unlock_irqrestore(&par->DAClock, flags); | ||
1067 | } | 1063 | } |
1068 | 1064 | ||
1069 | if (cursor->set && FB_CUR_SETPOS) { | 1065 | if (cursor->set & FB_CUR_SETPOS) { |
1070 | int x, y; | 1066 | int x = cursor->image.dx; |
1067 | int y = cursor->image.dy - info->var.yoffset; | ||
1071 | 1068 | ||
1072 | x = cursor->image.dx; | ||
1073 | y = cursor->image.dy; | ||
1074 | y -= info->var.yoffset; | ||
1075 | info->cursor.image.dx = x; | ||
1076 | info->cursor.image.dy = y; | ||
1077 | x += 63; | 1069 | x += 63; |
1078 | y += 63; | 1070 | y += 63; |
1079 | spin_lock_irqsave(&par->DAClock, flags); | ||
1080 | banshee_make_room(par, 1); | 1071 | banshee_make_room(par, 1); |
1081 | tdfx_outl(par, HWCURLOC, (y << 16) + x); | 1072 | tdfx_outl(par, HWCURLOC, (y << 16) + x); |
1082 | spin_unlock_irqrestore(&par->DAClock, flags); | ||
1083 | } | 1073 | } |
1084 | 1074 | if (cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) { | |
1085 | /* Not supported so we fake it */ | ||
1086 | if (cursor->set && FB_CUR_SETHOT) { | ||
1087 | info->cursor.hot.x = cursor->hot.x; | ||
1088 | info->cursor.hot.y = cursor->hot.y; | ||
1089 | } | ||
1090 | |||
1091 | if (cursor->set && FB_CUR_SETSHAPE) { | ||
1092 | /* | 1075 | /* |
1093 | * Voodoo 3 and above cards use 2 monochrome cursor patterns. | 1076 | * Voodoo 3 and above cards use 2 monochrome cursor patterns. |
1094 | * The reason is so the card can fetch 8 words at a time | 1077 | * The reason is so the card can fetch 8 words at a time |
@@ -1096,7 +1079,7 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
1096 | * This reduces the number of times for access to draw the | 1079 | * This reduces the number of times for access to draw the |
1097 | * cursor for each screen refresh. | 1080 | * cursor for each screen refresh. |
1098 | * Each pattern is a bitmap of 64 bit wide and 64 bit high | 1081 | * Each pattern is a bitmap of 64 bit wide and 64 bit high |
1099 | * (total of 8192 bits or 1024 Kbytes). The two patterns are | 1082 | * (total of 8192 bits or 1024 bytes). The two patterns are |
1100 | * stored in such a way that pattern 0 always resides in the | 1083 | * stored in such a way that pattern 0 always resides in the |
1101 | * lower half (least significant 64 bits) of a 128 bit word | 1084 | * lower half (least significant 64 bits) of a 128 bit word |
1102 | * and pattern 1 the upper half. If you examine the data of | 1085 | * and pattern 1 the upper half. If you examine the data of |
@@ -1107,50 +1090,34 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
1107 | * (128 bits) which is the maximum cursor width times two for | 1090 | * (128 bits) which is the maximum cursor width times two for |
1108 | * the two monochrome patterns. | 1091 | * the two monochrome patterns. |
1109 | */ | 1092 | */ |
1110 | u8 *cursorbase = (u8 *)info->cursor.image.data; | 1093 | u8 __iomem *cursorbase = info->screen_base + info->fix.smem_len; |
1111 | char *bitmap = (char *)cursor->image.data; | 1094 | u8 *bitmap = (u8 *)cursor->image.data; |
1112 | char *mask = (char *)cursor->mask; | 1095 | u8 *mask = (u8 *)cursor->mask; |
1113 | int i, j, k, h = 0; | 1096 | int i; |
1114 | 1097 | ||
1115 | for (i = 0; i < 64; i++) { | 1098 | fb_memset(cursorbase, 0, 1024); |
1116 | if (i < cursor->image.height) { | 1099 | |
1117 | j = (cursor->image.width + 7) >> 3; | 1100 | for (i = 0; i < cursor->image.height; i++) { |
1118 | k = 8 - j; | 1101 | int h = 0; |
1119 | 1102 | int j = (cursor->image.width + 7) >> 3; | |
1120 | for (; j > 0; j--) { | 1103 | |
1121 | /* Pattern 0. Copy the cursor bitmap to it */ | 1104 | for (; j > 0; j--) { |
1122 | fb_writeb(*bitmap, cursorbase + h); | 1105 | u8 data = *mask ^ *bitmap; |
1123 | bitmap++; | 1106 | if (cursor->rop == ROP_COPY) |
1124 | /* Pattern 1. Copy the cursor mask to it */ | 1107 | data = *mask & *bitmap; |
1125 | fb_writeb(*mask, cursorbase + h + 8); | 1108 | /* Pattern 0. Copy the cursor mask to it */ |
1126 | mask++; | 1109 | fb_writeb(*mask, cursorbase + h); |
1127 | h++; | 1110 | mask++; |
1128 | } | 1111 | /* Pattern 1. Copy the cursor bitmap to it */ |
1129 | for (; k > 0; k--) { | 1112 | fb_writeb(data, cursorbase + h + 8); |
1130 | fb_writeb(0, cursorbase + h); | 1113 | bitmap++; |
1131 | fb_writeb(~0, cursorbase + h + 8); | 1114 | h++; |
1132 | h++; | ||
1133 | } | ||
1134 | } else { | ||
1135 | fb_writel(0, cursorbase + h); | ||
1136 | fb_writel(0, cursorbase + h + 4); | ||
1137 | fb_writel(~0, cursorbase + h + 8); | ||
1138 | fb_writel(~0, cursorbase + h + 12); | ||
1139 | h += 16; | ||
1140 | } | 1115 | } |
1116 | cursorbase += 16; | ||
1141 | } | 1117 | } |
1142 | } | 1118 | } |
1143 | /* Turn the cursor on */ | ||
1144 | cursor->enable = 1; | ||
1145 | info->cursor = *cursor; | ||
1146 | mod_timer(&par->hwcursor.timer, jiffies + HZ / 2); | ||
1147 | spin_lock_irqsave(&par->DAClock, flags); | ||
1148 | banshee_make_room(par, 1); | ||
1149 | tdfx_outl(par, VIDPROCCFG, par->hwcursor.enable); | ||
1150 | spin_unlock_irqrestore(&par->DAClock, flags); | ||
1151 | return 0; | 1119 | return 0; |
1152 | } | 1120 | } |
1153 | #endif | ||
1154 | 1121 | ||
1155 | static struct fb_ops tdfxfb_ops = { | 1122 | static struct fb_ops tdfxfb_ops = { |
1156 | .owner = THIS_MODULE, | 1123 | .owner = THIS_MODULE, |
@@ -1160,6 +1127,7 @@ static struct fb_ops tdfxfb_ops = { | |||
1160 | .fb_blank = tdfxfb_blank, | 1127 | .fb_blank = tdfxfb_blank, |
1161 | .fb_pan_display = tdfxfb_pan_display, | 1128 | .fb_pan_display = tdfxfb_pan_display, |
1162 | .fb_sync = banshee_wait_idle, | 1129 | .fb_sync = banshee_wait_idle, |
1130 | .fb_cursor = tdfxfb_cursor, | ||
1163 | #ifdef CONFIG_FB_3DFX_ACCEL | 1131 | #ifdef CONFIG_FB_3DFX_ACCEL |
1164 | .fb_fillrect = tdfxfb_fillrect, | 1132 | .fb_fillrect = tdfxfb_fillrect, |
1165 | .fb_copyarea = tdfxfb_copyarea, | 1133 | .fb_copyarea = tdfxfb_copyarea, |
@@ -1272,6 +1240,11 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, | |||
1272 | FBINFO_HWACCEL_IMAGEBLIT | | 1240 | FBINFO_HWACCEL_IMAGEBLIT | |
1273 | FBINFO_READS_FAST; | 1241 | FBINFO_READS_FAST; |
1274 | #endif | 1242 | #endif |
1243 | /* reserve 8192 bits for cursor */ | ||
1244 | /* the 2.4 driver says PAGE_MASK boundary is not enough for Voodoo4 */ | ||
1245 | if (hwcursor) | ||
1246 | info->fix.smem_len = (info->fix.smem_len - 1024) & | ||
1247 | (PAGE_MASK << 1); | ||
1275 | 1248 | ||
1276 | if (!mode_option) | 1249 | if (!mode_option) |
1277 | mode_option = "640x480@60"; | 1250 | mode_option = "640x480@60"; |
@@ -1336,6 +1309,8 @@ static void tdfxfb_setup(char *options) | |||
1336 | nopan = 1; | 1309 | nopan = 1; |
1337 | } else if (!strcmp(this_opt, "nowrap")) { | 1310 | } else if (!strcmp(this_opt, "nowrap")) { |
1338 | nowrap = 1; | 1311 | nowrap = 1; |
1312 | } else if (!strcmp(this_opt, "hwcursor")) { | ||
1313 | hwcursor = simple_strtoul(opt + 9, NULL, 0); | ||
1339 | } else { | 1314 | } else { |
1340 | mode_option = this_opt; | 1315 | mode_option = this_opt; |
1341 | } | 1316 | } |
@@ -1394,5 +1369,9 @@ MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>"); | |||
1394 | MODULE_DESCRIPTION("3Dfx framebuffer device driver"); | 1369 | MODULE_DESCRIPTION("3Dfx framebuffer device driver"); |
1395 | MODULE_LICENSE("GPL"); | 1370 | MODULE_LICENSE("GPL"); |
1396 | 1371 | ||
1372 | module_param(hwcursor, int, 0644); | ||
1373 | MODULE_PARM_DESC(hwcursor, "Enable hardware cursor " | ||
1374 | "(1=enable, 0=disable, default=1)"); | ||
1375 | |||
1397 | module_init(tdfxfb_init); | 1376 | module_init(tdfxfb_init); |
1398 | module_exit(tdfxfb_exit); | 1377 | module_exit(tdfxfb_exit); |