summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorLiu Ying <Ying.Liu@freescale.com>2015-09-11 16:03:06 +0800
committerNitin Garg <nitin.garg@nxp.com>2016-01-14 11:01:47 -0600
commita04c581248bdafee8b335c1f4f509784076d6c83 (patch)
treed8a44ce0333f4daa1b7c71aa714f57fa1f0f5c5d /drivers/video
parent8573397f949fd03652cd8524b693cd4f0450b096 (diff)
MLK-11316-3 video: mxc ipuv3 fb: Change pan display mechanism for PRE workaround
In order to workaround the PRE SoC bug recorded by errata ERR009624, the software cannot write the PRE_CTRL register when the PRE writes the PRE_CTRL register automatically to set the ENABLE bit(bit0) to 1 in the PRE repeat mode. The software mechanism to set the PRE_CTRL register is different for PRE Y resolution higher than 9 lines and lower than or equal to 9 lines. For cases in which Y resolution is higher than 9 lines, before we update PRE shadow, we just need to wait until the PRE store engine status runs out of the problematic PRE automatic writing window. While for cases in which Y resolutin is lower than or equal to 9 lines, we have to update PRE shadow in the buffer flip interrupt handler. Signed-off-by: Liu Ying <Ying.Liu@freescale.com> (cherry picked from commit bd9c14e24aaf67926dfd31bd819ab0c87129fe4b)
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbdev/mxc/mxc_ipuv3_fb.c91
1 files changed, 74 insertions, 17 deletions
diff --git a/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c b/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c
index 355b4778e1d8..77a634c3b916 100644
--- a/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c
+++ b/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c
@@ -83,6 +83,11 @@ struct mxcfb_info {
bool on_the_fly;
uint32_t final_pfmt;
unsigned long gpu_sec_buf_off;
+ unsigned long base;
+ uint32_t x_crop;
+ uint32_t y_crop;
+ unsigned int sec_buf_off;
+ unsigned int trd_buf_off;
dma_addr_t store_addr;
dma_addr_t alpha_phy_addr0;
dma_addr_t alpha_phy_addr1;
@@ -111,6 +116,7 @@ struct mxcfb_info {
uint32_t cur_ipu_pfmt;
uint32_t cur_fb_pfmt;
bool cur_prefetch;
+ spinlock_t spin_lock; /* for PRE small yres cases */
};
struct mxcfb_pfmt {
@@ -530,7 +536,9 @@ static int _setup_disp_channel2(struct fb_info *fbi)
* so we call complete() for both mxc_fbi->flip_complete
* and mxc_fbi->alpha_flip_complete.
*/
- complete(&mxc_fbi->flip_complete);
+ if (!mxc_fbi->prefetch ||
+ (mxc_fbi->prefetch && !ipu_pre_yres_is_small(fbi->var.yres)))
+ complete(&mxc_fbi->flip_complete);
if (mxc_fbi->alpha_chan_en) {
mxc_fbi->cur_ipu_alpha_buf = 1;
init_completion(&mxc_fbi->alpha_flip_complete);
@@ -2309,8 +2317,6 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
*mxc_graphic_fbi = NULL;
u_int y_bottom;
unsigned int fr_xoff, fr_yoff, fr_w, fr_h;
- unsigned int x_crop = 0, y_crop = 0;
- unsigned int sec_buf_off = 0, trd_buf_off = 0;
unsigned long base, ipu_base = 0, active_alpha_phy_addr = 0;
bool loc_alpha_en = false;
int fb_stride;
@@ -2392,12 +2398,27 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
if (mxc_fbi->cur_prefetch && (info->var.vmode & FB_VMODE_INTERLACED))
base += info->var.rotate ?
fr_w * bytes_per_pixel(fbi_to_pixfmt(info, true)) : 0;
- } else {
- x_crop = fr_xoff & ~(bw - 1);
- y_crop = fr_yoff & ~(bh - 1);
}
if (mxc_fbi->cur_prefetch) {
+ unsigned long lock_flags = 0;
+
+ if (ipu_pre_yres_is_small(info->var.yres))
+ /*
+ * Update the PRE buffer address in the flip interrupt
+ * handler in this case to workaround the SoC design
+ * bug recorded by errata ERR009624.
+ */
+ spin_lock_irqsave(&mxc_fbi->spin_lock, lock_flags);
+
+ if (mxc_fbi->resolve) {
+ mxc_fbi->x_crop = fr_xoff & ~(bw - 1);
+ mxc_fbi->y_crop = fr_yoff & ~(bh - 1);
+ } else {
+ mxc_fbi->x_crop = 0;
+ mxc_fbi->y_crop = 0;
+ }
+
ipu_get_channel_offset(fbi_to_pixfmt(info, true),
info->var.xres,
fr_h,
@@ -2405,10 +2426,15 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
0, 0,
fr_yoff,
fr_xoff,
- &sec_buf_off,
- &trd_buf_off);
+ &mxc_fbi->sec_buf_off,
+ &mxc_fbi->trd_buf_off);
if (mxc_fbi->resolve)
- sec_buf_off = mxc_fbi->gpu_sec_buf_off;
+ mxc_fbi->sec_buf_off = mxc_fbi->gpu_sec_buf_off;
+
+ if (ipu_pre_yres_is_small(info->var.yres)) {
+ mxc_fbi->base = base;
+ spin_unlock_irqrestore(&mxc_fbi->spin_lock, lock_flags);
+ }
} else {
ipu_base = base;
}
@@ -2441,10 +2467,15 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
}
}
- ret = wait_for_completion_timeout(&mxc_fbi->flip_complete, HZ/2);
- if (ret == 0) {
- dev_err(info->device, "timeout when waiting for flip irq\n");
- return -ETIMEDOUT;
+ if (!mxc_fbi->cur_prefetch ||
+ (mxc_fbi->cur_prefetch && !ipu_pre_yres_is_small(info->var.yres))) {
+ ret = wait_for_completion_timeout(&mxc_fbi->flip_complete,
+ HZ/2);
+ if (ret == 0) {
+ dev_err(info->device, "timeout when waiting for flip "
+ "irq\n");
+ return -ETIMEDOUT;
+ }
}
if (!mxc_fbi->cur_prefetch) {
@@ -2486,10 +2517,14 @@ next:
ipu_select_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch,
IPU_INPUT_BUFFER, mxc_fbi->cur_ipu_buf);
- } else {
- ipu_pre_set_fb_buffer(mxc_fbi->pre_num, base,
- x_crop, y_crop,
- sec_buf_off, trd_buf_off);
+ } else if (!ipu_pre_yres_is_small(info->var.yres)) {
+ ipu_pre_set_fb_buffer(mxc_fbi->pre_num,
+ mxc_fbi->resolve,
+ base, info->var.yres,
+ mxc_fbi->x_crop,
+ mxc_fbi->y_crop,
+ mxc_fbi->sec_buf_off,
+ mxc_fbi->trd_buf_off);
}
ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
@@ -2518,6 +2553,16 @@ next:
return -EBUSY;
}
+ if (mxc_fbi->cur_prefetch && ipu_pre_yres_is_small(info->var.yres)) {
+ ret = wait_for_completion_timeout(&mxc_fbi->flip_complete,
+ HZ/2);
+ if (ret == 0) {
+ dev_err(info->device, "timeout when waiting for flip "
+ "irq\n");
+ return -ETIMEDOUT;
+ }
+ }
+
dev_dbg(info->device, "Update complete\n");
info->var.yoffset = var->yoffset;
@@ -2605,6 +2650,17 @@ static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id)
struct fb_info *fbi = dev_id;
struct mxcfb_info *mxc_fbi = fbi->par;
+ if (mxc_fbi->cur_prefetch && ipu_pre_yres_is_small(fbi->var.yres)) {
+ spin_lock(&mxc_fbi->spin_lock);
+ ipu_pre_set_fb_buffer(mxc_fbi->pre_num,
+ mxc_fbi->resolve,
+ mxc_fbi->base, fbi->var.yres,
+ mxc_fbi->x_crop, mxc_fbi->y_crop,
+ mxc_fbi->sec_buf_off,
+ mxc_fbi->trd_buf_off);
+ spin_unlock(&mxc_fbi->spin_lock);
+ }
+
complete(&mxc_fbi->flip_complete);
return IRQ_HANDLED;
}
@@ -3382,6 +3438,7 @@ static int mxcfb_probe(struct platform_device *pdev)
mxcfbi->first_set_par = true;
mxcfbi->prefetch = plat_data->prefetch;
mxcfbi->pre_num = -1;
+ spin_lock_init(&mxcfbi->spin_lock);
ret = mxcfb_dispdrv_init(pdev, fbi);
if (ret < 0)