aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tdfxfb.c
diff options
context:
space:
mode:
authorKrzysztof Helt <krzysztof.h1@wp.pl>2007-10-16 04:28:48 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:15 -0400
commit90b0f08536531abbbe7b5d4944792da08cadde01 (patch)
treec6379621f90d4a9b1d01df3060c00d196549ca95 /drivers/video/tdfxfb.c
parent4f05b53b28cc7a2b868bc13d19d88cd858e759b6 (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/tdfxfb.c')
-rw-r--r--drivers/video/tdfxfb.c169
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 */
151static int nopan = 0; 150static int nopan;
152static int nowrap = 1; // not implemented (yet) 151static int nowrap = 1; /* not implemented (yet) */
152static int hwcursor = 1;
153static char *mode_option __devinitdata = NULL; 153static 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
1016static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) 1019static 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
1155static struct fb_ops tdfxfb_ops = { 1122static 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>");
1394MODULE_DESCRIPTION("3Dfx framebuffer device driver"); 1369MODULE_DESCRIPTION("3Dfx framebuffer device driver");
1395MODULE_LICENSE("GPL"); 1370MODULE_LICENSE("GPL");
1396 1371
1372module_param(hwcursor, int, 0644);
1373MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
1374 "(1=enable, 0=disable, default=1)");
1375
1397module_init(tdfxfb_init); 1376module_init(tdfxfb_init);
1398module_exit(tdfxfb_exit); 1377module_exit(tdfxfb_exit);