summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiu Ying <b17645@freescale.com>2009-07-13 15:41:36 +0800
committerJason Chen <b02280@freescale.com>2009-08-27 10:41:51 +0800
commit3f54b1f3e97dd9e302574fa24b74bf33182b5537 (patch)
treedab3fd211ec35063c35c91e1b786ebb8c54c8105
parent45bf725c596b43a7173f040df0227be733cce744 (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.c228
-rw-r--r--drivers/media/video/mxc/capture/mxc_v4l2_capture.c68
-rw-r--r--drivers/mxc/ipu3/ipu_common.c32
-rw-r--r--drivers/mxc/ipu3/ipu_disp.c32
-rw-r--r--drivers/mxc/ipu3/ipu_param_mem.h24
-rw-r--r--drivers/video/mxc/mxc_ipuv3_fb.c109
-rw-r--r--include/linux/ipu.h2
-rw-r--r--include/linux/mxcfb.h8
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(&params, 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, &params);
- 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(&params, 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, &params);
- 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(&params, 0, 107, 3, 3); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
- ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
-
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
- _ipu_ch_params_set_packing(&params, 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(&params, 1, 125, 3, 7);
+ _ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
break;
case IPU_PIX_FMT_BGR24:
ipu_ch_param_set_field(&params, 0, 107, 3, 1); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
- _ipu_ch_params_set_packing(&params, 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(&params, 1, 125, 3, 7);
+ _ipu_ch_params_set_packing(&params, 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(&params, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
- _ipu_ch_params_set_packing(&params, 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(&params, 1, 125, 3, 7);
+ _ipu_ch_params_set_packing(&params, 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, &params);
@@ -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__