aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimur Tabi <timur@tabi.org>2013-03-29 20:36:00 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2013-04-10 08:03:32 -0400
commit38dd2daf297a4543344b6c473f3e80b362430a4b (patch)
treefac466c1472dc4c54abb3225cad7a12e7f99b338
parent3ccbf89f4d86cc8f4d6645fa5db0327ef835777b (diff)
drivers/video: fsl-diu-fb: add hardware cursor support
The Freescale DIU supports a 32x32 color hardware cursor. Framebuffer cursors are monochrome, so the driver converts the image data to the format that the DIU expects and then programs to hardware accordingly. The support cursor enabling/disabling, we provide two cursor image buffers. One is always blank (all zeroes), and the other contains the real cursor image data. To disable the cursor (used typically for cursor blinking), we just tell the hardware to use the blank cursor data. Signed-off-by: Timur Tabi <timur@tabi.org> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
-rw-r--r--drivers/video/fsl-diu-fb.c157
1 files changed, 155 insertions, 2 deletions
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 41fbd9453c5f..6c278056fc60 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -375,7 +375,10 @@ struct fsl_diu_data {
375 struct diu_ad dummy_ad __aligned(8); 375 struct diu_ad dummy_ad __aligned(8);
376 struct diu_ad ad[NUM_AOIS] __aligned(8); 376 struct diu_ad ad[NUM_AOIS] __aligned(8);
377 u8 gamma[256 * 3] __aligned(32); 377 u8 gamma[256 * 3] __aligned(32);
378 u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32); 378 /* It's easier to parse the cursor data as little-endian */
379 __le16 cursor[MAX_CURS * MAX_CURS] __aligned(32);
380 /* Blank cursor data -- used to hide the cursor */
381 __le16 blank_cursor[MAX_CURS * MAX_CURS] __aligned(32);
379 uint8_t edid_data[EDID_LENGTH]; 382 uint8_t edid_data[EDID_LENGTH];
380 bool has_edid; 383 bool has_edid;
381} __aligned(32); 384} __aligned(32);
@@ -824,7 +827,6 @@ static void update_lcdc(struct fb_info *info)
824 /* Program DIU registers */ 827 /* Program DIU registers */
825 828
826 out_be32(&hw->gamma, DMA_ADDR(data, gamma)); 829 out_be32(&hw->gamma, DMA_ADDR(data, gamma));
827 out_be32(&hw->cursor, DMA_ADDR(data, cursor));
828 830
829 out_be32(&hw->bgnd, 0x007F7F7F); /* Set background to grey */ 831 out_be32(&hw->bgnd, 0x007F7F7F); /* Set background to grey */
830 out_be32(&hw->disp_size, (var->yres << 16) | var->xres); 832 out_be32(&hw->disp_size, (var->yres << 16) | var->xres);
@@ -968,6 +970,156 @@ static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel)
968} 970}
969 971
970/* 972/*
973 * Copies a cursor image from user space to the proper place in driver
974 * memory so that the hardware can display the cursor image.
975 *
976 * Cursor data is represented as a sequence of 'width' bits packed into bytes.
977 * That is, the first 8 bits are in the first byte, the second 8 bits in the
978 * second byte, and so on. Therefore, the each row of the cursor is (width +
979 * 7) / 8 bytes of 'data'
980 *
981 * The DIU only supports cursors up to 32x32 (MAX_CURS). We reject cursors
982 * larger than this, so we already know that 'width' <= 32. Therefore, we can
983 * simplify our code by using a 32-bit big-endian integer ("line") to read in
984 * a single line of pixels, and only look at the top 'width' bits of that
985 * integer.
986 *
987 * This could result in an unaligned 32-bit read. For example, if the cursor
988 * is 24x24, then the first three bytes of 'image' contain the pixel data for
989 * the top line of the cursor. We do a 32-bit read of 'image', but we look
990 * only at the top 24 bits. Then we increment 'image' by 3 bytes. The next
991 * read is unaligned. The only problem is that we might read past the end of
992 * 'image' by 1-3 bytes, but that should not cause any problems.
993 */
994static void fsl_diu_load_cursor_image(struct fb_info *info,
995 const void *image, uint16_t bg, uint16_t fg,
996 unsigned int width, unsigned int height)
997{
998 struct mfb_info *mfbi = info->par;
999 struct fsl_diu_data *data = mfbi->parent;
1000 __le16 *cursor = data->cursor;
1001 __le16 _fg = cpu_to_le16(fg);
1002 __le16 _bg = cpu_to_le16(bg);
1003 unsigned int h, w;
1004
1005 for (h = 0; h < height; h++) {
1006 uint32_t mask = 1 << 31;
1007 uint32_t line = be32_to_cpup(image);
1008
1009 for (w = 0; w < width; w++) {
1010 cursor[w] = (line & mask) ? _fg : _bg;
1011 mask >>= 1;
1012 }
1013
1014 cursor += MAX_CURS;
1015 image += DIV_ROUND_UP(width, 8);
1016 }
1017}
1018
1019/*
1020 * Set a hardware cursor. The image data for the cursor is passed via the
1021 * fb_cursor object.
1022 */
1023static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
1024{
1025 struct mfb_info *mfbi = info->par;
1026 struct fsl_diu_data *data = mfbi->parent;
1027 struct diu __iomem *hw = data->diu_reg;
1028
1029 if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
1030 return -EINVAL;
1031
1032 /* The cursor size has changed */
1033 if (cursor->set & FB_CUR_SETSIZE) {
1034 /*
1035 * The DIU cursor is a fixed size, so when we get this
1036 * message, instead of resizing the cursor, we just clear
1037 * all the image data, in expectation of new data. However,
1038 * in tests this control does not appear to be normally
1039 * called.
1040 */
1041 memset(data->cursor, 0, sizeof(data->cursor));
1042 }
1043
1044 /* The cursor position has changed (cursor->image.dx|dy) */
1045 if (cursor->set & FB_CUR_SETPOS) {
1046 uint32_t xx, yy;
1047
1048 yy = (cursor->image.dy - info->var.yoffset) & 0x7ff;
1049 xx = (cursor->image.dx - info->var.xoffset) & 0x7ff;
1050
1051 out_be32(&hw->curs_pos, yy << 16 | xx);
1052 }
1053
1054 /*
1055 * FB_CUR_SETIMAGE - the cursor image has changed
1056 * FB_CUR_SETCMAP - the cursor colors has changed
1057 * FB_CUR_SETSHAPE - the cursor bitmask has changed
1058 */
1059 if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
1060 unsigned int image_size =
1061 DIV_ROUND_UP(cursor->image.width, 8) * cursor->image.height;
1062 unsigned int image_words =
1063 DIV_ROUND_UP(image_size, sizeof(uint32_t));
1064 unsigned int bg_idx = cursor->image.bg_color;
1065 unsigned int fg_idx = cursor->image.fg_color;
1066 uint8_t buffer[image_size];
1067 uint32_t *image, *source, *mask;
1068 uint16_t fg, bg;
1069 unsigned int i;
1070
1071 if (info->state != FBINFO_STATE_RUNNING)
1072 return 0;
1073
1074 /*
1075 * Determine the size of the cursor image data. Normally,
1076 * it's 8x16.
1077 */
1078 image_size = DIV_ROUND_UP(cursor->image.width, 8) *
1079 cursor->image.height;
1080
1081 bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
1082 ((info->cmap.green[bg_idx] & 0xf8) << 2) |
1083 ((info->cmap.blue[bg_idx] & 0xf8) >> 3) |
1084 1 << 15;
1085
1086 fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
1087 ((info->cmap.green[fg_idx] & 0xf8) << 2) |
1088 ((info->cmap.blue[fg_idx] & 0xf8) >> 3) |
1089 1 << 15;
1090
1091 /* Use 32-bit operations on the data to improve performance */
1092 image = (uint32_t *)buffer;
1093 source = (uint32_t *)cursor->image.data;
1094 mask = (uint32_t *)cursor->mask;
1095
1096 if (cursor->rop == ROP_XOR)
1097 for (i = 0; i < image_words; i++)
1098 image[i] = source[i] ^ mask[i];
1099 else
1100 for (i = 0; i < image_words; i++)
1101 image[i] = source[i] & mask[i];
1102
1103 fsl_diu_load_cursor_image(info, image, bg, fg,
1104 cursor->image.width, cursor->image.height);
1105 };
1106
1107 /*
1108 * Show or hide the cursor. The cursor data is always stored in the
1109 * 'cursor' memory block, and the actual cursor position is always in
1110 * the DIU's CURS_POS register. To hide the cursor, we redirect the
1111 * CURSOR register to a blank cursor. The show the cursor, we
1112 * redirect the CURSOR register to the real cursor data.
1113 */
1114 if (cursor->enable)
1115 out_be32(&hw->cursor, DMA_ADDR(data, cursor));
1116 else
1117 out_be32(&hw->cursor, DMA_ADDR(data, blank_cursor));
1118
1119 return 0;
1120}
1121
1122/*
971 * Using the fb_var_screeninfo in fb_info we set the resolution of this 1123 * Using the fb_var_screeninfo in fb_info we set the resolution of this
972 * particular framebuffer. This function alters the fb_fix_screeninfo stored 1124 * particular framebuffer. This function alters the fb_fix_screeninfo stored
973 * in fb_info. It does not alter var in fb_info since we are using that 1125 * in fb_info. It does not alter var in fb_info since we are using that
@@ -1312,6 +1464,7 @@ static struct fb_ops fsl_diu_ops = {
1312 .fb_ioctl = fsl_diu_ioctl, 1464 .fb_ioctl = fsl_diu_ioctl,
1313 .fb_open = fsl_diu_open, 1465 .fb_open = fsl_diu_open,
1314 .fb_release = fsl_diu_release, 1466 .fb_release = fsl_diu_release,
1467 .fb_cursor = fsl_diu_cursor,
1315}; 1468};
1316 1469
1317static int install_fb(struct fb_info *info) 1470static int install_fb(struct fb_info *info)