diff options
author | Jason Chen <b02280@freescale.com> | 2009-08-27 14:21:50 +0800 |
---|---|---|
committer | Jason Chen <b02280@freescale.com> | 2009-08-27 14:21:50 +0800 |
commit | 164225171de3bade78ac74554e5b4102a02565ec (patch) | |
tree | 4be4ed321604b28bfa86a267c3c70be9e3024446 /drivers | |
parent | c209b2927d1774e10ab04e1171459ced30d8b68c (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.c | 40 | ||||
-rw-r--r-- | drivers/media/video/mxc/output/mxc_v4l2_output.c | 2 | ||||
-rw-r--r-- | drivers/video/mxc/mxc_ipuv3_fb.c | 162 |
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; |