]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
ENGR00180103-3 V4L2: HDMI display error when dual display with LVDS panel
authorWayne Zou <b36644@freescale.com>
Sat, 28 Apr 2012 09:23:50 +0000 (17:23 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:34:32 +0000 (08:34 +0200)
Restore fb_var_screeninfo when finishing video playback

Signed-off-by: Wayne Zou <b36644@freescale.com>
drivers/media/video/mxc/output/mxc_vout.c

index 9d9be79dbb99e1500cb324602d3cc21bd9f65820..aebe57fda0c5c1d0d76c9d09e516fc8956e2f215 100644 (file)
@@ -56,9 +56,18 @@ struct mxc_vout_fb {
        bool disp_support_windows;
 };
 
+struct dma_mem {
+       void *vaddr;
+       dma_addr_t paddr;
+       size_t size;
+};
+
 struct mxc_vout_output {
        int open_cnt;
        struct fb_info *fbi;
+       unsigned long fb_smem_start;
+       unsigned long fb_smem_len;
+       struct fb_var_screeninfo fb_var;
        struct video_device *vfd;
        struct mutex mutex;
        struct mutex task_lock;
@@ -77,15 +86,13 @@ struct mxc_vout_output {
        bool disp_support_csc;
 
        bool fmt_init;
+       bool release;
+       bool save_var;
        bool bypass_pp;
        bool is_vdoaipu_task;
        struct ipu_task task;
        struct ipu_task vdoa_task;
-       struct vdoa_mem {
-               void *vaddr;
-               dma_addr_t paddr;
-               size_t size;
-       } vdoa_dma;
+       struct dma_mem vdoa_dma;
 
        bool timer_stop;
        struct timer_list timer;
@@ -428,6 +435,7 @@ static int show_buf(struct mxc_vout_output *vout, int idx,
        int ret;
        u32 is_1080p;
        u32 yres = 0;
+       u32 fb_base = 0;
 
        memcpy(&var, &fbi->var, sizeof(var));
 
@@ -437,11 +445,13 @@ static int show_buf(struct mxc_vout_output *vout, int idx,
                 * NOTE: should not do other fb operation during v4l2
                 */
                console_lock();
+               fb_base = fbi->fix.smem_start;
                fbi->fix.smem_start = vout->task.output.paddr;
                fbi->var.yoffset = ipos->y + 1;
                var.xoffset = ipos->x;
                var.yoffset = ipos->y;
                ret = fb_pan_display(fbi, &var);
+               fbi->fix.smem_start = fb_base;
                console_unlock();
        } else {
                console_lock();
@@ -603,6 +613,10 @@ static void disp_work_func(struct work_struct *work)
        spin_unlock_irqrestore(q->irqlock, flags);
 
        v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "disp work finish one frame\n");
+       if (!vout->save_var) {
+               memcpy(&vout->fb_var, &vout->fbi->var, sizeof(vout->fb_var));
+               vout->save_var = true;
+       }
 
        return;
 err:
@@ -1550,8 +1564,16 @@ static int config_disp_output(struct mxc_vout_output *vout)
        struct fb_var_screeninfo var;
        int i, display_buf_size, fb_num, ret;
        u32 is_1080p;
+       u32 fb_base;
+       u32 is_bg;
 
        memcpy(&var, &fbi->var, sizeof(var));
+       fb_base = fbi->fix.smem_start;
+       is_bg = get_ipu_channel(fbi);
+       if (is_bg == MEM_BG_SYNC) {
+               memcpy(&vout->fb_var, &fbi->var, sizeof(var));
+               vout->save_var = true;
+       }
 
        var.xres = vout->task.output.width;
        var.yres = vout->task.output.height;
@@ -1586,8 +1608,10 @@ static int config_disp_output(struct mxc_vout_output *vout)
                        var.xres, var.yres);
 
        ret = set_window_position(vout, &vout->win_pos);
-       if (ret < 0)
+       if (ret < 0) {
+               v4l2_err(vout->vfd->v4l2_dev, "ERR: set_win_pos ret:%d\n", ret);
                return ret;
+       }
 
        /* Init display channel through fb API */
        var.yoffset = 0;
@@ -1597,8 +1621,11 @@ static int config_disp_output(struct mxc_vout_output *vout)
        ret = fb_set_var(fbi, &var);
        fbi->flags &= ~FBINFO_MISC_USEREVENT;
        console_unlock();
-       if (ret < 0)
+       if (ret < 0) {
+               v4l2_err(vout->vfd->v4l2_dev,
+                               "ERR:%s fb_set_var ret:%d\n", __func__, ret);
                return ret;
+       }
 
        is_1080p = CHECK_TILED_1080P_DISPLAY(vout);
        if (is_1080p)
@@ -1608,11 +1635,22 @@ static int config_disp_output(struct mxc_vout_output *vout)
        for (i = 0; i < fb_num; i++)
                vout->disp_bufs[i] = fbi->fix.smem_start + i * display_buf_size;
 
+       vout->fb_smem_len = fbi->fix.smem_len;
+       vout->fb_smem_start = fbi->fix.smem_start;
+       if (fb_base != fbi->fix.smem_start) {
+               v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+                       "realloc fb mem size:0x%x@0x%lx,old paddr @0x%x\n",
+                       fbi->fix.smem_len, fbi->fix.smem_start, fb_base);
+               if (is_bg)
+                       vout->save_var = false;
+       }
+
        console_lock();
        fbi->flags |= FBINFO_MISC_USEREVENT;
        ret = fb_blank(fbi, FB_BLANK_UNBLANK);
        fbi->flags &= ~FBINFO_MISC_USEREVENT;
        console_unlock();
+       vout->release = false;
 
        return ret;
 }
@@ -1621,7 +1659,10 @@ static void release_disp_output(struct mxc_vout_output *vout)
 {
        struct fb_info *fbi = vout->fbi;
        struct mxcfb_pos pos;
+       int ret;
 
+       if (vout->release)
+               return;
        console_lock();
        fbi->flags |= FBINFO_MISC_USEREVENT;
        fb_blank(fbi, FB_BLANK_POWERDOWN);
@@ -1633,20 +1674,24 @@ static void release_disp_output(struct mxc_vout_output *vout)
        pos.y = 0;
        set_window_position(vout, &pos);
 
-       /* fix if ic bypass crack smem_start */
-       if (vout->bypass_pp) {
+       if (get_ipu_channel(fbi) == MEM_BG_SYNC) {
                console_lock();
-               fbi->fix.smem_start = vout->disp_bufs[0];
+               fbi->fix.smem_start = vout->fb_smem_start;
+               fbi->fix.smem_len = vout->fb_smem_len;
+               vout->fb_var.activate |= FB_ACTIVATE_FORCE;
+               fbi->flags |= FBINFO_MISC_USEREVENT;
+               ret = fb_set_var(fbi, &vout->fb_var);
+               fbi->flags &= ~FBINFO_MISC_USEREVENT;
                console_unlock();
-       }
-
-       if (get_ipu_channel(fbi) == MEM_BG_SYNC) {
+               if (ret < 0)
+                       v4l2_err(vout->vfd->v4l2_dev, "ERR: fb_set_var.\n");
                console_lock();
                fbi->flags |= FBINFO_MISC_USEREVENT;
                fb_blank(fbi, FB_BLANK_UNBLANK);
                fbi->flags &= ~FBINFO_MISC_USEREVENT;
                console_unlock();
        }
+       vout->release = true;
 }
 
 static int mxc_vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)