summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWayne Zou <b36644@freescale.com>2012-04-28 17:23:50 +0800
committerFrank Li <Frank.Li@freescale.com>2012-04-30 16:15:52 +0800
commit10bd8dec850cc864441a1b096c524c34c4ff45c1 (patch)
treea3d9574af85c06e400c528018bf1c4b59cc5cf4d
parentf264d2369a32040e6b72245bdf9caf24ac3e0429 (diff)
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 <b36644@freescale.com>
-rw-r--r--drivers/media/video/mxc/output/mxc_vout.c71
1 files 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)