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>
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index b49300d..c7ec849 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -81,6 +81,10 @@
 	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 6ded98b..28d8e8a 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -639,7 +639,7 @@
 	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 @@
 	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 @@
 	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 7390f10..89434b3 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -354,7 +354,9 @@
 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 480c626..c88e106 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -171,6 +171,11 @@
 	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 @@
 		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 d084f9c..12f8a2c 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -211,6 +211,9 @@
 	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_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 @@
 	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 @@
 	/* 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 @@
 	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 @@
 			__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 @@
 	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 @@
 			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 946f823..8df366f 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -34,6 +34,24 @@
 	}								\
 }
 
+#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 @@
 		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 @@
 
 	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 @@
 		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 @@
 		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 @@
 		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(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 @@
 #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 @@
 	}
 	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 @@
 	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 @@
 			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 @@
 		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 @@
 	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 @@
 			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 @@
 #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 @@
 			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 @@
 	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 @@
 			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 @@
 	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 @@
 	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 @@
 		}
 	} 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 @@
 			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 @@
 {
 	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 4d48c6b..4008c68 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -895,6 +895,9 @@
 	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 @@
 
 	/* 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 4544a67..e6d7c20 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -305,6 +305,9 @@
 #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 {