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 <hurlisal@codeaurora.org>
Signed-off-by: Mingcheng Zhu <mingchen@codeaurora.org>
This commit is contained in:
Kiran Kumar H N
2011-07-17 12:31:53 -07:00
committed by Bryan Huntsman
parent 9812bd34ec
commit 0fb9dcfbc6
8 changed files with 331 additions and 265 deletions

View File

@@ -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 {

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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, <<<REMOVE<<< buffer 0x%x, index %d"
" from free Q", __func__, pcam_inst,
buf_phyaddr, buf->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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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 {