summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJason Chen <b02280@freescale.com>2009-08-27 14:21:50 +0800
committerJason Chen <b02280@freescale.com>2009-08-27 14:21:50 +0800
commit164225171de3bade78ac74554e5b4102a02565ec (patch)
tree4be4ed321604b28bfa86a267c3c70be9e3024446 /drivers
parentc209b2927d1774e10ab04e1171459ced30d8b68c (diff)
ENGR00115764 IPUv3 FB:Support DP local alpha channel in double buffer mode
Add the double buffer mode support for DP local alpha feature with separate alpha channel. Signed-off-by: Liu Ying <b17645@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/mxc/capture/ipu_prp_vf_sdc.c40
-rw-r--r--drivers/media/video/mxc/output/mxc_v4l2_output.c2
-rw-r--r--drivers/video/mxc/mxc_ipuv3_fb.c162
3 files changed, 160 insertions, 44 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 f4ec31e975cb..369facdf29c2 100644
--- a/drivers/media/video/mxc/capture/ipu_prp_vf_sdc.c
+++ b/drivers/media/video/mxc/capture/ipu_prp_vf_sdc.c
@@ -67,6 +67,18 @@ static int prpvf_start(void *private)
return -EPERM;
}
+ fbvar = fbi->var;
+ fbvar.bits_per_pixel = 16;
+ fbvar.nonstd = 0;
+ fbvar.xres = fbvar.xres_virtual = cam->win.w.width;
+ fbvar.yres = cam->win.w.height;
+ fbvar.yres_virtual = cam->win.w.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);
+
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);
@@ -124,20 +136,6 @@ 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,
@@ -212,20 +210,6 @@ static int prpvf_start(void *private)
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,
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.c b/drivers/media/video/mxc/output/mxc_v4l2_output.c
index b2c57e951896..328fd10e04bd 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.c
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.c
@@ -2091,7 +2091,7 @@ mxc_v4l2out_do_ioctl(struct inode *inode, struct file *file,
set_fs(old_fs);
}
if (ipu_ch == CHAN_NONE) {
- dev_err(vdev->dev,
+ dev_err(&vdev->dev,
"Can't get disp ipu channel\n");
retval = -EINVAL;
break;
diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c
index b39ade689b71..6c6e33580874 100644
--- a/drivers/video/mxc/mxc_ipuv3_fb.c
+++ b/drivers/video/mxc/mxc_ipuv3_fb.c
@@ -62,15 +62,19 @@ struct mxcfb_info {
u32 ipu_di_pix_fmt;
bool overlay;
bool alpha_chan_en;
- dma_addr_t alpha_phy_addr;
- void *alpha_virt_addr;
+ dma_addr_t alpha_phy_addr0;
+ dma_addr_t alpha_phy_addr1;
+ void *alpha_virt_addr0;
+ void *alpha_virt_addr1;
uint32_t alpha_mem_len;
uint32_t ipu_ch_irq;
uint32_t cur_ipu_buf;
+ uint32_t cur_ipu_alpha_buf;
u32 pseudo_palette[16];
struct semaphore flip_sem;
+ struct semaphore alpha_flip_sem;
struct completion vsync_complete;
};
@@ -193,6 +197,10 @@ static int _setup_disp_channel2(struct fb_info *fbi)
mxc_fbi->cur_ipu_buf = 1;
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 = fbi->var.yoffset = 0;
retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
@@ -216,8 +224,8 @@ static int _setup_disp_channel2(struct fb_info *fbi)
fbi->var.xres, fbi->var.yres,
fbi->var.xres,
IPU_ROTATE_NONE,
- mxc_fbi->alpha_phy_addr,
- mxc_fbi->alpha_phy_addr,
+ mxc_fbi->alpha_phy_addr0,
+ mxc_fbi->alpha_phy_addr1,
0, 0);
if (retval) {
dev_err(fbi->device,
@@ -259,21 +267,44 @@ static int mxcfb_set_par(struct fb_info *fbi)
}
if (mxc_fbi->alpha_chan_en) {
alpha_mem_len = fbi->var.xres * fbi->var.yres;
- if (!mxc_fbi->alpha_phy_addr ||
+ if ((!mxc_fbi->alpha_phy_addr0 && !mxc_fbi->alpha_phy_addr1) ||
(alpha_mem_len > mxc_fbi->alpha_mem_len)) {
- if (mxc_fbi->alpha_phy_addr)
+ if (mxc_fbi->alpha_phy_addr0)
+ dma_free_coherent(fbi->device,
+ mxc_fbi->alpha_mem_len,
+ mxc_fbi->alpha_virt_addr0,
+ mxc_fbi->alpha_phy_addr0);
+ if (mxc_fbi->alpha_phy_addr1)
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 =
+ mxc_fbi->alpha_virt_addr1,
+ mxc_fbi->alpha_phy_addr1);
+
+ mxc_fbi->alpha_virt_addr0 =
dma_alloc_coherent(fbi->device,
alpha_mem_len,
- &mxc_fbi->alpha_phy_addr,
+ &mxc_fbi->alpha_phy_addr0,
GFP_DMA | GFP_KERNEL);
- if (mxc_fbi->alpha_virt_addr == NULL) {
+
+ mxc_fbi->alpha_virt_addr1 =
+ dma_alloc_coherent(fbi->device,
+ alpha_mem_len,
+ &mxc_fbi->alpha_phy_addr1,
+ GFP_DMA | GFP_KERNEL);
+ if (mxc_fbi->alpha_virt_addr0 == NULL ||
+ mxc_fbi->alpha_virt_addr1 == NULL) {
dev_err(fbi->device, "mxcfb: dma alloc for"
" alpha buffer failed.\n");
+ if (mxc_fbi->alpha_virt_addr0)
+ dma_free_coherent(fbi->device,
+ mxc_fbi->alpha_mem_len,
+ mxc_fbi->alpha_virt_addr0,
+ mxc_fbi->alpha_phy_addr0);
+ if (mxc_fbi->alpha_virt_addr1)
+ dma_free_coherent(fbi->device,
+ mxc_fbi->alpha_mem_len,
+ mxc_fbi->alpha_virt_addr1,
+ mxc_fbi->alpha_phy_addr1);
return -ENOMEM;
}
mxc_fbi->alpha_mem_len = alpha_mem_len;
@@ -676,6 +707,8 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
case MXCFB_SET_LOC_ALPHA:
{
struct mxcfb_loc_alpha la;
+ int i;
+ char *video_plane_idstr;
if (copy_from_user(&la, (void *)arg, sizeof(la))) {
retval = -EFAULT;
@@ -688,14 +721,28 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
- if (la.enable)
+ if (la.enable) {
mxc_fbi->alpha_chan_en = true;
- else
+
+ if (mxc_fbi->ipu_ch == MEM_FG_SYNC)
+ video_plane_idstr = "DISP3 BG";
+ else if (mxc_fbi->ipu_ch == MEM_BG_SYNC)
+ video_plane_idstr = "DISP3 FG";
+
+ for (i = 0; i < num_registered_fb; i++) {
+ char *idstr = registered_fb[i]->fix.id;
+ if (strcmp(idstr, "video_plane_idstr") == 0) {
+ ((struct mxcfb_info *)(registered_fb[i]->par))->alpha_chan_en = false;
+ break;
+ }
+ }
+ } else
mxc_fbi->alpha_chan_en = false;
mxcfb_set_par(fbi);
- la.alpha_phy_addr = mxc_fbi->alpha_phy_addr;
+ la.alpha_phy_addr0 = mxc_fbi->alpha_phy_addr0;
+ la.alpha_phy_addr1 = mxc_fbi->alpha_phy_addr1;
if (copy_to_user((void *)arg, &la, sizeof(la))) {
retval = -EFAULT;
break;
@@ -707,6 +754,60 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
fbi->fix.id);
break;
}
+ case MXCFB_SET_LOC_ALP_BUF:
+ {
+ unsigned long base;
+ uint32_t ipu_alp_ch_irq;
+
+ if (!(((mxc_fbi->ipu_ch == MEM_FG_SYNC) ||
+ (mxc_fbi->ipu_ch == MEM_BG_SYNC)) &&
+ (mxc_fbi->alpha_chan_en))) {
+ dev_err(fbi->device,
+ "Should use background or overlay "
+ "framebuffer to set the alpha buffer "
+ "number\n");
+ return -EINVAL;
+ }
+
+ if (get_user(base, argp))
+ return -EFAULT;
+
+ if (base != mxc_fbi->alpha_phy_addr0 &&
+ base != mxc_fbi->alpha_phy_addr1) {
+ dev_err(fbi->device,
+ "Wrong alpha buffer physical address "
+ "%lu\n", base);
+ return -EINVAL;
+ }
+
+ if (mxc_fbi->ipu_ch == MEM_FG_SYNC)
+ ipu_alp_ch_irq = IPU_IRQ_FG_ALPHA_SYNC_EOF;
+ else
+ ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
+
+ down(&mxc_fbi->alpha_flip_sem);
+
+ mxc_fbi->cur_ipu_alpha_buf =
+ !mxc_fbi->cur_ipu_alpha_buf;
+ if (ipu_update_channel_buffer(mxc_fbi->ipu_ch,
+ IPU_ALPHA_IN_BUFFER,
+ mxc_fbi->
+ cur_ipu_alpha_buf,
+ base) == 0) {
+ ipu_select_buffer(mxc_fbi->ipu_ch,
+ IPU_ALPHA_IN_BUFFER,
+ mxc_fbi->cur_ipu_alpha_buf);
+ ipu_clear_irq(ipu_alp_ch_irq);
+ ipu_enable_irq(ipu_alp_ch_irq);
+ } else {
+ dev_err(fbi->device,
+ "Error updating %s SDC alpha buf %d "
+ "to address=0x%08lX\n",
+ fbi->fix.id,
+ mxc_fbi->cur_ipu_alpha_buf, base);
+ }
+ break;
+ }
case MXCFB_SET_CLR_KEY:
{
struct mxcfb_color_key key;
@@ -942,7 +1043,10 @@ static int mxcfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
/* 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)) {
+ } else if ((vma->vm_pgoff ==
+ (mxc_fbi->alpha_phy_addr0 >> PAGE_SHIFT)) ||
+ (vma->vm_pgoff ==
+ (mxc_fbi->alpha_phy_addr1 >> PAGE_SHIFT))) {
len = mxc_fbi->alpha_mem_len;
} else {
list_for_each_entry(mem, &fb_alloc_list, list) {
@@ -1004,6 +1108,16 @@ static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t mxcfb_alpha_irq_handler(int irq, void *dev_id)
+{
+ struct fb_info *fbi = dev_id;
+ struct mxcfb_info *mxc_fbi = fbi->par;
+
+ up(&mxc_fbi->alpha_flip_sem);
+ ipu_disable_irq(irq);
+ return IRQ_HANDLED;
+}
+
/*
* Suspends the framebuffer and blanks the screen. Power management support
*/
@@ -1238,6 +1352,15 @@ static int mxcfb_probe(struct platform_device *pdev)
ipu_disp_set_color_key(mxcfbi->ipu_ch, false, 0);
strcpy(fbi->fix.id, "DISP3 BG");
g_dp_in_use = true;
+
+ if (ipu_request_irq(IPU_IRQ_BG_ALPHA_SYNC_EOF,
+ mxcfb_alpha_irq_handler, 0,
+ MXCFB_NAME, fbi) != 0) {
+ dev_err(&pdev->dev, "Error registering BG alpha irq "
+ "handler.\n");
+ ret = -EBUSY;
+ goto err1;
+ }
} else if (pdev->id == 1) {
strcpy(fbi->fix.id, "DISP3 BG - DI1");
g_dp_in_use = true;
@@ -1249,6 +1372,15 @@ static int mxcfb_probe(struct platform_device *pdev)
mxcfbi->blank = FB_BLANK_POWERDOWN;
strcpy(fbi->fix.id, "DISP3 FG");
+
+ if (ipu_request_irq(IPU_IRQ_FG_ALPHA_SYNC_EOF,
+ mxcfb_alpha_irq_handler, 0,
+ MXCFB_NAME, fbi) != 0) {
+ dev_err(&pdev->dev, "Error registering FG alpha irq "
+ "handler.\n");
+ ret = -EBUSY;
+ goto err1;
+ }
}
mxcfb_info[pdev->id] = fbi;