Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 362930
b: refs/heads/master
c: 38dd2da
h: refs/heads/master
v: v3
  • Loading branch information
Timur Tabi authored and Tomi Valkeinen committed Apr 10, 2013
1 parent 11378a6 commit 7cdbef7
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3ccbf89f4d86cc8f4d6645fa5db0327ef835777b
refs/heads/master: 38dd2daf297a4543344b6c473f3e80b362430a4b
157 changes: 155 additions & 2 deletions trunk/drivers/video/fsl-diu-fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,10 @@ struct fsl_diu_data {
struct diu_ad dummy_ad __aligned(8);
struct diu_ad ad[NUM_AOIS] __aligned(8);
u8 gamma[256 * 3] __aligned(32);
u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32);
/* It's easier to parse the cursor data as little-endian */
__le16 cursor[MAX_CURS * MAX_CURS] __aligned(32);
/* Blank cursor data -- used to hide the cursor */
__le16 blank_cursor[MAX_CURS * MAX_CURS] __aligned(32);
uint8_t edid_data[EDID_LENGTH];
bool has_edid;
} __aligned(32);
Expand Down Expand Up @@ -824,7 +827,6 @@ static void update_lcdc(struct fb_info *info)
/* Program DIU registers */

out_be32(&hw->gamma, DMA_ADDR(data, gamma));
out_be32(&hw->cursor, DMA_ADDR(data, cursor));

out_be32(&hw->bgnd, 0x007F7F7F); /* Set background to grey */
out_be32(&hw->disp_size, (var->yres << 16) | var->xres);
Expand Down Expand Up @@ -967,6 +969,156 @@ static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel)
}
}

/*
* Copies a cursor image from user space to the proper place in driver
* memory so that the hardware can display the cursor image.
*
* Cursor data is represented as a sequence of 'width' bits packed into bytes.
* That is, the first 8 bits are in the first byte, the second 8 bits in the
* second byte, and so on. Therefore, the each row of the cursor is (width +
* 7) / 8 bytes of 'data'
*
* The DIU only supports cursors up to 32x32 (MAX_CURS). We reject cursors
* larger than this, so we already know that 'width' <= 32. Therefore, we can
* simplify our code by using a 32-bit big-endian integer ("line") to read in
* a single line of pixels, and only look at the top 'width' bits of that
* integer.
*
* This could result in an unaligned 32-bit read. For example, if the cursor
* is 24x24, then the first three bytes of 'image' contain the pixel data for
* the top line of the cursor. We do a 32-bit read of 'image', but we look
* only at the top 24 bits. Then we increment 'image' by 3 bytes. The next
* read is unaligned. The only problem is that we might read past the end of
* 'image' by 1-3 bytes, but that should not cause any problems.
*/
static void fsl_diu_load_cursor_image(struct fb_info *info,
const void *image, uint16_t bg, uint16_t fg,
unsigned int width, unsigned int height)
{
struct mfb_info *mfbi = info->par;
struct fsl_diu_data *data = mfbi->parent;
__le16 *cursor = data->cursor;
__le16 _fg = cpu_to_le16(fg);
__le16 _bg = cpu_to_le16(bg);
unsigned int h, w;

for (h = 0; h < height; h++) {
uint32_t mask = 1 << 31;
uint32_t line = be32_to_cpup(image);

for (w = 0; w < width; w++) {
cursor[w] = (line & mask) ? _fg : _bg;
mask >>= 1;
}

cursor += MAX_CURS;
image += DIV_ROUND_UP(width, 8);
}
}

/*
* Set a hardware cursor. The image data for the cursor is passed via the
* fb_cursor object.
*/
static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct mfb_info *mfbi = info->par;
struct fsl_diu_data *data = mfbi->parent;
struct diu __iomem *hw = data->diu_reg;

if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
return -EINVAL;

/* The cursor size has changed */
if (cursor->set & FB_CUR_SETSIZE) {
/*
* The DIU cursor is a fixed size, so when we get this
* message, instead of resizing the cursor, we just clear
* all the image data, in expectation of new data. However,
* in tests this control does not appear to be normally
* called.
*/
memset(data->cursor, 0, sizeof(data->cursor));
}

/* The cursor position has changed (cursor->image.dx|dy) */
if (cursor->set & FB_CUR_SETPOS) {
uint32_t xx, yy;

yy = (cursor->image.dy - info->var.yoffset) & 0x7ff;
xx = (cursor->image.dx - info->var.xoffset) & 0x7ff;

out_be32(&hw->curs_pos, yy << 16 | xx);
}

/*
* FB_CUR_SETIMAGE - the cursor image has changed
* FB_CUR_SETCMAP - the cursor colors has changed
* FB_CUR_SETSHAPE - the cursor bitmask has changed
*/
if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
unsigned int image_size =
DIV_ROUND_UP(cursor->image.width, 8) * cursor->image.height;
unsigned int image_words =
DIV_ROUND_UP(image_size, sizeof(uint32_t));
unsigned int bg_idx = cursor->image.bg_color;
unsigned int fg_idx = cursor->image.fg_color;
uint8_t buffer[image_size];
uint32_t *image, *source, *mask;
uint16_t fg, bg;
unsigned int i;

if (info->state != FBINFO_STATE_RUNNING)
return 0;

/*
* Determine the size of the cursor image data. Normally,
* it's 8x16.
*/
image_size = DIV_ROUND_UP(cursor->image.width, 8) *
cursor->image.height;

bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
((info->cmap.green[bg_idx] & 0xf8) << 2) |
((info->cmap.blue[bg_idx] & 0xf8) >> 3) |
1 << 15;

fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
((info->cmap.green[fg_idx] & 0xf8) << 2) |
((info->cmap.blue[fg_idx] & 0xf8) >> 3) |
1 << 15;

/* Use 32-bit operations on the data to improve performance */
image = (uint32_t *)buffer;
source = (uint32_t *)cursor->image.data;
mask = (uint32_t *)cursor->mask;

if (cursor->rop == ROP_XOR)
for (i = 0; i < image_words; i++)
image[i] = source[i] ^ mask[i];
else
for (i = 0; i < image_words; i++)
image[i] = source[i] & mask[i];

fsl_diu_load_cursor_image(info, image, bg, fg,
cursor->image.width, cursor->image.height);
};

/*
* Show or hide the cursor. The cursor data is always stored in the
* 'cursor' memory block, and the actual cursor position is always in
* the DIU's CURS_POS register. To hide the cursor, we redirect the
* CURSOR register to a blank cursor. The show the cursor, we
* redirect the CURSOR register to the real cursor data.
*/
if (cursor->enable)
out_be32(&hw->cursor, DMA_ADDR(data, cursor));
else
out_be32(&hw->cursor, DMA_ADDR(data, blank_cursor));

return 0;
}

/*
* Using the fb_var_screeninfo in fb_info we set the resolution of this
* particular framebuffer. This function alters the fb_fix_screeninfo stored
Expand Down Expand Up @@ -1312,6 +1464,7 @@ static struct fb_ops fsl_diu_ops = {
.fb_ioctl = fsl_diu_ioctl,
.fb_open = fsl_diu_open,
.fb_release = fsl_diu_release,
.fb_cursor = fsl_diu_cursor,
};

static int install_fb(struct fb_info *info)
Expand Down

0 comments on commit 7cdbef7

Please sign in to comment.