summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c
diff options
context:
space:
mode:
authorLiu Ying <Ying.Liu@freescale.com>2015-09-11 17:36:39 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:23:25 +0800
commit0dd6cc3e8f9bab60707426af9e85377d5cb807a6 (patch)
treec8b540a8cb4cdc7b23c40de5ee7e3b8673f3b3d1 /drivers/video/fbdev/mxc/mxc_ipuv3_fb.c
parent14f5226b4609a5b94235e0a33c295ac147d97b28 (diff)
MLK-11316-4 video: mxc ipuv3 fb: Change on-the-fly switch 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. Instead of setting the PRE_CTRL register any time we want to do on-the-fly switch(PRE keeps working before and after the switch), we change to set the register in the on-the-fly configuration interrupt(EOF) handler. This way, we may avoid encountering the problematic PRE automatic writing cycle for sure. Signed-off-by: Liu Ying <Ying.Liu@freescale.com> (cherry picked from commit 6218cbcf34f5fb7910a824a8d31cc58819d0bd00)
Diffstat (limited to 'drivers/video/fbdev/mxc/mxc_ipuv3_fb.c')
-rw-r--r--drivers/video/fbdev/mxc/mxc_ipuv3_fb.c55
1 files changed, 46 insertions, 9 deletions
diff --git a/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c b/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c
index 77a634c3b916..3af13e6f0e46 100644
--- a/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c
+++ b/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c
@@ -106,6 +106,7 @@ struct mxcfb_info {
struct completion flip_complete;
struct completion alpha_flip_complete;
struct completion vsync_complete;
+ struct completion otf_complete; /* on the fly */
void *ipu;
struct fb_info *ovfbi;
@@ -117,6 +118,7 @@ struct mxcfb_info {
uint32_t cur_fb_pfmt;
bool cur_prefetch;
spinlock_t spin_lock; /* for PRE small yres cases */
+ struct ipu_pre_context *pre_config;
};
struct mxcfb_pfmt {
@@ -417,6 +419,8 @@ static irqreturn_t mxcfb_nf_irq_handler(int irq, void *dev_id);
static int mxcfb_blank(int blank, struct fb_info *info);
static int mxcfb_map_video_memory(struct fb_info *fbi);
static int mxcfb_unmap_video_memory(struct fb_info *fbi);
+static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd,
+ unsigned long arg);
/*
* Set fixed framebuffer parameters based on variable settings.
@@ -566,7 +570,7 @@ static int _setup_disp_channel2(struct fb_info *fbi)
pre.handshake_en = true;
pre.hsk_abort_en = true;
pre.hsk_line_num = 0;
- pre.sdw_update = false;
+ pre.sdw_update = true;
pre.cur_buf = base;
pre.next_buf = pre.cur_buf;
if (fbi->var.vmode & FB_VMODE_INTERLACED) {
@@ -712,15 +716,41 @@ static int _setup_disp_channel2(struct fb_info *fbi)
ipu_base = pre.store_addr;
mxc_fbi->store_addr = ipu_base;
- retval = ipu_pre_set_ctrl(mxc_fbi->pre_num, &pre);
- if (retval < 0)
- return retval;
+ if (mxc_fbi->cur_prefetch && mxc_fbi->on_the_fly) {
+ /*
+ * Make sure any pending interrupt is handled so that
+ * the buffer panned can start to be scanned out.
+ */
+ if (!ipu_pre_yres_is_small(fbi->var.yres)) {
+ mxcfb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC,
+ (unsigned long)fbi->par);
+ mxcfb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC,
+ (unsigned long)fbi->par);
+ }
- retval = ipu_pre_sdw_update(mxc_fbi->pre_num);
- if (retval < 0) {
- dev_err(fbi->device,
- "failed to update PRE shadow reg %d\n", retval);
- return retval;
+ mxc_fbi->pre_config = &pre;
+
+ /*
+ * Write the PRE control register in the flip interrupt
+ * handler in this on-the-fly case to workaround the
+ * SoC design bug recorded by errata ERR009624.
+ */
+ init_completion(&mxc_fbi->otf_complete);
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ retval = wait_for_completion_timeout(
+ &mxc_fbi->otf_complete, HZ/2);
+ if (retval == 0) {
+ dev_err(fbi->device, "timeout when waiting "
+ "for on the fly config irq\n");
+ return -ETIMEDOUT;
+ } else {
+ retval = 0;
+ }
+ } else {
+ retval = ipu_pre_set_ctrl(mxc_fbi->pre_num, &pre);
+ if (retval < 0)
+ return retval;
}
if (!mxc_fbi->on_the_fly || !mxc_fbi->cur_prefetch) {
@@ -2650,6 +2680,13 @@ 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->pre_config) {
+ ipu_pre_set_ctrl(mxc_fbi->pre_num, mxc_fbi->pre_config);
+ mxc_fbi->pre_config = NULL;
+ complete(&mxc_fbi->otf_complete);
+ return IRQ_HANDLED;
+ }
+
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,