diff options
author | Liu Ying <b17645@freescale.com> | 2009-07-13 15:41:36 +0800 |
---|---|---|
committer | Jason Chen <b02280@freescale.com> | 2009-08-27 10:41:51 +0800 |
commit | 3f54b1f3e97dd9e302574fa24b74bf33182b5537 (patch) | |
tree | dab3fd211ec35063c35c91e1b786ebb8c54c8105 | |
parent | 45bf725c596b43a7173f040df0227be733cce744 (diff) |
ENGR00113878 IPUv3:Support DP alpha blending
Support DP alpha blending with alpha value contained in separate channel.
Signed-off-by: Liu Ying <b17645@freescale.com>
-rw-r--r-- | drivers/media/video/mxc/capture/ipu_prp_vf_sdc.c | 228 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mxc_v4l2_capture.c | 68 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_common.c | 32 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_disp.c | 32 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_param_mem.h | 24 | ||||
-rw-r--r-- | drivers/video/mxc/mxc_ipuv3_fb.c | 109 | ||||
-rw-r--r-- | include/linux/ipu.h | 2 | ||||
-rw-r--r-- | include/linux/mxcfb.h | 8 |
8 files changed, 310 insertions, 193 deletions
diff --git a/drivers/media/video/mxc/capture/ipu_prp_vf_sdc.c b/drivers/media/video/mxc/capture/ipu_prp_vf_sdc.c index 465630de5e28..f4ec31e975cb 100644 --- a/drivers/media/video/mxc/capture/ipu_prp_vf_sdc.c +++ b/drivers/media/video/mxc/capture/ipu_prp_vf_sdc.c @@ -20,7 +20,9 @@ */ #include <linux/dma-mapping.h> +#include <linux/console.h> #include <linux/ipu.h> +#include <linux/mxcfb.h> #include "mxc_v4l2_capture.h" #include "ipu_prp_sw.h" @@ -36,11 +38,13 @@ */ static int prpvf_start(void *private) { + struct fb_var_screeninfo fbvar; + struct fb_info *fbi = NULL; cam_data *cam = (cam_data *) private; - ipu_channel_params_t vf, params; + ipu_channel_params_t vf; u32 format = IPU_PIX_FMT_RGB565; u32 size = 2, temp = 0; - int err = 0; + int err = 0, i = 0; if (!cam) { printk(KERN_ERR "private is NULL\n"); @@ -52,6 +56,17 @@ static int prpvf_start(void *private) return 0; } + for (i = 0; i < num_registered_fb; i++) { + char *idstr = registered_fb[i]->fix.id; + if (strcmp(idstr, "DISP3 FG") == 0) + fbi = registered_fb[i]; + } + + if (fbi == NULL) { + printk(KERN_ERR "DISP3 FG fb not found\n"); + return -EPERM; + } + memset(&vf, 0, sizeof(ipu_channel_params_t)); ipu_csi_get_window_size(&vf.csi_prp_vf_mem.in_width, &vf.csi_prp_vf_mem.in_height, cam->csi); @@ -68,7 +83,7 @@ static int prpvf_start(void *private) err = ipu_init_channel(CSI_PRP_VF_MEM, &vf); if (err != 0) - goto out_4; + goto out_5; ipu_csi_enable_mclk_if(CSI_MCLK_VF, cam->csi, true, true); @@ -92,7 +107,7 @@ static int prpvf_start(void *private) if (cam->vf_bufs_vaddr[0] == NULL) { printk(KERN_ERR "Error to allocate vf buffer\n"); err = -ENOMEM; - goto out_3; + goto out_4; } cam->vf_bufs_size[1] = PAGE_ALIGN(size); cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, @@ -109,6 +124,20 @@ static int prpvf_start(void *private) pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]); if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { + fbvar = fbi->var; + + fbvar.bits_per_pixel = 16; + fbvar.nonstd = 0; + fbvar.xres = fbvar.xres_virtual = vf.csi_prp_vf_mem.out_height; + fbvar.yres = vf.csi_prp_vf_mem.out_width; + fbvar.yres_virtual = vf.csi_prp_vf_mem.out_width * 2; + + fbvar.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbvar); + + ipu_disp_set_window_pos(MEM_FG_SYNC, cam->win.w.left, + cam->win.w.top); + err = ipu_init_channel_buffer(CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, format, vf.csi_prp_vf_mem.out_width, @@ -120,53 +149,6 @@ static int prpvf_start(void *private) goto out_3; } - if (cam->rot_vf_bufs[0]) { - dma_free_coherent(0, cam->rot_vf_buf_size[0], - cam->rot_vf_bufs_vaddr[0], - (dma_addr_t) cam->rot_vf_bufs[0]); - cam->rot_vf_bufs_vaddr[0] = NULL; - cam->rot_vf_bufs[0] = 0; - } - if (cam->rot_vf_bufs[1]) { - dma_free_coherent(0, cam->rot_vf_buf_size[1], - cam->rot_vf_bufs_vaddr[1], - (dma_addr_t) cam->rot_vf_bufs[1]); - cam->rot_vf_bufs_vaddr[1] = NULL; - cam->rot_vf_bufs[1] = 0; - } - cam->rot_vf_buf_size[0] = PAGE_ALIGN(size); - cam->rot_vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0, - cam-> - rot_vf_buf_size - [0], - &cam-> - rot_vf_bufs - [0], - GFP_DMA | - GFP_KERNEL); - if (cam->rot_vf_bufs_vaddr[0] == NULL) { - printk(KERN_ERR "alloc rot_vf_bufs.\n"); - err = -ENOMEM; - goto out_3; - } - cam->rot_vf_buf_size[1] = PAGE_ALIGN(size); - cam->rot_vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, - cam-> - rot_vf_buf_size - [0], - &cam-> - rot_vf_bufs - [1], - GFP_DMA | - GFP_KERNEL); - if (cam->rot_vf_bufs_vaddr[1] == NULL) { - printk(KERN_ERR "alloc rot_vf_bufs.\n"); - err = -ENOMEM; - goto out_3; - } - pr_debug("rot_vf_bufs %x %x\n", cam->rot_vf_bufs[0], - cam->rot_vf_bufs[1]); - err = ipu_init_channel(MEM_ROT_VF_MEM, NULL); if (err != 0) { printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n"); @@ -182,7 +164,7 @@ static int prpvf_start(void *private) cam->vf_bufs[1], 0, 0); if (err != 0) { printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n"); - goto out_3; + goto out_2; } if (cam->vf_rotation < IPU_ROTATE_90_RIGHT) { @@ -198,8 +180,11 @@ static int prpvf_start(void *private) vf.csi_prp_vf_mem.out_width, vf.csi_prp_vf_mem.out_height, IPU_ROTATE_NONE, - cam->rot_vf_bufs[0], - cam->rot_vf_bufs[1], 0, 0); + fbi->fix.smem_start + + (fbi->fix.line_length * + fbi->var.yres), + fbi->fix.smem_start, 0, 0); + if (err != 0) { printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n"); goto out_2; @@ -212,29 +197,6 @@ static int prpvf_start(void *private) goto out_2; } - memset(¶ms, 0, sizeof(ipu_channel_params_t)); - params.mem_dp_fg_sync.in_pixel_fmt = format; - params.mem_dp_fg_sync.out_pixel_fmt = IPU_PIX_FMT_RGB24; - err = ipu_init_channel(MEM_FG_SYNC, ¶ms); - if (err != 0) - goto out_2; - - ipu_disp_set_window_pos(MEM_FG_SYNC, cam->win.w.left, - cam->win.w.top); - - err = ipu_init_channel_buffer(MEM_FG_SYNC, IPU_INPUT_BUFFER, - format, - vf.csi_prp_vf_mem.out_height, - vf.csi_prp_vf_mem.out_width, - vf.csi_prp_vf_mem.out_height, - IPU_ROTATE_NONE, - cam->rot_vf_bufs[0], - cam->rot_vf_bufs[1], 0, 0); - if (err != 0) { - printk(KERN_ERR "Error initializing SDC FG buffer\n"); - goto out_2; - } - err = ipu_link_channels(MEM_ROT_VF_MEM, MEM_FG_SYNC); if (err < 0) { printk(KERN_ERR @@ -244,69 +206,66 @@ static int prpvf_start(void *private) ipu_enable_channel(CSI_PRP_VF_MEM); ipu_enable_channel(MEM_ROT_VF_MEM); - ipu_enable_channel(MEM_FG_SYNC); ipu_select_buffer(CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0); ipu_select_buffer(CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 1); ipu_select_buffer(MEM_ROT_VF_MEM, IPU_OUTPUT_BUFFER, 0); ipu_select_buffer(MEM_ROT_VF_MEM, IPU_OUTPUT_BUFFER, 1); } else { + fbvar = fbi->var; + + fbvar.bits_per_pixel = 16; + fbvar.nonstd = 0; + fbvar.xres = fbvar.xres_virtual = vf.csi_prp_vf_mem.out_width; + fbvar.yres = vf.csi_prp_vf_mem.out_height; + fbvar.yres_virtual = vf.csi_prp_vf_mem.out_height * 2; + + fbvar.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbvar); + + ipu_disp_set_window_pos(MEM_FG_SYNC, cam->win.w.left, + cam->win.w.top); + err = ipu_init_channel_buffer(CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, format, cam->win.w.width, cam->win.w.height, - cam->win.w.width, cam->vf_rotation, - cam->vf_bufs[0], cam->vf_bufs[1], - 0, 0); + cam->win.w.width, + cam->vf_rotation, + fbi->fix.smem_start + + (fbi->fix.line_length * + fbi->var.yres), + fbi->fix.smem_start, 0, 0); if (err != 0) { printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n"); goto out_4; } - memset(¶ms, 0, sizeof(ipu_channel_params_t)); - params.mem_dp_fg_sync.in_pixel_fmt = format; - params.mem_dp_fg_sync.out_pixel_fmt = IPU_PIX_FMT_RGB24; - err = ipu_init_channel(MEM_FG_SYNC, ¶ms); - if (err != 0) - goto out_3; - - ipu_disp_set_window_pos(MEM_FG_SYNC, cam->win.w.left, - cam->win.w.top); - err = ipu_init_channel_buffer(MEM_FG_SYNC, - IPU_INPUT_BUFFER, format, - cam->win.w.width, - cam->win.w.height, - cam->win.w.width, IPU_ROTATE_NONE, - cam->vf_bufs[0], cam->vf_bufs[1], - 0, 0); - if (err != 0) { - printk(KERN_ERR "Error initializing SDC FG buffer\n"); - goto out_1; - } err = ipu_link_channels(CSI_PRP_VF_MEM, MEM_FG_SYNC); if (err < 0) { printk(KERN_ERR "Error linking ipu channels\n"); - goto out_1; + goto out_4; } ipu_enable_channel(CSI_PRP_VF_MEM); - ipu_enable_channel(MEM_FG_SYNC); ipu_select_buffer(CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0); ipu_select_buffer(CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 1); } + acquire_console_sem(); + fb_blank(fbi, FB_BLANK_UNBLANK); + release_console_sem(); + cam->overlay_active = true; return err; - out_1: - ipu_uninit_channel(MEM_FG_SYNC); - out_2: +out_1: + ipu_unlink_channels(CSI_PRP_VF_MEM, MEM_ROT_VF_MEM); +out_2: if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { ipu_uninit_channel(MEM_ROT_VF_MEM); } - out_3: - ipu_uninit_channel(CSI_PRP_VF_MEM); - out_4: +out_3: if (cam->vf_bufs_vaddr[0]) { dma_free_coherent(0, cam->vf_bufs_size[0], cam->vf_bufs_vaddr[0], @@ -321,20 +280,9 @@ static int prpvf_start(void *private) cam->vf_bufs_vaddr[1] = NULL; cam->vf_bufs[1] = 0; } - if (cam->rot_vf_bufs_vaddr[0]) { - dma_free_coherent(0, cam->rot_vf_buf_size[0], - cam->rot_vf_bufs_vaddr[0], - (dma_addr_t) cam->rot_vf_bufs[0]); - cam->rot_vf_bufs_vaddr[0] = NULL; - cam->rot_vf_bufs[0] = 0; - } - if (cam->rot_vf_bufs_vaddr[1]) { - dma_free_coherent(0, cam->rot_vf_buf_size[1], - cam->rot_vf_bufs_vaddr[1], - (dma_addr_t) cam->rot_vf_bufs[1]); - cam->rot_vf_bufs_vaddr[1] = NULL; - cam->rot_vf_bufs[1] = 0; - } +out_4: + ipu_uninit_channel(CSI_PRP_VF_MEM); +out_5: return err; } @@ -347,11 +295,23 @@ static int prpvf_start(void *private) static int prpvf_stop(void *private) { cam_data *cam = (cam_data *) private; - int err = 0; + int err = 0, i = 0; + struct fb_info *fbi = NULL; if (cam->overlay_active == false) return 0; + for (i = 0; i < num_registered_fb; i++) { + char *idstr = registered_fb[i]->fix.id; + if (strcmp(idstr, "DISP3 FG") == 0) + fbi = registered_fb[i]; + } + + if (fbi == NULL) { + printk(KERN_ERR "DISP3 FG fb not found\n"); + return -EPERM; + } + ipu_disp_set_window_pos(MEM_FG_SYNC, 0, 0); if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { @@ -361,16 +321,18 @@ static int prpvf_stop(void *private) ipu_unlink_channels(CSI_PRP_VF_MEM, MEM_FG_SYNC); } - ipu_disable_channel(MEM_FG_SYNC, true); ipu_disable_channel(CSI_PRP_VF_MEM, true); if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { ipu_disable_channel(MEM_ROT_VF_MEM, true); ipu_uninit_channel(MEM_ROT_VF_MEM); } - ipu_uninit_channel(MEM_FG_SYNC); ipu_uninit_channel(CSI_PRP_VF_MEM); + acquire_console_sem(); + fb_blank(fbi, FB_BLANK_POWERDOWN); + release_console_sem(); + ipu_csi_enable_mclk_if(CSI_MCLK_VF, cam->csi, false, false); if (cam->vf_bufs_vaddr[0]) { @@ -387,20 +349,6 @@ static int prpvf_stop(void *private) cam->vf_bufs_vaddr[1] = NULL; cam->vf_bufs[1] = 0; } - if (cam->rot_vf_bufs_vaddr[0]) { - dma_free_coherent(0, cam->rot_vf_buf_size[0], - cam->rot_vf_bufs_vaddr[0], - (dma_addr_t) cam->rot_vf_bufs[0]); - cam->rot_vf_bufs_vaddr[0] = NULL; - cam->rot_vf_bufs[0] = 0; - } - if (cam->rot_vf_bufs_vaddr[1]) { - dma_free_coherent(0, cam->rot_vf_buf_size[1], - cam->rot_vf_bufs_vaddr[1], - (dma_addr_t) cam->rot_vf_bufs[1]); - cam->rot_vf_bufs_vaddr[1] = NULL; - cam->rot_vf_bufs[1] = 0; - } cam->overlay_active = false; return err; diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c index a05f4b896f34..f2bc8d0eebea 100644 --- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c @@ -42,11 +42,11 @@ static int video_nr = -1; static cam_data *g_cam; /*! This data is used for the output to the display. */ -#define MXC_V4L2_CAPTURE_NUM_OUTPUTS 2 +#define MXC_V4L2_CAPTURE_NUM_OUTPUTS 3 static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = { { .index = 0, - .name = "DISP3", + .name = "DISP3 BG", .type = V4L2_OUTPUT_TYPE_ANALOG, .audioset = 0, .modulator = 0, @@ -59,7 +59,15 @@ static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = { .audioset = 0, .modulator = 0, .std = V4L2_STD_UNKNOWN, - } + }, + { + .index = 2, + .name = "DISP3 FG", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .audioset = 0, + .modulator = 0, + .std = V4L2_STD_UNKNOWN, + }, }; /*! List of TV input video formats supported. The video formats is corresponding @@ -380,8 +388,10 @@ static int mxc_streamoff(cam_data *cam) */ static int verify_preview(cam_data *cam, struct v4l2_window *win) { - int i = 0; + int i = 0, width_bound = 0, height_bound = 0; int *width, *height; + struct fb_info *bg_fbi = NULL; + bool foregound_fb; pr_debug("In MVC: verify_preview\n"); @@ -391,23 +401,41 @@ static int verify_preview(cam_data *cam, struct v4l2_window *win) pr_err("ERROR: verify_preview frame buffer NULL.\n"); return -1; } - if (strncmp(cam->overlay_fb->fix.id, - mxc_capture_outputs[cam->output].name, 5) == 0) { + if (strcmp(cam->overlay_fb->fix.id, "DISP3 BG") == 0) + bg_fbi = cam->overlay_fb; + if (strcmp(cam->overlay_fb->fix.id, + mxc_capture_outputs[cam->output].name) == 0) { + if (strcmp(cam->overlay_fb->fix.id, "DISP3 FG") == 0) + foregound_fb = true; break; } } while (++i < FB_MAX); - /* 4 bytes alignment for both FG and BG */ - if (cam->overlay_fb->var.bits_per_pixel == 24) { - win->w.left -= win->w.left % 4; - } else if (cam->overlay_fb->var.bits_per_pixel == 16) { - win->w.left -= win->w.left % 2; - } + if (foregound_fb) { + width_bound = bg_fbi->var.xres; + height_bound = bg_fbi->var.yres; - if (win->w.width + win->w.left > cam->overlay_fb->var.xres) - win->w.width = cam->overlay_fb->var.xres - win->w.left; - if (win->w.height + win->w.top > cam->overlay_fb->var.yres) - win->w.height = cam->overlay_fb->var.yres - win->w.top; + if (win->w.width + win->w.left > bg_fbi->var.xres || + win->w.height + win->w.top > bg_fbi->var.yres) { + pr_err("ERROR: FG window position exceeds.\n"); + return -1; + } + } else { + /* 4 bytes alignment for BG */ + width_bound = cam->overlay_fb->var.xres; + height_bound = cam->overlay_fb->var.yres; + + if (cam->overlay_fb->var.bits_per_pixel == 24) { + win->w.left -= win->w.left % 4; + } else if (cam->overlay_fb->var.bits_per_pixel == 16) { + win->w.left -= win->w.left % 2; + } + + if (win->w.width + win->w.left > cam->overlay_fb->var.xres) + win->w.width = cam->overlay_fb->var.xres - win->w.left; + if (win->w.height + win->w.top > cam->overlay_fb->var.yres) + win->w.height = cam->overlay_fb->var.yres - win->w.top; + } /* stride line limitation */ win->w.height -= win->w.height % 8; @@ -427,7 +455,7 @@ static int verify_preview(cam_data *cam, struct v4l2_window *win) *width = cam->crop_bounds.width / 8; if (*width % 8) *width += 8 - *width % 8; - if (*width + win->w.left > cam->overlay_fb->var.xres) { + if (*width + win->w.left > width_bound) { pr_err("ERROR: v4l2 capture: width exceeds " "resize limit.\n"); return -1; @@ -443,7 +471,7 @@ static int verify_preview(cam_data *cam, struct v4l2_window *win) *height = cam->crop_bounds.height / 8; if (*height % 8) *height += 8 - *height % 8; - if (*height + win->w.top > cam->overlay_fb->var.yres) { + if (*height + win->w.top > height_bound) { pr_err("ERROR: v4l2 capture: height exceeds " "resize limit.\n"); return -1; @@ -471,7 +499,7 @@ static int start_preview(cam_data *cam) #if defined(CONFIG_MXC_IPU_PRP_VF_SDC) || defined(CONFIG_MXC_IPU_PRP_VF_SDC_MODULE) pr_debug(" This is an SDC display\n"); - if (cam->output == 0) { + if (cam->output == 0 || cam->output == 2) { if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) err = prp_vf_sdc_select(cam); else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY) @@ -530,7 +558,7 @@ static int stop_preview(cam_data *cam) #endif #if defined(CONFIG_MXC_IPU_PRP_VF_SDC) || defined(CONFIG_MXC_IPU_PRP_VF_SDC_MODULE) - if (cam->output == 0) { + if (cam->output == 0 || cam->output == 2) { if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) err = prp_vf_sdc_deselect(cam); else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY) diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index f2d2bffedfdd..5f24954b8e64 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -112,6 +112,12 @@ static inline int _ipu_is_ic_graphic_chan(uint32_t dma_chan) return (dma_chan == 14 || dma_chan == 15); } +/* Either DP BG or DP FG can be graphic window */ +static inline int _ipu_is_dp_graphic_chan(uint32_t dma_chan) +{ + return (dma_chan == 23 || dma_chan == 27); +} + static inline int _ipu_is_irt_chan(uint32_t dma_chan) { return ((dma_chan >= 45) && (dma_chan <= 50)); @@ -540,6 +546,9 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) goto err; } + if (params->mem_dp_bg_sync.alpha_chan_en) + g_thrd_chan_en[IPU_CHAN_ID(channel)] = true; + g_dc_di_assignment[5] = params->mem_dp_bg_sync.di; _ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt, params->mem_dp_bg_sync.out_pixel_fmt); @@ -553,6 +562,10 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) case MEM_FG_SYNC: _ipu_dp_init(channel, params->mem_dp_fg_sync.in_pixel_fmt, params->mem_dp_fg_sync.out_pixel_fmt); + + if (params->mem_dp_fg_sync.alpha_chan_en) + g_thrd_chan_en[IPU_CHAN_ID(channel)] = true; + ipu_dc_use_count++; ipu_dp_use_count++; ipu_dmfc_use_count++; @@ -907,7 +920,8 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, phyaddr_0, phyaddr_1); /* Set correlative channel parameter of local alpha channel */ - if (_ipu_is_ic_graphic_chan(dma_chan) && + if ((_ipu_is_ic_graphic_chan(dma_chan) || + _ipu_is_dp_graphic_chan(dma_chan)) && (g_thrd_chan_en[IPU_CHAN_ID(channel)] == true)) { _ipu_ch_param_set_alpha_use_separate_channel(dma_chan, true); _ipu_ch_param_set_alpha_buffer_memory(dma_chan); @@ -1503,6 +1517,13 @@ int32_t ipu_enable_channel(ipu_channel_t channel) sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER); reg = __raw_readl(IDMAC_SEP_ALPHA); __raw_writel(reg | idma_mask(sec_dma), IDMAC_SEP_ALPHA); + } else if ((g_thrd_chan_en[IPU_CHAN_ID(channel)]) && + ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))) { + thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER); + reg = __raw_readl(IDMAC_CHA_EN(thrd_dma)); + __raw_writel(reg | idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma)); + reg = __raw_readl(IDMAC_SEP_ALPHA); + __raw_writel(reg | idma_mask(in_dma), IDMAC_SEP_ALPHA); } if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) || @@ -1613,8 +1634,13 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) if (g_thrd_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(thrd_dma)) { reg = __raw_readl(IDMAC_CHA_EN(thrd_dma)); __raw_writel(reg & ~idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma)); - reg = __raw_readl(IDMAC_SEP_ALPHA); - __raw_writel(reg & ~idma_mask(sec_dma), IDMAC_SEP_ALPHA); + if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) { + reg = __raw_readl(IDMAC_SEP_ALPHA); + __raw_writel(reg & ~idma_mask(in_dma), IDMAC_SEP_ALPHA); + } else { + reg = __raw_readl(IDMAC_SEP_ALPHA); + __raw_writel(reg & ~idma_mask(sec_dma), IDMAC_SEP_ALPHA); + } __raw_writel(idma_mask(thrd_dma), IPU_CHA_CUR_BUF(thrd_dma)); } diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c index e666d6f28f95..bfeed3a1efb3 100644 --- a/drivers/mxc/ipu3/ipu_disp.c +++ b/drivers/mxc/ipu3/ipu_disp.c @@ -1261,7 +1261,10 @@ EXPORT_SYMBOL(ipu_init_async_panel); /*! * This function sets the foreground and background plane global alpha blending - * modes. + * modes. This function also sets the DP graphic plane according to the + * parameter of IPUv3 DP channel. + * + * @param channel IPUv3 DP channel * * @param enable Boolean to enable or disable global alpha * blending. If disabled, local blending is used. @@ -1276,20 +1279,35 @@ int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, bool enable, uint32_t reg; uint32_t flow; unsigned long lock_flags; + bool bg_chan; - if (channel == MEM_BG_SYNC) + if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) flow = DP_SYNC; - else if (channel == MEM_BG_ASYNC0) + else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) flow = DP_ASYNC0; - else if (channel == MEM_BG_ASYNC1) + else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1) flow = DP_ASYNC1; else return -EINVAL; + if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 || + channel == MEM_BG_ASYNC1) + bg_chan = true; + else + bg_chan = false; + if (!g_ipu_clk_enabled) clk_enable(g_ipu_clk); spin_lock_irqsave(&ipu_lock, lock_flags); + if (bg_chan) { + reg = __raw_readl(DP_COM_CONF(flow)); + __raw_writel(reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF(flow)); + } else { + reg = __raw_readl(DP_COM_CONF(flow)); + __raw_writel(reg | DP_COM_CONF_GWSEL, DP_COM_CONF(flow)); + } + if (enable) { reg = __raw_readl(DP_GRAPH_WIND_CTRL(flow)) & 0x00FFFFFFL; __raw_writel(reg | ((uint32_t) alpha << 24), @@ -1332,11 +1350,11 @@ int32_t ipu_disp_set_color_key(ipu_channel_t channel, bool enable, int red, green, blue; unsigned long lock_flags; - if (channel == MEM_BG_SYNC) + if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) flow = DP_SYNC; - else if (channel == MEM_BG_ASYNC0) + else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) flow = DP_ASYNC0; - else if (channel == MEM_BG_ASYNC1) + else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1) flow = DP_ASYNC1; else return -EINVAL; diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h index 541b795df859..067ace19563c 100644 --- a/drivers/mxc/ipu3/ipu_param_mem.h +++ b/drivers/mxc/ipu3/ipu_param_mem.h @@ -172,23 +172,16 @@ static inline void _ipu_ch_param_init(int ch, case IPU_PIX_FMT_RGB565: ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ - ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ - + ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ - _ipu_ch_params_set_packing(¶ms, 5, 0, 6, 5, 5, 11, 1, 16); - /* Set WID3 to be 8-bit for seperate alpha channel */ - if (ch == 14 || ch == 15) - ipu_ch_param_set_field(¶ms, 1, 125, 3, 7); + _ipu_ch_params_set_packing(¶ms, 5, 0, 6, 5, 5, 11, 8, 16); break; case IPU_PIX_FMT_BGR24: ipu_ch_param_set_field(¶ms, 0, 107, 3, 1); /* bits/pixel */ ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */ - _ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 1, 24); - /* Set WID3 to be 8-bit for seperate alpha channel */ - if (ch == 14 || ch == 15) - ipu_ch_param_set_field(¶ms, 1, 125, 3, 7); + _ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24); break; case IPU_PIX_FMT_RGB24: case IPU_PIX_FMT_YUV444: @@ -196,10 +189,7 @@ static inline void _ipu_ch_param_init(int ch, ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */ - _ipu_ch_params_set_packing(¶ms, 8, 16, 8, 8, 8, 0, 1, 24); - /* Set WID3 to be 8-bit for seperate alpha channel */ - if (ch == 14 || ch == 15) - ipu_ch_param_set_field(¶ms, 1, 125, 3, 7); + _ipu_ch_params_set_packing(¶ms, 8, 16, 8, 8, 8, 0, 8, 24); break; case IPU_PIX_FMT_BGRA32: case IPU_PIX_FMT_BGR32: @@ -363,6 +353,12 @@ static inline void _ipu_ch_param_set_alpha_buffer_memory(uint32_t ch) case 15: /* PP graphic */ alp_mem_idx = 1; break; + case 23: /* DP BG SYNC graphic */ + alp_mem_idx = 4; + break; + case 27: /* DP FG SYNC graphic */ + alp_mem_idx = 2; + break; default: dev_err(g_ipu_dev, "unsupported correlative channel of local " "alpha channel\n"); diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c index 4722dbe4c057..b39ade689b71 100644 --- a/drivers/video/mxc/mxc_ipuv3_fb.c +++ b/drivers/video/mxc/mxc_ipuv3_fb.c @@ -61,6 +61,10 @@ struct mxcfb_info { int ipu_di; u32 ipu_di_pix_fmt; bool overlay; + bool alpha_chan_en; + dma_addr_t alpha_phy_addr; + void *alpha_virt_addr; + uint32_t alpha_mem_len; uint32_t ipu_ch_irq; uint32_t cur_ipu_buf; @@ -174,6 +178,8 @@ static int _setup_disp_channel1(struct fb_info *fbi) params.mem_dp_bg_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666; } params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi); + if (mxc_fbi->alpha_chan_en) + params.mem_dp_bg_sync.alpha_chan_en = true; ipu_init_channel(mxc_fbi->ipu_ch, ¶ms); @@ -203,6 +209,23 @@ static int _setup_disp_channel2(struct fb_info *fbi) "ipu_init_channel_buffer error %d\n", retval); } + if (mxc_fbi->alpha_chan_en) { + retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, + IPU_ALPHA_IN_BUFFER, + IPU_PIX_FMT_GENERIC, + fbi->var.xres, fbi->var.yres, + fbi->var.xres, + IPU_ROTATE_NONE, + mxc_fbi->alpha_phy_addr, + mxc_fbi->alpha_phy_addr, + 0, 0); + if (retval) { + dev_err(fbi->device, + "ipu_init_channel_buffer error %d\n", retval); + return retval; + } + } + return retval; } @@ -214,7 +237,7 @@ static int _setup_disp_channel2(struct fb_info *fbi) static int mxcfb_set_par(struct fb_info *fbi) { int retval = 0; - u32 mem_len; + u32 mem_len, alpha_mem_len; ipu_di_signal_cfg_t sig_cfg; struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; @@ -234,6 +257,28 @@ static int mxcfb_set_par(struct fb_info *fbi) if (mxcfb_map_video_memory(fbi) < 0) return -ENOMEM; } + if (mxc_fbi->alpha_chan_en) { + alpha_mem_len = fbi->var.xres * fbi->var.yres; + if (!mxc_fbi->alpha_phy_addr || + (alpha_mem_len > mxc_fbi->alpha_mem_len)) { + if (mxc_fbi->alpha_phy_addr) + dma_free_coherent(fbi->device, + mxc_fbi->alpha_mem_len, + mxc_fbi->alpha_virt_addr, + mxc_fbi->alpha_phy_addr); + mxc_fbi->alpha_virt_addr = + dma_alloc_coherent(fbi->device, + alpha_mem_len, + &mxc_fbi->alpha_phy_addr, + GFP_DMA | GFP_KERNEL); + if (mxc_fbi->alpha_virt_addr == NULL) { + dev_err(fbi->device, "mxcfb: dma alloc for" + " alpha buffer failed.\n"); + return -ENOMEM; + } + mxc_fbi->alpha_mem_len = alpha_mem_len; + } + } if (mxc_fbi->blank != FB_BLANK_UNBLANK) return retval; @@ -606,16 +651,60 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) case MXCFB_SET_GBL_ALPHA: { struct mxcfb_gbl_alpha ga; + if (copy_from_user(&ga, (void *)arg, sizeof(ga))) { retval = -EFAULT; break; } - retval = - ipu_disp_set_global_alpha(MEM_BG_SYNC, - (bool) ga.enable, - ga.alpha); - dev_dbg(fbi->device, "Set global alpha to %d\n", - ga.alpha); + + if (ipu_disp_set_global_alpha(mxc_fbi->ipu_ch, + (bool)ga.enable, + ga.alpha)) { + retval = -EINVAL; + break; + } + + if (ga.enable) + mxc_fbi->alpha_chan_en = false; + + if (ga.enable) + dev_dbg(fbi->device, + "Set global alpha of %s to %d\n", + fbi->fix.id, ga.alpha); + break; + } + case MXCFB_SET_LOC_ALPHA: + { + struct mxcfb_loc_alpha la; + + if (copy_from_user(&la, (void *)arg, sizeof(la))) { + retval = -EFAULT; + break; + } + + if (ipu_disp_set_global_alpha(mxc_fbi->ipu_ch, + !(bool)la.enable, 0)) { + retval = -EINVAL; + break; + } + + if (la.enable) + mxc_fbi->alpha_chan_en = true; + else + mxc_fbi->alpha_chan_en = false; + + mxcfb_set_par(fbi); + + la.alpha_phy_addr = mxc_fbi->alpha_phy_addr; + if (copy_to_user((void *)arg, &la, sizeof(la))) { + retval = -EFAULT; + break; + } + + if (la.enable) + dev_dbg(fbi->device, + "Enable DP local alpha for %s\n", + fbi->fix.id); break; } case MXCFB_SET_CLR_KEY: @@ -625,7 +714,8 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - retval = ipu_disp_set_color_key(MEM_BG_SYNC, key.enable, + retval = ipu_disp_set_color_key(mxc_fbi->ipu_ch, + key.enable, key.color_key); dev_dbg(fbi->device, "Set color key to 0x%08X\n", key.color_key); @@ -846,11 +936,14 @@ static int mxcfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) u32 len; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; struct mxcfb_alloc_list *mem; + struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; if (offset < fbi->fix.smem_len) { /* mapping framebuffer memory */ len = fbi->fix.smem_len - offset; vma->vm_pgoff = (fbi->fix.smem_start + offset) >> PAGE_SHIFT; + } else if (vma->vm_pgoff == (mxc_fbi->alpha_phy_addr >> PAGE_SHIFT)) { + len = mxc_fbi->alpha_mem_len; } else { list_for_each_entry(mem, &fb_alloc_list, list) { if (offset == mem->phy_addr) { diff --git a/include/linux/ipu.h b/include/linux/ipu.h index 2f9fa4380593..f9216bbe2178 100644 --- a/include/linux/ipu.h +++ b/include/linux/ipu.h @@ -426,6 +426,7 @@ typedef union { bool interlaced; uint32_t in_pixel_fmt; uint32_t out_pixel_fmt; + bool alpha_chan_en; } mem_dp_bg_sync; struct { uint32_t temp; @@ -435,6 +436,7 @@ typedef union { bool interlaced; uint32_t in_pixel_fmt; uint32_t out_pixel_fmt; + bool alpha_chan_en; } mem_dp_fg_sync; struct { uint32_t di; diff --git a/include/linux/mxcfb.h b/include/linux/mxcfb.h index c91ef8699f18..cd21213468a3 100644 --- a/include/linux/mxcfb.h +++ b/include/linux/mxcfb.h @@ -35,6 +35,11 @@ struct mxcfb_gbl_alpha { int alpha; }; +struct mxcfb_loc_alpha { + int enable; + unsigned long alpha_phy_addr; +}; + struct mxcfb_color_key { int enable; __u32 color_key; @@ -49,7 +54,8 @@ struct mxcfb_pos { #define MXCFB_SET_GBL_ALPHA _IOW('F', 0x21, struct mxcfb_gbl_alpha) #define MXCFB_SET_CLR_KEY _IOW('F', 0x22, struct mxcfb_color_key) #define MXCFB_SET_OVERLAY_POS _IOW('F', 0x24, struct mxcfb_pos) -#define MXCFB_GET_FB_IPU_CHAN _IOR('F', 0x25, u_int32_t) +#define MXCFB_GET_FB_IPU_CHAN _IOR('F', 0x25, u_int32_t) +#define MXCFB_SET_LOC_ALPHA _IOWR('F', 0x26, struct mxcfb_loc_alpha) #ifdef __KERNEL__ |