From b80aa11ee88cc4a3a9764eb6312f011da15c566b Mon Sep 17 00:00:00 2001 From: Jason Chen Date: Wed, 14 Dec 2011 14:02:16 +0800 Subject: ENGR00170168-1 ipuv3 fb: add non FB_VMODE_YWRAP support when use pan display, the case could be: 1. a small window wrap in a big frame buffer 2. a frame switch in a serial buffers the ipuv3 fb driver used to support case 1, and for case 2, if the fb format is interleaved, there is no problem, but for non-interleaved format (like I420), there will be a display bug. Signed-off-by: Jason Chen --- drivers/video/mxc/mxc_ipuv3_fb.c | 63 +++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c index 70b7be1df0b..9ccafc2d95b 100644 --- a/drivers/video/mxc/mxc_ipuv3_fb.c +++ b/drivers/video/mxc/mxc_ipuv3_fb.c @@ -247,6 +247,7 @@ static int _setup_disp_channel2(struct fb_info *fbi) struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; int fb_stride; unsigned long base; + unsigned int fr_xoff, fr_yoff, fr_w, fr_h; switch (bpp_to_pixfmt(fbi)) { case IPU_PIX_FMT_YUV420P2: @@ -261,16 +262,28 @@ static int _setup_disp_channel2(struct fb_info *fbi) fb_stride = fbi->fix.line_length; } + base = fbi->fix.smem_start; + fr_xoff = fbi->var.xoffset; + fr_w = fbi->var.xres_virtual; + if (!(fbi->var.vmode & FB_VMODE_YWRAP)) { + dev_dbg(fbi->device, "Y wrap disabled\n"); + fr_yoff = fbi->var.yoffset % fbi->var.yres; + fr_h = fbi->var.yres; + base += fbi->fix.line_length * fbi->var.yres * + (fbi->var.yoffset / fbi->var.yres); + } else { + dev_dbg(fbi->device, "Y wrap enabled\n"); + fr_yoff = fbi->var.yoffset; + fr_h = fbi->var.yres_virtual; + } + base += fr_yoff * fb_stride + fr_xoff; + mxc_fbi->cur_ipu_buf = 2; sema_init(&mxc_fbi->flip_sem, 1); if (mxc_fbi->alpha_chan_en) { mxc_fbi->cur_ipu_alpha_buf = 1; sema_init(&mxc_fbi->alpha_flip_sem, 1); } - fbi->var.xoffset = 0; - - base = (fbi->var.yoffset * fb_stride + fbi->var.xoffset); - base += fbi->fix.smem_start; retval = ipu_init_channel_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch, IPU_INPUT_BUFFER, @@ -288,6 +301,17 @@ static int _setup_disp_channel2(struct fb_info *fbi) "ipu_init_channel_buffer error %d\n", retval); } + /* update u/v offset */ + ipu_update_channel_offset(mxc_fbi->ipu, mxc_fbi->ipu_ch, + IPU_INPUT_BUFFER, + bpp_to_pixfmt(fbi), + fr_w, + fr_h, + fr_w, + 0, 0, + fr_yoff, + fr_xoff); + if (mxc_fbi->alpha_chan_en) { retval = ipu_init_channel_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch, @@ -1224,6 +1248,7 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par, *mxc_graphic_fbi = NULL; u_int y_bottom; + unsigned int fr_xoff, fr_yoff, fr_w, fr_h; unsigned long base, active_alpha_phy_addr = 0; bool loc_alpha_en = false; int fb_stride; @@ -1250,9 +1275,6 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) y_bottom = var->yoffset; - if (!(var->vmode & FB_VMODE_YWRAP)) - y_bottom += var->yres; - if (y_bottom > info->var.yres_virtual) return -EINVAL; @@ -1269,8 +1291,21 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) fb_stride = info->fix.line_length; } - base = (var->yoffset * fb_stride + var->xoffset); - base += info->fix.smem_start; + base = info->fix.smem_start; + fr_xoff = var->xoffset; + fr_w = info->var.xres_virtual; + if (!(var->vmode & FB_VMODE_YWRAP)) { + dev_dbg(info->device, "Y wrap disabled\n"); + fr_yoff = var->yoffset % info->var.yres; + fr_h = info->var.yres; + base += info->fix.line_length * info->var.yres * + (var->yoffset / info->var.yres); + } else { + dev_dbg(info->device, "Y wrap enabled\n"); + fr_yoff = var->yoffset; + fr_h = info->var.yres_virtual; + } + base += fr_yoff * fb_stride + fr_xoff; /* Check if DP local alpha is enabled and find the graphic fb */ if (mxc_fbi->ipu_ch == MEM_BG_SYNC || mxc_fbi->ipu_ch == MEM_FG_SYNC) { @@ -1326,12 +1361,12 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) ipu_update_channel_offset(mxc_fbi->ipu, mxc_fbi->ipu_ch, IPU_INPUT_BUFFER, bpp_to_pixfmt(info), - info->var.xres_virtual, - info->var.yres_virtual, - info->var.xres_virtual, + fr_w, + fr_h, + fr_w, 0, 0, - var->yoffset, - var->xoffset); + fr_yoff, + fr_xoff); ipu_select_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch, IPU_INPUT_BUFFER, mxc_fbi->cur_ipu_buf); -- cgit v1.2.3