From 0fb9dcfbc652ed617ceb244bd8a9201d00a124fe Mon Sep 17 00:00:00 2001 From: Kiran Kumar H N Date: Sun, 17 Jul 2011 12:31:53 -0700 Subject: [PATCH] msm-camera: configure preview and recording buffers seperately. decouple preview and recording path configuration by configuring the buffers during preview start and recording start respectively. Signed-off-by: Kiran Kumar H N Signed-off-by: Mingcheng Zhu --- arch/arm/mach-msm/include/mach/camera.h | 4 + drivers/media/video/msm/msm.c | 6 +- drivers/media/video/msm/msm.h | 4 +- drivers/media/video/msm/msm_isp.c | 59 +++- drivers/media/video/msm/msm_mctl_buf.c | 99 +++--- drivers/media/video/msm/msm_vfe32.c | 417 +++++++++++------------- drivers/media/video/msm/msm_vfe32.h | 4 + include/media/msm_camera.h | 3 + 8 files changed, 331 insertions(+), 265 deletions(-) diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h index b49300df746..c7ec849aeee 100644 --- a/arch/arm/mach-msm/include/mach/camera.h +++ b/arch/arm/mach-msm/include/mach/camera.h @@ -81,6 +81,10 @@ enum vfe_resp_msg { VFE_MSG_SYNC_TIMER1, VFE_MSG_SYNC_TIMER2, VFE_MSG_COMMON, + VFE_MSG_V32_START, + VFE_MSG_V32_START_RECORDING, + VFE_MSG_V32_CAPTURE, + VFE_MSG_OUTPUT_IRQ, }; enum vpe_resp_msg { diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c index 6ded98b2a26..28d8e8ac284 100644 --- a/drivers/media/video/msm/msm.c +++ b/drivers/media/video/msm/msm.c @@ -639,7 +639,7 @@ static int msm_camera_v4l2_qbuf(struct file *f, void *pctx, pcam_inst = container_of(f->private_data, struct msm_cam_v4l2_dev_inst, eventHandle); - D("%s\n", __func__); + D("%s Inst = %p\n", __func__, pcam_inst); WARN_ON(pctx != f->private_data); D("%s stored reserved info %d", __func__, pb->reserved); @@ -679,7 +679,7 @@ static int msm_camera_v4l2_streamon(struct file *f, void *pctx, pcam_inst = container_of(f->private_data, struct msm_cam_v4l2_dev_inst, eventHandle); - D("%s\n", __func__); + D("%s Inst %p\n", __func__, pcam_inst); WARN_ON(pctx != f->private_data); D("%s Calling videobuf_streamon", __func__); @@ -707,7 +707,7 @@ static int msm_camera_v4l2_streamoff(struct file *f, void *pctx, pcam_inst = container_of(f->private_data, struct msm_cam_v4l2_dev_inst, eventHandle); - D("%s\n", __func__); + pr_err("%s Inst %p\n", __func__, pcam_inst); WARN_ON(pctx != f->private_data); /* first turn of HW (VFE/sensor) streaming so that buffers are diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h index 7390f10374e..89434b33552 100644 --- a/drivers/media/video/msm/msm.h +++ b/drivers/media/video/msm/msm.h @@ -354,7 +354,9 @@ int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam); int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam); int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl, int msg_type, uint32_t y_phy); -int msm_mctl_fetch_free_buf(struct msm_cam_media_controller *pmctl, +int msm_mctl_reserve_free_buf(struct msm_cam_media_controller *pmctl, + int path, struct msm_free_buf *free_buf); +int msm_mctl_release_free_buf(struct msm_cam_media_controller *pmctl, int path, struct msm_free_buf *free_buf); /*Memory(PMEM) functions*/ int msm_register_pmem(struct hlist_head *ptype, void __user *arg); diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c index 480c6263fd3..c88e1061384 100644 --- a/drivers/media/video/msm/msm_isp.c +++ b/drivers/media/video/msm/msm_isp.c @@ -171,6 +171,11 @@ static int msm_isp_notify(struct v4l2_subdev *sd, void *arg) struct msm_sync *sync = (struct msm_sync *)v4l2_get_subdev_hostdata(sd); struct msm_vfe_resp *vdata = (struct msm_vfe_resp *)arg; + struct msm_free_buf free_buf; + struct msm_camvfe_params vfe_params; + struct msm_vfe_cfg_cmd cfgcmd; + struct msm_cam_v4l2_device *pcam = sync->pcam_sync; + int vfe_id = vdata->evt_msg.msg_id; if (!sync) { pr_err("%s: no context in dsp callback.\n", __func__); @@ -212,13 +217,61 @@ static int msm_isp_notify(struct v4l2_subdev *sd, void *arg) D("%s: qtype %d, general msg, enqueue event_q.\n", __func__, vdata->type); break; + case VFE_MSG_V32_START: + case VFE_MSG_V32_START_RECORDING: + D("%s Got V32_START_*: Getting ping addr id = %d", + __func__, vfe_id); + msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf); + cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR; + cfgcmd.value = &vfe_id; + vfe_params.vfe_cfg = &cfgcmd; + vfe_params.data = (void *)&free_buf; + rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params); + msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf); + cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR; + cfgcmd.value = &vfe_id; + vfe_params.vfe_cfg = &cfgcmd; + vfe_params.data = (void *)&free_buf; + rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params); + break; + case VFE_MSG_V32_CAPTURE: + D("%s Got V32_CAPTURE: getting buffer for id = %d", + __func__, vfe_id); + msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf); + cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR; + cfgcmd.value = &vfe_id; + vfe_params.vfe_cfg = &cfgcmd; + vfe_params.data = (void *)&free_buf; + rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params); + /* Write the same buffer into PONG */ + cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR; + cfgcmd.value = &vfe_id; + vfe_params.vfe_cfg = &cfgcmd; + vfe_params.data = (void *)&free_buf; + rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params); + break; + case VFE_MSG_OUTPUT_IRQ: + D("%s Got OUTPUT_IRQ: Getting free buf id = %d", + __func__, vfe_id); + msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf); + cfgcmd.cmd_type = CMD_CONFIG_FREE_BUF_ADDR; + cfgcmd.value = &vfe_id; + vfe_params.vfe_cfg = &cfgcmd; + vfe_params.data = (void *)&free_buf; + rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params); + break; default: D("%s: qtype %d not handled\n", __func__, vdata->type); /* fall through, send to config. */ } - - D("%s: msm_enqueue event_q\n", __func__); - rc = msm_isp_enqueue(&sync->pcam_sync->mctl, vdata, MSM_CAM_Q_VFE_MSG); + if (vdata->type != VFE_MSG_V32_START && + vdata->type != VFE_MSG_V32_START_RECORDING && + vdata->type != VFE_MSG_V32_CAPTURE && + vdata->type != VFE_MSG_OUTPUT_IRQ) { + D("%s: msm_enqueue event_q\n", __func__); + rc = msm_isp_enqueue(&sync->pcam_sync->mctl, + vdata, MSM_CAM_Q_VFE_MSG); + } msm_isp_sync_free(vdata); diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c index d084f9c606d..12f8a2c5a52 100644 --- a/drivers/media/video/msm/msm_mctl_buf.c +++ b/drivers/media/video/msm/msm_mctl_buf.c @@ -211,6 +211,9 @@ static void msm_vb2_ops_buf_cleanup(struct vb2_buffer *vb) pcam_inst = vb2_get_drv_priv(vb->vb2_queue); pcam = pcam_inst->pcam; buf = container_of(vb, struct msm_frame_buffer, vidbuf); + mem = vb2_plane_cookie(vb, 0); + if (!mem) + return; D("%s: inst=0x%x, buf=0x%x, idx=%d\n", __func__, (uint32_t)pcam_inst, (uint32_t)buf, vb->v4l2_buf.index); vb_phyaddr = (unsigned long) videobuf2_to_pmem_contig(vb, 0); @@ -238,6 +241,12 @@ static int msm_vb2_ops_start_streaming(struct vb2_queue *q) static int msm_vb2_ops_stop_streaming(struct vb2_queue *q) { + int rc = 0; + struct msm_free_buf *free_buf = NULL; + struct msm_cam_v4l2_dev_inst *pcam_inst = vb2_get_drv_priv(q); + if (rc != 0) + msm_mctl_release_free_buf(&pcam_inst->pcam->mctl, + pcam_inst->path, free_buf); return 0; } @@ -247,10 +256,7 @@ static void msm_vb2_ops_buf_queue(struct vb2_buffer *vb) struct msm_cam_v4l2_device *pcam = NULL; unsigned long phyaddr = 0; unsigned long flags = 0; - int rc; struct vb2_queue *vq = vb->vb2_queue; - struct msm_frame frame; - struct msm_vfe_cfg_cmd cfgcmd; struct videobuf2_contig_pmem *mem; struct msm_frame_buffer *buf; D("%s\n", __func__); @@ -268,20 +274,10 @@ static void msm_vb2_ops_buf_queue(struct vb2_buffer *vb) /* get the physcial address of the buffer */ phyaddr = (unsigned long) videobuf2_to_pmem_contig(vb, 0); D("%s buffer type is %d\n", __func__, mem->buffer_type); - frame.path = pcam_inst->path; - frame.buffer = 0; - frame.y_off = mem->y_off; - frame.cbcr_off = mem->cbcr_off; - /* now release frame to vfe */ - cfgcmd.cmd_type = CMD_FRAME_BUF_RELEASE; - cfgcmd.value = (void *)&frame; spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + D("Inst %p, >>>ADD>>> Buf 0x%x index %d into free Q", + pcam_inst, (int)phyaddr, vb->v4l2_buf.index); list_add_tail(&buf->list, &pcam_inst->free_vq); - /* TBD: need to remove. VFE is going to call - msm_mctl_fetch_free_buf to get free buf. - Work with Shuzhen to hash out details tomorrow */ - rc = msm_isp_subdev_ioctl(&pcam->mctl.isp_sdev->sd, - &cfgcmd, &phyaddr); spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); } @@ -375,23 +371,6 @@ static int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam, return 0; } -static int msm_mctl_get_pcam_inst_idx(int out_put_type) -{ - switch (out_put_type) { - case OUTPUT_TYPE_T: - return MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL; - case OUTPUT_TYPE_S: - return MSM_V4L2_EXT_CAPTURE_MODE_MAIN; - case OUTPUT_TYPE_V: - return MSM_V4L2_EXT_CAPTURE_MODE_VIDEO; - case OUTPUT_TYPE_P: - return MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW; - default: - return 0; - } -} - - int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl, int msg_type, uint32_t y_phy) { @@ -422,6 +401,9 @@ int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl, __func__, (uint32_t)y_phy, (uint32_t)buf_phyaddr); return -EINVAL; } + D("%s Inst %p, <<vidbuf.v4l2_buf.index); list_del(&buf->list); buf->vidbuf.v4l2_buf.sequence++; spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); @@ -436,27 +418,29 @@ int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam) return 0; } -int msm_mctl_fetch_free_buf(struct msm_cam_media_controller *pmctl, - int path, struct msm_free_buf *free_buf) +int msm_mctl_reserve_free_buf(struct msm_cam_media_controller *pmctl, + int msg_type, struct msm_free_buf *free_buf) { struct msm_cam_v4l2_dev_inst *pcam_inst; struct videobuf2_contig_pmem *mem; - int idx = msm_mctl_get_pcam_inst_idx(path); unsigned long flags = 0; struct msm_frame_buffer *buf = NULL; - int rc = -1; + int rc = -EINVAL, idx; + idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, msg_type); pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx]; spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); list_for_each_entry(buf, &pcam_inst->free_vq, list) { if (buf->inuse == 0) { mem = vb2_plane_cookie(&buf->vidbuf, 0); + if (!mem) + continue; free_buf->paddr = (uint32_t) videobuf2_to_pmem_contig(&buf->vidbuf, 0); free_buf->y_off = mem->y_off; free_buf->cbcr_off = mem->cbcr_off; - D("%s path=%d,inst=0x%p,idx=%d,paddr=0x%x, " - "y_off=%d,cbcroff=%d\n", __func__, path, + D("%s idx=%d,inst=0x%p,idx=%d,paddr=0x%x, " + "y_off=%d,cbcroff=%d\n", __func__, idx, pcam_inst, buf->vidbuf.v4l2_buf.index, free_buf->paddr, free_buf->y_off, free_buf->cbcr_off); @@ -466,6 +450,45 @@ int msm_mctl_fetch_free_buf(struct msm_cam_media_controller *pmctl, break; } } + if (rc != 0) { + free_buf->paddr = 0; + pr_err("No free buffer available "); + } spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); return rc; } + +int msm_mctl_release_free_buf(struct msm_cam_media_controller *pmctl, + int msg_type, struct msm_free_buf *free_buf) +{ + struct msm_cam_v4l2_dev_inst *pcam_inst; + unsigned long flags = 0; + struct msm_frame_buffer *buf = NULL; + uint32_t buf_phyaddr = 0; + int rc = -EINVAL, idx; + + if (!free_buf) + return rc; + + idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, msg_type); + pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx]; + spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); + list_for_each_entry(buf, &pcam_inst->free_vq, list) { + buf_phyaddr = + (uint32_t) videobuf2_to_pmem_contig(&buf->vidbuf, 0); + if (free_buf->paddr == buf_phyaddr) { + D("%s buf = 0x%x ", __func__, free_buf->paddr); + /* mark it free */ + buf->inuse = 0; + rc = 0; + break; + } + } + + if (rc != 0) + pr_err("%s invalid buffer address ", __func__); + + spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); + return rc; +} + diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c index 946f823395a..8df366f5690 100644 --- a/drivers/media/video/msm/msm_vfe32.c +++ b/drivers/media/video/msm/msm_vfe32.c @@ -34,6 +34,24 @@ atomic_t irq_cnt; } \ } +#define VFE32_AXI_OFFSET 0x0050 +#define vfe32_get_ch_ping_addr(chn) \ + (msm_io_r(vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn))) +#define vfe32_get_ch_pong_addr(chn) \ + (msm_io_r(vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4)) +#define vfe32_get_ch_addr(ping_pong, chn) \ + (((ping_pong) & (1 << (chn))) == 0 ? \ + vfe32_get_ch_pong_addr(chn) : vfe32_get_ch_ping_addr(chn)) + +#define vfe32_put_ch_ping_addr(chn, addr) \ + (msm_io_w((addr), vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn))) +#define vfe32_put_ch_pong_addr(chn, addr) \ + (msm_io_w((addr), vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4)) +#define vfe32_put_ch_addr(ping_pong, chn, addr) \ + (((ping_pong) & (1 << (chn))) == 0 ? \ + vfe32_put_ch_pong_addr((chn), (addr)) : \ + vfe32_put_ch_ping_addr((chn), (addr))) + static struct vfe32_ctrl_type *vfe32_ctrl; static struct msm_camera_io_clk camio_clk; static void *vfe_syncdata; @@ -576,82 +594,28 @@ static void vfe32_stop(void) vfe32_ctrl->vfebase + VFE_GLOBAL_RESET); } -static int vfe32_enqueue_free_buf(struct vfe32_output_ch *outch, - uint32_t paddr, uint32_t y_off, uint32_t cbcr_off) +static void vfe32_subdev_notify(int id, int path) { - struct vfe32_free_buf *free_buf = NULL; + struct msm_vfe_resp *rp; unsigned long flags = 0; - free_buf = kmalloc(sizeof(struct vfe32_free_buf), GFP_KERNEL); - if (!free_buf) - return -ENOMEM; - - spin_lock_irqsave(&outch->free_buf_lock, flags); - free_buf->paddr = paddr; - free_buf->y_off = y_off; - free_buf->cbcr_off = cbcr_off; - list_add_tail(&free_buf->node, &outch->free_buf_queue); - CDBG("%s: free_buf paddr = 0x%x, y_off = %d, cbcr_off = %d\n", - __func__, free_buf->paddr, free_buf->y_off, - free_buf->cbcr_off); - spin_unlock_irqrestore(&outch->free_buf_lock, flags); - return 0; -} - -static struct vfe32_free_buf *vfe32_dequeue_free_buf( - struct vfe32_output_ch *outch) -{ - unsigned long flags = 0; - struct vfe32_free_buf *free_buf = NULL; - spin_lock_irqsave(&outch->free_buf_lock, flags); - if (!list_empty(&outch->free_buf_queue)) { - free_buf = list_first_entry(&outch->free_buf_queue, - struct vfe32_free_buf, node); - if (free_buf) - list_del_init(&free_buf->node); + spin_lock_irqsave(&vfe32_ctrl->sd_notify_lock, flags); + rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp), + vfe32_ctrl->syncdata, GFP_ATOMIC); + if (!rp) { + CDBG("rp: cannot allocate buffer\n"); + return; } - spin_unlock_irqrestore(&outch->free_buf_lock, flags); - return free_buf; -} - -static void vfe32_reset_free_buf_queue( - struct vfe32_output_ch *outch) -{ - unsigned long flags = 0; - struct vfe32_free_buf *free_buf = NULL; - spin_lock_irqsave(&outch->free_buf_lock, flags); - while (!list_empty(&outch->free_buf_queue)) { - free_buf = list_first_entry(&outch->free_buf_queue, - struct vfe32_free_buf, node); - if (free_buf) { - list_del_init(&free_buf->node); - kfree(free_buf); - } - } - spin_unlock_irqrestore(&outch->free_buf_lock, flags); -} - -static void vfe32_init_free_buf_queues(void) -{ - INIT_LIST_HEAD(&vfe32_ctrl->outpath.out0.free_buf_queue); - INIT_LIST_HEAD(&vfe32_ctrl->outpath.out1.free_buf_queue); - INIT_LIST_HEAD(&vfe32_ctrl->outpath.out2.free_buf_queue); - spin_lock_init(&vfe32_ctrl->outpath.out0.free_buf_lock); - spin_lock_init(&vfe32_ctrl->outpath.out1.free_buf_lock); - spin_lock_init(&vfe32_ctrl->outpath.out2.free_buf_lock); -} - -static void vfe32_reset_free_buf_queues(void) -{ - vfe32_reset_free_buf_queue(&vfe32_ctrl->outpath.out0); - vfe32_reset_free_buf_queue(&vfe32_ctrl->outpath.out1); - vfe32_reset_free_buf_queue(&vfe32_ctrl->outpath.out2); + CDBG("vfe32_subdev_notify : msgId = %d\n", id); + rp->evt_msg.type = MSM_CAMERA_MSG; + rp->evt_msg.msg_id = path; + rp->type = id; + v4l2_subdev_notify(vfe32_ctrl->subdev, NOTIFY_VFE_MSG_EVT, rp); + spin_unlock_irqrestore(&vfe32_ctrl->sd_notify_lock, flags); } static int vfe32_config_axi(int mode, struct axidata *ad, uint32_t *ao) { - int ret; - int i; - uint32_t *p, *p1, *p2; + uint32_t *p, *p1; int32_t *ch_info; struct vfe32_output_ch *outp1, *outp2; struct msm_pmem_region *regp1 = NULL; @@ -676,7 +640,6 @@ static int vfe32_config_axi(int mode, struct axidata *ad, uint32_t *ao) CDBG("vfe32_config_axi: mode = %d, bufnum1 = %d, bufnum2 = %d\n", mode, ad->bufnum1, ad->bufnum2); - switch (mode) { case OUTPUT_2: { @@ -686,21 +649,6 @@ static int vfe32_config_axi(int mode, struct axidata *ad, uint32_t *ao) outp1 = &(vfe32_ctrl->outpath.out0); vfe32_ctrl->outpath.output_mode |= VFE32_OUTPUT_MODE_PT; - for (i = 0; i < 2; i++) { - p1 = ao + 6 + i; /* wm0 for y */ - *p1 = (regp1->paddr + regp1->info.y_off); - - p1 = ao + 12 + i; /* wm1 for cbcr */ - *p1 = (regp1->paddr + regp1->info.cbcr_off); - regp1++; - } - for (i = 2; i < ad->bufnum2; i++) { - ret = vfe32_enqueue_free_buf(outp1, regp1->paddr, - regp1->info.y_off, regp1->info.cbcr_off); - if (ret < 0) - return ret; - regp1++; - } } break; @@ -718,62 +666,6 @@ static int vfe32_config_axi(int mode, struct axidata *ad, uint32_t *ao) regp2 = &(ad->region[ad->bufnum1]); outp1 = &(vfe32_ctrl->outpath.out0); outp2 = &(vfe32_ctrl->outpath.out1); /* snapshot */ - - /* Parse the buffers!!! */ - if (ad->bufnum2 == 1) { /* assuming bufnum1 = bufnum2 */ - p1 = ao + 6; /* wm0 ping */ - *p1++ = (regp1->paddr + regp1->info.y_off); - /* this is to duplicate ping address to pong.*/ - *p1 = (regp1->paddr + regp1->info.y_off); - p1 = ao + 30; /* wm4 ping */ - *p1++ = (regp1->paddr + regp1->info.cbcr_off); - /* this is to duplicate ping address to pong.*/ - *p1 = (regp1->paddr + regp1->info.cbcr_off); - p1 = ao + 12; /* wm1 ping */ - *p1++ = (regp2->paddr + regp2->info.y_off); - /* pong = ping,*/ - *p1 = (regp2->paddr + regp2->info.y_off); - p1 = ao + 36; /* wm5 */ - *p1++ = (regp2->paddr + regp2->info.cbcr_off); - *p1 = (regp2->paddr + regp2->info.cbcr_off); - - } else { /* more than one snapshot */ - /* first fill ping & pong */ - for (i = 0; i < 2; i++) { - p1 = ao + 6 + i; /* wm0 for y */ - *p1 = (regp1->paddr + regp1->info.y_off); - p1 = ao + 30 + i; /* wm4 for cbcr */ - *p1 = (regp1->paddr + regp1->info.cbcr_off); - regp1++; - } - - for (i = 0; i < 2; i++) { - p2 = ao + 12 + i; /* wm1 for y */ - *p2 = (regp2->paddr + regp2->info.y_off); - p2 = ao + 36 + i; /* wm5 for cbcr */ - *p2 = (regp2->paddr + regp2->info.cbcr_off); - regp2++; - } - - for (i = 2; i < ad->bufnum1; i++) { - ret = vfe32_enqueue_free_buf(outp1, - regp1->paddr, - regp1->info.y_off, - regp1->info.cbcr_off); - if (ret < 0) - return ret; - regp1++; - } - for (i = 2; i < ad->bufnum2; i++) { - ret = vfe32_enqueue_free_buf(outp2, - regp2->paddr, - regp2->info.y_off, - regp2->info.cbcr_off); - if (ret < 0) - return ret; - regp2++; - } - } break; case OUTPUT_1_AND_3: @@ -791,40 +683,6 @@ static int vfe32_config_axi(int mode, struct axidata *ad, uint32_t *ao) outp1 = &(vfe32_ctrl->outpath.out0); /* preview */ outp2 = &(vfe32_ctrl->outpath.out2); /* video */ - - for (i = 0; i < 2; i++) { - p1 = ao + 6 + i; /* wm0 for y */ - *p1 = (regp1->paddr + regp1->info.y_off); - - p1 = ao + 30 + i; /* wm1 for cbcr */ - *p1 = (regp1->paddr + regp1->info.cbcr_off); - regp1++; - } - - for (i = 0; i < 2; i++) { - p2 = ao + 12 + i; /* wm0 for y */ - *p2 = (regp2->paddr + regp2->info.y_off); - - p2 = ao + 36 + i; /* wm1 for cbcr */ - *p2 = (regp2->paddr + regp2->info.cbcr_off); - regp2++; - } - for (i = 2; i < ad->bufnum1; i++) { - ret = vfe32_enqueue_free_buf(outp1, regp1->paddr, - regp1->info.y_off, - regp1->info.cbcr_off); - if (ret < 0) - return ret; - regp1++; - } - for (i = 2; i < ad->bufnum2; i++) { - ret = vfe32_enqueue_free_buf(outp2, regp2->paddr, - regp2->info.y_off, - regp2->info.cbcr_off); - if (ret < 0) - return ret; - regp2++; - } break; case CAMIF_TO_AXI_VIA_OUTPUT_2: { /* use wm0 only */ if (ad->bufnum2 < 1) @@ -898,7 +756,6 @@ static void vfe32_reset_internal_variables(void) static void vfe32_reset(void) { uint32_t vfe_version; - vfe32_reset_free_buf_queues(); vfe32_reset_internal_variables(); vfe_version = msm_io_r(vfe32_ctrl->vfebase); CDBG("vfe_version = 0x%x\n", vfe_version); @@ -1056,18 +913,6 @@ static void vfe32_start_common(void) #define ENQUEUED_BUFFERS 3 static int vfe32_start_recording(void) { - /* Clear out duplicate entries in free_buf qeueue, - * because the same number of the buffers were programmed - * during AXI config and then enqueued before recording. - * TODO: Do AXI config separately for recording at the - * time of enqueue */ - int i; - for (i = 0; i < ENQUEUED_BUFFERS; ++i) { - struct vfe32_free_buf *free_buf = NULL; - free_buf = vfe32_dequeue_free_buf(&vfe32_ctrl->outpath.out2); - kfree(free_buf); - } - vfe32_ctrl->req_start_video_rec = TRUE; /* Mask with 0x7 to extract the pixel pattern*/ switch (msm_io_r(vfe32_ctrl->vfebase + VFE_CFG) & 0x7) { @@ -1320,7 +1165,66 @@ static void vfe32_write_la_cfg(enum VFE32_DMI_RAM_SEL channel_sel, } vfe32_program_dmi_cfg(NO_MEM_SELECTED); } +static struct msm_free_buf *vfe32_check_free_buffer(int id, int path) +{ + struct vfe32_output_ch *outch = NULL; + struct msm_free_buf *b = NULL; + vfe32_subdev_notify(id, path); + switch (path) { + case VFE_MSG_OUTPUT_P: + case VFE_MSG_OUTPUT_T: + outch = &vfe32_ctrl->outpath.out0; + break; + case VFE_MSG_OUTPUT_S: + outch = &vfe32_ctrl->outpath.out1; + break; + case VFE_MSG_OUTPUT_V: + outch = &vfe32_ctrl->outpath.out2; + break; + } + if (outch->free_buf.paddr) + b = &outch->free_buf; + return b; +} +static int vfe32_configure_pingpong_buffers(int id, int path) +{ + struct vfe32_output_ch *outch = NULL; + int rc = 0; + vfe32_subdev_notify(id, path); + switch (path) { + case VFE_MSG_OUTPUT_P: + case VFE_MSG_OUTPUT_T: + outch = &vfe32_ctrl->outpath.out0; + break; + case VFE_MSG_OUTPUT_S: + outch = &vfe32_ctrl->outpath.out1; + break; + case VFE_MSG_OUTPUT_V: + outch = &vfe32_ctrl->outpath.out2; + break; + } + if (outch->ping.paddr && outch->pong.paddr) { + /* Configure Preview Ping Pong */ + pr_err("%s Configure ping/pong address for %d", __func__, path); + vfe32_put_ch_ping_addr(outch->ch0, + outch->ping.paddr + outch->ping.y_off); + vfe32_put_ch_ping_addr(outch->ch1, + outch->ping.paddr + outch->ping.cbcr_off); + vfe32_put_ch_pong_addr(outch->ch0, + outch->pong.paddr + outch->pong.y_off); + vfe32_put_ch_pong_addr(outch->ch1, + outch->pong.paddr + outch->pong.cbcr_off); + + /* avoid stale info */ + outch->ping.paddr = 0; + outch->pong.paddr = 0; + } else { + pr_err("%s ping/pong addr is null!!", __func__); + rc = -EINVAL; + } + return rc; +} static int vfe32_proc_general(struct msm_vfe32_cmd *cmd) { @@ -1341,6 +1245,14 @@ static int vfe32_proc_general(struct msm_vfe32_cmd *cmd) case V32_START: pr_info("vfe32_proc_general: cmdID = %s\n", vfe32_general_cmd[cmd->id]); + rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_START, + VFE_MSG_OUTPUT_P); + if (rc < 0) { + pr_err("%s error configuring pingpong buffers" + " for preview", __func__); + rc = -EINVAL; + goto proc_general_done; + } rc = vfe32_start(); break; case V32_UPDATE: @@ -1354,11 +1266,35 @@ static int vfe32_proc_general(struct msm_vfe32_cmd *cmd) rc = -EFAULT; goto proc_general_done; } + rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_CAPTURE, + VFE_MSG_OUTPUT_S); + if (rc < 0) { + pr_err("%s error configuring pingpong buffers" + " for preview", __func__); + rc = -EINVAL; + goto proc_general_done; + } + rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_CAPTURE, + VFE_MSG_OUTPUT_T); + if (rc < 0) { + pr_err("%s error configuring pingpong buffers" + " for preview", __func__); + rc = -EINVAL; + goto proc_general_done; + } rc = vfe32_capture(snapshot_cnt); break; case V32_START_RECORDING: pr_info("vfe32_proc_general: cmdID = %s\n", vfe32_general_cmd[cmd->id]); + rc = vfe32_configure_pingpong_buffers( + VFE_MSG_V32_START_RECORDING, VFE_MSG_OUTPUT_V); + if (rc < 0) { + pr_err("%s error configuring pingpong buffers" + " for recording", __func__); + rc = -EINVAL; + goto proc_general_done; + } rc = vfe32_start_recording(); break; case V32_STOP_RECORDING: @@ -2280,23 +2216,6 @@ static void vfe32_process_error_irq(uint32_t errStatus) pr_err("vfe32_irq: axi error\n"); } -#define VFE32_AXI_OFFSET 0x0050 -#define vfe32_get_ch_ping_addr(chn) \ - (msm_io_r(vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn))) -#define vfe32_get_ch_pong_addr(chn) \ - (msm_io_r(vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4)) -#define vfe32_get_ch_addr(ping_pong, chn) \ - (((ping_pong) & (1 << (chn))) == 0 ? \ - vfe32_get_ch_pong_addr(chn) : vfe32_get_ch_ping_addr(chn)) - -#define vfe32_put_ch_ping_addr(chn, addr) \ - (msm_io_w((addr), vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn))) -#define vfe32_put_ch_pong_addr(chn, addr) \ - (msm_io_w((addr), vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4)) -#define vfe32_put_ch_addr(ping_pong, chn, addr) \ - (((ping_pong) & (1 << (chn))) == 0 ? \ - vfe32_put_ch_pong_addr((chn), (addr)) : \ - vfe32_put_ch_ping_addr((chn), (addr))) static void vfe32_process_output_path_irq_0(void) { @@ -2306,8 +2225,16 @@ static void vfe32_process_output_path_irq_0(void) uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong; #endif uint8_t out_bool = 0; - struct vfe32_free_buf *free_buf = NULL; - free_buf = vfe32_dequeue_free_buf(&vfe32_ctrl->outpath.out0); + struct msm_free_buf *free_buf = NULL; + if (vfe32_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_SNAPSHOT) + free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_T); + else + free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_P); + if (!free_buf) + pr_err(" Output IRQ 0: NO FREE BUFF"); /* we render frames in the following conditions: 1. Continuous mode and the free buffer is avaialable. 2. In snapshot shot mode, free buffer is not always available. @@ -2343,7 +2270,6 @@ static void vfe32_process_output_path_irq_0(void) vfe32_put_ch_addr(ping_pong, vfe32_ctrl->outpath.out0.ch1, free_buf->paddr + free_buf->cbcr_off); - kfree(free_buf); } if (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_SNAPSHOT) { @@ -2408,9 +2334,11 @@ static void vfe32_process_output_path_irq_1(void) #endif /* this must be snapshot main image output. */ uint8_t out_bool = 0; - struct vfe32_free_buf *free_buf = NULL; - free_buf = vfe32_dequeue_free_buf(&vfe32_ctrl->outpath.out1); - + struct msm_free_buf *free_buf = NULL; + free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_S); + if (!free_buf) + pr_err(" Output IRQ 1: NO FREE BUFF"); /* we render frames in the following conditions: 1. Continuous mode and the free buffer is avaialable. 2. In snapshot shot mode, free buffer is not always available. @@ -2445,7 +2373,6 @@ static void vfe32_process_output_path_irq_1(void) vfe32_put_ch_addr(ping_pong, vfe32_ctrl->outpath.out1.ch1, free_buf->paddr + free_buf->cbcr_off); - kfree(free_buf); } if (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_SNAPSHOT || @@ -2505,9 +2432,11 @@ static void vfe32_process_output_path_irq_2(void) uint32_t pyaddr_ping, pcbcraddr_ping, pyaddr_pong, pcbcraddr_pong; #endif uint8_t out_bool = 0; - struct vfe32_free_buf *free_buf = NULL; - free_buf = vfe32_dequeue_free_buf(&vfe32_ctrl->outpath.out2); - + struct msm_free_buf *free_buf = NULL; + free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_V); + if (!free_buf) + pr_err(" Output IRQ 2: NO FREE BUFF"); /* we render frames in the following conditions: 1. Continuous mode and the free buffer is avaialable. 2. In snapshot shot mode, free buffer is not always available. @@ -2545,7 +2474,6 @@ static void vfe32_process_output_path_irq_2(void) vfe32_put_ch_addr(ping_pong, vfe32_ctrl->outpath.out2.ch1, free_buf->paddr + free_buf->cbcr_off); - kfree(free_buf); } vfe_send_outmsg(MSG_ID_OUTPUT_V, pyaddr, pcbcraddr); } else { @@ -3033,8 +2961,8 @@ static int vfe32_resource_init(struct platform_device *pdev, void *sdata) spin_lock_init(&vfe32_ctrl->aec_ack_lock); spin_lock_init(&vfe32_ctrl->awb_ack_lock); spin_lock_init(&vfe32_ctrl->af_ack_lock); + spin_lock_init(&vfe32_ctrl->sd_notify_lock); INIT_LIST_HEAD(&vfe32_ctrl->tasklet_q); - vfe32_init_free_buf_queues(); vfe32_ctrl->syncdata = sdata; vfe32_ctrl->vfemem = vfemem; @@ -3066,6 +2994,9 @@ static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd, struct msm_pmem_region *regptr = NULL; struct vfe_cmd_stats_ack *sack = NULL; if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE && + cmd->cmd_type != CMD_CONFIG_PING_ADDR && + cmd->cmd_type != CMD_CONFIG_PONG_ADDR && + cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR && cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE && cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE && cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE && @@ -3081,7 +3012,10 @@ static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd, } } else { /* here eith stats release or frame release. */ - if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE) { + if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE && + cmd->cmd_type != CMD_CONFIG_PING_ADDR && + cmd->cmd_type != CMD_CONFIG_PONG_ADDR && + cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) { /* then must be stats release. */ if (!data) return -EFAULT; @@ -3176,7 +3110,51 @@ static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd, break; } - rc = vfe32_enqueue_free_buf(outch, p, b->y_off, b->cbcr_off); + } + break; + + case CMD_CONFIG_PING_ADDR: { + struct vfe32_output_ch *outch = NULL; + int path = *((int *)cmd->value); + if ((path == VFE_MSG_OUTPUT_P) + || (path == VFE_MSG_OUTPUT_T)) + outch = &vfe32_ctrl->outpath.out0; + else if (path == VFE_MSG_OUTPUT_S) + outch = &vfe32_ctrl->outpath.out1; + else if (path == VFE_MSG_OUTPUT_V) + outch = &vfe32_ctrl->outpath.out2; + + outch->ping = *((struct msm_free_buf *)data); + } + break; + + case CMD_CONFIG_PONG_ADDR: { + struct vfe32_output_ch *outch = NULL; + int path = *((int *)cmd->value); + if ((path == VFE_MSG_OUTPUT_P) + || (path == VFE_MSG_OUTPUT_T)) + outch = &vfe32_ctrl->outpath.out0; + else if (path == VFE_MSG_OUTPUT_S) + outch = &vfe32_ctrl->outpath.out1; + else if (path == VFE_MSG_OUTPUT_V) + outch = &vfe32_ctrl->outpath.out2; + + outch->pong = *((struct msm_free_buf *)data); + } + break; + + case CMD_CONFIG_FREE_BUF_ADDR: { + struct vfe32_output_ch *outch = NULL; + int path = *((int *)cmd->value); + if ((path == VFE_MSG_OUTPUT_P) + || (path == VFE_MSG_OUTPUT_T)) + outch = &vfe32_ctrl->outpath.out0; + else if (path == VFE_MSG_OUTPUT_S) + outch = &vfe32_ctrl->outpath.out1; + else if (path == VFE_MSG_OUTPUT_V) + outch = &vfe32_ctrl->outpath.out2; + + outch->free_buf = *((struct msm_free_buf *)data); } break; @@ -3360,7 +3338,6 @@ void msm_vfe_subdev_release(struct platform_device *pdev) { struct resource *vfemem, *vfeio; - vfe32_reset_free_buf_queues(); CDBG("%s, free_irq\n", __func__); free_irq(vfe32_ctrl->vfeirq, 0); tasklet_kill(&vfe32_tasklet); diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h index 4d48c6b1fcc..4008c68b174 100644 --- a/drivers/media/video/msm/msm_vfe32.h +++ b/drivers/media/video/msm/msm_vfe32.h @@ -895,6 +895,9 @@ struct vfe32_output_ch { int8_t ch2; uint32_t capture_cnt; uint32_t frame_drop_cnt; + struct msm_free_buf ping; + struct msm_free_buf pong; + struct msm_free_buf free_buf; }; /* no error irq in mask 0 */ @@ -1082,6 +1085,7 @@ struct vfe32_ctrl_type { /* v4l2 subdev */ struct v4l2_subdev *subdev; + spinlock_t sd_notify_lock; }; #define statsAeNum 0 diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h index 4544a676c88..e6d7c20a16e 100644 --- a/include/media/msm_camera.h +++ b/include/media/msm_camera.h @@ -305,6 +305,9 @@ struct msm_camera_cfg_cmd { #define CMD_AXI_CFG_ZSL 43 #define CMD_AXI_CFG_SNAP_VPE 44 #define CMD_AXI_CFG_SNAP_THUMB_VPE 45 +#define CMD_CONFIG_PING_ADDR 46 +#define CMD_CONFIG_PONG_ADDR 47 +#define CMD_CONFIG_FREE_BUF_ADDR 48 /* vfe config command: config command(from config thread)*/ struct msm_vfe_cfg_cmd {