diff options
author | Liu Ying <Ying.Liu@freescale.com> | 2015-09-11 16:03:06 +0800 |
---|---|---|
committer | Nitin Garg <nitin.garg@nxp.com> | 2016-01-14 11:01:47 -0600 |
commit | a04c581248bdafee8b335c1f4f509784076d6c83 (patch) | |
tree | d8a44ce0333f4daa1b7c71aa714f57fa1f0f5c5d /drivers/video | |
parent | 8573397f949fd03652cd8524b693cd4f0450b096 (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.c | 91 |
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) |