From 8f5d050af1da13455068cefbaf3c1bc306d6fe0b Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Tue, 16 Oct 2007 01:28:53 -0700 Subject: [PATCH] pm2fb: Permedia 2V hardware cursor support This patch adds hardware cursor support for Permedia 2V chips. The hardware cursor is disabled by default. It does not blink - the same issue is mentioned in the x11 driver. Signed-off-by: Krzysztof Helt Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/pm2fb.c | 137 ++++++++++++++++++++++++++++++++++++++ include/video/permedia2.h | 2 + 2 files changed, 139 insertions(+) diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 19cbde192956..53dd639e9753 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -66,6 +66,7 @@ /* * Driver data */ +static int hwcursor; static char *mode __devinitdata; /* @@ -1245,6 +1246,136 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image) pm2_WR(par, PM2R_SCISSOR_MODE, 0); } +/* + * Hardware cursor support. + */ +static const u8 cursor_bits_lookup[16] = { + 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, + 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 +}; + +static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct pm2fb_par *par = info->par; + u8 mode; + + if (!hwcursor) + return -EINVAL; /* just to force soft_cursor() call */ + + /* Too large of a cursor or wrong bpp :-( */ + if (cursor->image.width > 64 || + cursor->image.height > 64 || + cursor->image.depth > 1) + return -EINVAL; + + mode = PM2F_CURSORMODE_TYPE_X; + if (cursor->enable) + mode |= PM2F_CURSORMODE_CURSOR_ENABLE; + + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_MODE, mode); + + /* + * If the cursor is not be changed this means either we want the + * current cursor state (if enable is set) or we want to query what + * we can do with the cursor (if enable is not set) + */ + if (!cursor->set) + return 0; + + if (cursor->set & FB_CUR_SETPOS) { + int x = cursor->image.dx - info->var.xoffset; + int y = cursor->image.dy - info->var.yoffset; + + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf); + } + + if (cursor->set & FB_CUR_SETHOT) { + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HOT, + cursor->hot.x & 0x3f); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HOT, + cursor->hot.y & 0x3f); + } + + if (cursor->set & FB_CUR_SETCMAP) { + u32 fg_idx = cursor->image.fg_color; + u32 bg_idx = cursor->image.bg_color; + struct fb_cmap cmap = info->cmap; + + /* the X11 driver says one should use these color registers */ + pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 0, + cmap.red[bg_idx] >> 8 ); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 1, + cmap.green[bg_idx] >> 8 ); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 2, + cmap.blue[bg_idx] >> 8 ); + + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 3, + cmap.red[fg_idx] >> 8 ); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 4, + cmap.green[fg_idx] >> 8 ); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 5, + cmap.blue[fg_idx] >> 8 ); + pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); + } + + if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { + u8 *bitmap = (u8 *)cursor->image.data; + u8 *mask = (u8 *)cursor->mask; + int i; + int pos = PM2VI_RD_CURSOR_PATTERN; + + for (i = 0; i < cursor->image.height; i++) { + int j = (cursor->image.width + 7) >> 3; + int k = 8 - j; + + pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8); + + for (; j > 0; j--) { + u8 data = *bitmap ^ *mask; + + if (cursor->rop == ROP_COPY) + data = *mask & *bitmap; + /* Upper 4 bits of bitmap data */ + pm2v_RDAC_WR(par, pos++, + cursor_bits_lookup[data >> 4] | + (cursor_bits_lookup[*mask >> 4] << 1)); + /* Lower 4 bits of bitmap */ + pm2v_RDAC_WR(par, pos++, + cursor_bits_lookup[data & 0xf] | + (cursor_bits_lookup[*mask & 0xf] << 1)); + bitmap++; + mask++; + } + for (; k > 0; k--) { + pm2v_RDAC_WR(par, pos++, 0); + pm2v_RDAC_WR(par, pos++, 0); + } + } + + while (pos < (1024 + PM2VI_RD_CURSOR_PATTERN)) { + pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8); + pm2v_RDAC_WR(par, pos++, 0); + } + + pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); + } + return 0; +} + +static int pm2fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct pm2fb_par *par = info->par; + + if (par->type == PM2_TYPE_PERMEDIA2V) + return pm2vfb_cursor(info, cursor); + + return -ENXIO; +} + /* ------------ Hardware Independent Functions ------------ */ /* @@ -1262,6 +1393,7 @@ static struct fb_ops pm2fb_ops = { .fb_copyarea = pm2fb_copyarea, .fb_imageblit = pm2fb_imageblit, .fb_sync = pm2fb_sync, + .fb_cursor = pm2fb_cursor, }; /* @@ -1550,6 +1682,8 @@ static int __init pm2fb_setup(char *options) lowhsync = 1; else if (!strcmp(this_opt, "lowvsync")) lowvsync = 1; + else if (!strncmp(this_opt, "hwcursor=", 9)) + hwcursor = simple_strtoul(this_opt + 9, NULL, 0); #ifdef CONFIG_MTRR else if (!strncmp(this_opt, "nomtrr", 6)) nomtrr = 1; @@ -1601,6 +1735,9 @@ module_param(lowvsync, bool, 0); MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode"); module_param(noaccel, bool, 0); MODULE_PARM_DESC(noaccel, "Disable acceleration"); +module_param(hwcursor, int, 0644); +MODULE_PARM_DESC(hwcursor, "Enable hardware cursor " + "(1=enable, 0=disable, default=0)"); #ifdef CONFIG_MTRR module_param(nomtrr, bool, 0); MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); diff --git a/include/video/permedia2.h b/include/video/permedia2.h index cf1d95bce412..c6575b834fef 100644 --- a/include/video/permedia2.h +++ b/include/video/permedia2.h @@ -232,6 +232,8 @@ #define PM2F_APERTURE_STANDARD 0 #define PM2F_APERTURE_BYTESWAP 1 #define PM2F_APERTURE_HALFWORDSWAP 2 +#define PM2F_CURSORMODE_CURSOR_ENABLE (1 << 0) +#define PM2F_CURSORMODE_TYPE_X (1 << 4) typedef enum { PM2_TYPE_PERMEDIA2,