summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDanny Nold <dannynold@freescale.com>2011-02-04 14:03:54 -0600
committerDanny Nold <dannynold@freescale.com>2011-02-08 08:56:02 -0600
commit0b3f782cfaad8eaac459a2d2a91834700e845761 (patch)
tree9592e931025852670053681ff61e9d0e6a27a111 /drivers
parent1fcf0b4b0c6e9576b0d23bfb1609b394dd9ae0d0 (diff)
ENGR00138821 - EPDC fb: Panning may cause missed collision
- When update is processed, we check against latest panning offset and drop the update if they don't match. This ensures that we always update using the most current buffer location. Signed-off-by: Danny Nold <dannynold@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/mxc/mxc_epdc_fb.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/drivers/video/mxc/mxc_epdc_fb.c b/drivers/video/mxc/mxc_epdc_fb.c
index 9589812f89d1..a26e1bc98bb7 100644
--- a/drivers/video/mxc/mxc_epdc_fb.c
+++ b/drivers/video/mxc/mxc_epdc_fb.c
@@ -1047,6 +1047,7 @@ static int mxc_epdc_fb_set_par(struct fb_info *info)
int i;
int ret;
unsigned long flags;
+ __u32 xoffset_old, yoffset_old;
/*
* Can't change the FB parameters until current updates have completed.
@@ -1055,7 +1056,15 @@ static int mxc_epdc_fb_set_par(struct fb_info *info)
mxc_epdc_fb_flush_updates(fb_data);
spin_lock_irqsave(&fb_data->queue_lock, flags);
+ /*
+ * Set all screeninfo except for xoffset/yoffset
+ * Subsequent call to pan_display will handle those.
+ */
+ xoffset_old = fb_data->epdc_fb_var.xoffset;
+ yoffset_old = fb_data->epdc_fb_var.yoffset;
fb_data->epdc_fb_var = *screeninfo;
+ fb_data->epdc_fb_var.xoffset = xoffset_old;
+ fb_data->epdc_fb_var.yoffset = yoffset_old;
spin_unlock_irqrestore(&fb_data->queue_lock, flags);
mutex_lock(&fb_data->pxp_mutex);
@@ -1824,6 +1833,18 @@ static void epdc_submit_work_func(struct work_struct *work)
continue;
dev_dbg(fb_data->dev, "A collision update is ready to go!\n");
+
+ /* If update uses an out-of-date pan offset, we delete it */
+ if (next_update->fb_offset != fb_data->fb_offset) {
+ dev_dbg(fb_data->dev,
+ "Dropping update (old pan offset)\n");
+ list_del_init(&next_update->list);
+ /* Add to free buffer list */
+ list_add_tail(&next_update->list,
+ &fb_data->upd_buf_free_list->list);
+ continue;
+ }
+
/*
* We have a collision cleared, so select it for resubmission.
* If an update is already selected, attempt to merge.
@@ -1861,6 +1882,20 @@ static void epdc_submit_work_func(struct work_struct *work)
dev_dbg(fb_data->dev, "Found a pending update!\n");
+ /*
+ * Delete update if it is based on
+ * an out-of-date pan offset.
+ */
+ if (next_update->fb_offset != fb_data->fb_offset) {
+ dev_dbg(fb_data->dev,
+ "Dropping update (old pan offset)\n");
+ list_del_init(&next_update->list);
+ /* Add to free buffer list */
+ list_add_tail(&next_update->list,
+ &fb_data->upd_buf_free_list->list);
+ continue;
+ }
+
if (!upd_data_list) {
upd_data_list = next_update;
list_del_init(&next_update->list);
@@ -2430,8 +2465,8 @@ static int mxc_epdc_fb_pan_display(struct fb_var_screeninfo *var,
u_int y_bottom;
unsigned long flags;
- dev_dbg(info->device, "%s: var->xoffset %d, info->var.xoffset %d\n",
- __func__, var->xoffset, info->var.xoffset);
+ dev_dbg(info->device, "%s: var->yoffset %d, info->var.yoffset %d\n",
+ __func__, var->yoffset, info->var.yoffset);
/* check if var is valid; also, xpan is not supported */
if (!var || (var->xoffset != info->var.xoffset) ||
(var->yoffset + var->yres > var->yres_virtual)) {
@@ -2443,8 +2478,6 @@ static int mxc_epdc_fb_pan_display(struct fb_var_screeninfo *var,
(fb_data->epdc_fb_var.yoffset == var->yoffset))
return 0; /* No change, do nothing */
- spin_lock_irqsave(&fb_data->queue_lock, flags);
-
y_bottom = var->yoffset;
if (!(var->vmode & FB_VMODE_YWRAP))
@@ -2455,6 +2488,8 @@ static int mxc_epdc_fb_pan_display(struct fb_var_screeninfo *var,
return -EINVAL;
}
+ spin_lock_irqsave(&fb_data->queue_lock, flags);
+
fb_data->fb_offset = (var->yoffset * var->xres_virtual + var->xoffset)
* (var->bits_per_pixel) / 8;