MLK-11316-4 video: mxc ipuv3 fb: Change on-the-fly switch mechanism for PRE workaround
authorLiu Ying <Ying.Liu@freescale.com>
Fri, 11 Sep 2015 09:36:39 +0000 (17:36 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:48:48 +0000 (14:48 -0500)
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)

drivers/video/fbdev/mxc/mxc_ipuv3_fb.c

index 77a634c..3af13e6 100644 (file)
@@ -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,