From c98b98bd2b115e1bd44dbb57dbd93a15cbb76751 Mon Sep 17 00:00:00 2001 From: Wayne Zou Date: Sat, 28 Apr 2012 17:23:50 +0800 Subject: [PATCH] ENGR00180103-3 V4L2: HDMI display error when dual display with LVDS panel Restore fb_var_screeninfo when finishing video playback Signed-off-by: Wayne Zou --- drivers/media/video/mxc/output/mxc_vout.c | 71 ++++++++++++++++++----- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/drivers/media/video/mxc/output/mxc_vout.c b/drivers/media/video/mxc/output/mxc_vout.c index 9d9be79dbb99..aebe57fda0c5 100644 --- a/drivers/media/video/mxc/output/mxc_vout.c +++ b/drivers/media/video/mxc/output/mxc_vout.c @@ -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) -- 2.39.5