msm: add video processing engine (VPE) as a V4L2 subdev in 8960.

Signed-off-by: Mingcheng Zhu <mingchen@codeaurora.org>
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 1221ead..7dbcafe 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -933,6 +933,18 @@
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
+		.name	= "vpe",
+		.start	= 0x05300000,
+		.end	= 0x05300000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "vpe",
+		.start	= VPE_IRQ,
+		.end	= VPE_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
 		.name	= "vid_buf",
 		.flags	= IORESOURCE_DMA,
 	},
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 59bde6d..567a290 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -293,6 +293,11 @@
 	void *data;
 };
 
+struct msm_mctl_pp_params {
+	struct msm_mctl_pp_cmd *cmd;
+	void *data;
+};
+
 struct msm_camvpe_fn {
 	int (*vpe_reg)(struct msm_vpe_callback *);
 	int (*vpe_cfg_update) (void *);
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 35795fc..bd3fffe 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -4,7 +4,7 @@
 endif
 
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
-  obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o
+  obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
   obj-$(CONFIG_MSM_CAMERA) += io/ sensors/ actuators/
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 624c15c..e3b97c9 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1449,6 +1449,14 @@
 				__func__, rc);
 			return rc;
 		}
+		rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
+					&pcam->mctl.isp_sdev->sd_vpe);
+		if (rc < 0) {
+			mutex_unlock(&pcam->vid_lock);
+			pr_err("%s: vpe v4l2_device_register_subdev failed rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
 
 		rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
 							pcam->pvdev);
@@ -1501,7 +1509,6 @@
 		pr_err("%s: cannot map vaddr", __func__);
 		return -EFAULT;
 	}
-	pr_err("%s: phy_addr=0x%x\n", __func__, (uint32_t)phyaddr);
 	size = vma->vm_end - vma->vm_start;
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	retval = remap_pfn_range(vma, vma->vm_start,
@@ -1531,10 +1538,8 @@
 
 	if (pcam_inst->is_mem_map_inst &&
 		pcam_inst->mem_map.cookie) {
-		pr_err("%s: ioremap called, vma=0x%08lx\n",
-			 __func__, (unsigned long)vma);
 		rc = msm_addr_remap(pcam_inst, vma);
-		pr_err("%s: msm_addr_remap ret=%d\n", __func__, rc);
+		D("%s: msm_addr_remap ret=%d\n", __func__, rc);
 		return rc;
 	} else
 		rc = vb2_mmap(&pcam_inst->vid_bufq, vma);
@@ -1911,7 +1916,9 @@
 			break;
 		}
 		if (ev.type != (V4L2_EVENT_PRIVATE_START +
-				MSM_CAM_RESP_DIV_FRAME_EVT_MSG)) {
+				MSM_CAM_RESP_DIV_FRAME_EVT_MSG) &&
+				ev.type != (V4L2_EVENT_PRIVATE_START +
+				MSM_CAM_RESP_MCTL_PP_EVENT)) {
 			k_isp_event =
 			(struct msm_isp_stats_event_ctrl *)ev.u.data;
 			if (ev.type == (V4L2_EVENT_PRIVATE_START +
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index c2df360..001ca4b 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -30,6 +30,7 @@
 #include <media/videobuf2-msm-mem.h>
 #include <media/msm_isp.h>
 #include <mach/camera.h>
+#include <media/msm_isp.h>
 
 #define MSM_V4L2_DIMENSION_SIZE 96
 #define MAX_DEV_NAME_LEN 50
@@ -87,6 +88,7 @@
 struct msm_free_buf {
 	uint8_t num_planes;
 	uint32_t ch_paddr[VIDEO_MAX_PLANES];
+	uint32_t vb;
 };
 
 struct isp_msg_output {
@@ -103,6 +105,7 @@
 	NOTIFY_VFE_MSG_STATS,  /* arg = struct isp_msg_stats */
 	NOTIFY_VFE_BUF_EVT, /* arg = struct msm_vfe_resp */
 	NOTIFY_ISPIF_STREAM, /* arg = enable parameter for s_stream */
+	NOTIFY_VPE_MSG_EVT,
 	NOTIFY_INVALID
 };
 
@@ -147,13 +150,26 @@
 	enum v4l2_colorspace colorspace;
 };
 
+struct msm_mctl_pp_frame_info {
+	int user_cmd;
+	struct msm_pp_frame src_frame;
+	struct msm_pp_frame dest_frame;
+	struct msm_mctl_pp_frame_cmd pp_frame_cmd;
+};
 
+struct msm_mctl_pp_ctrl {
+	int pp_msg_type;
+	struct msm_mctl_pp_frame_info *pp_frame_info;
+
+};
 struct msm_mctl_pp_info {
 	spinlock_t lock;
 	uint32_t cnt;
 	uint32_t pp_key;
 	uint32_t cur_frame_id[MSM_MAX_IMG_MODE];
 	struct msm_free_buf div_frame[MSM_MAX_IMG_MODE];
+	struct msm_mctl_pp_ctrl pp_ctrl;
+
 };
 /* "Media Controller" represents a camera steaming session,
  * which consists of a "sensor" device and an "isp" device
@@ -204,16 +220,19 @@
 	char *config_dev_name;
 
 	/*int (*isp_init)(struct msm_cam_v4l2_device *pcam);*/
-	int (*isp_open)(struct v4l2_subdev *sd, struct msm_sync *sync);
+	int (*isp_open)(struct v4l2_subdev *sd, struct v4l2_subdev *sd_vpe,
+					struct msm_sync *sync);
 	int (*isp_config)(struct msm_cam_media_controller *pmctl,
 		 unsigned int cmd, unsigned long arg);
 	int (*isp_notify)(struct v4l2_subdev *sd,
 		unsigned int notification, void *arg);
-
 	void (*isp_release)(struct msm_sync *psync);
+	int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
+		 struct msm_mctl_pp_cmd, void *data);
 
 	/* vfe subdevice */
 	struct v4l2_subdev sd;
+	struct v4l2_subdev sd_vpe;
 };
 
 struct msm_isp_buf_info {
@@ -396,6 +415,52 @@
 
 int msm_isp_subdev_ioctl(struct v4l2_subdev *sd,
 	struct msm_vfe_cfg_cmd *cfgcmd, void *data);
+int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data,
+	struct platform_device *pdev);
+void msm_vpe_subdev_release(struct platform_device *pdev);
+int msm_isp_subdev_ioctl_vpe(struct v4l2_subdev *isp_subdev,
+	struct msm_mctl_pp_cmd *cmd, void *data);
+int msm_mctl_is_pp_msg_type(struct msm_cam_media_controller *p_mctl,
+	int msg_type);
+int msm_mctl_do_pp(struct msm_cam_media_controller *p_mctl,
+			int msg_type, uint32_t y_phy, uint32_t frame_id);
+int msm_mctl_pp_ioctl(struct msm_cam_media_controller *p_mctl,
+			unsigned int cmd, unsigned long arg);
+int msm_mctl_pp_notify(struct msm_cam_media_controller *pmctl,
+			struct msm_mctl_pp_frame_info *pp_frame_info);
+int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam,
+					int out_type);
+struct msm_frame_buffer *msm_mctl_buf_find(
+	struct msm_cam_media_controller *pmctl,
+	struct msm_cam_v4l2_dev_inst *pcam_inst, int del_buf,
+	int msg_type, struct msm_free_buf *fbuf);
+void msm_mctl_gettimeofday(struct timeval *tv);
+struct msm_frame_buffer *msm_mctl_get_free_buf(
+		struct msm_cam_media_controller *pmctl,
+		int msg_type);
+int msm_mctl_put_free_buf(
+		struct msm_cam_media_controller *pmctl,
+		int msg_type, struct msm_frame_buffer *buf);
+int msm_mctl_check_pp(struct msm_cam_media_controller *p_mctl,
+		int msg_type, int *pp_divert_type, int *pp_type);
+int msm_mctl_do_pp_divert(
+	struct msm_cam_media_controller *p_mctl,
+	int msg_type, struct msm_free_buf *fbuf,
+	uint32_t frame_id, int pp_type);
+int msm_mctl_buf_del(struct msm_cam_media_controller *pmctl,
+	int msg_type,
+	struct msm_frame_buffer *my_buf);
+int msm_mctl_pp_release_free_frame(
+	struct msm_cam_media_controller *p_mctl,
+	void __user *arg);
+int msm_mctl_pp_reserve_free_frame(
+	struct msm_cam_media_controller *p_mctl,
+	void __user *arg);
+int msm_mctl_set_pp_key(struct msm_cam_media_controller *p_mctl,
+				void __user *arg);
+int msm_mctl_pp_done(
+	struct msm_cam_media_controller *p_mctl,
+	void __user *arg);
 #endif /* __KERNEL__ */
 
 #endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index f8f1530..7682d7a 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -137,7 +137,7 @@
 /*
  * This function executes in interrupt context.
  */
-static int msm_isp_notify(struct v4l2_subdev *sd,
+static int msm_isp_notify_vfe(struct v4l2_subdev *sd,
 	unsigned int notification,  void *arg)
 {
 	int rc = 0;
@@ -244,8 +244,30 @@
 	return rc;
 }
 
+static int msm_isp_notify_vpe(struct v4l2_subdev *sd, void *arg)
+{
+	struct msm_sync *sync =
+		(struct msm_sync *)v4l2_get_subdev_hostdata(sd);
+	struct msm_vpe_resp *vdata = (struct msm_vpe_resp *)arg;
+
+	msm_mctl_pp_notify(&sync->pcam_sync->mctl,
+		(struct msm_mctl_pp_frame_info *)vdata->extdata);
+	return 0;
+}
+
+static int msm_isp_notify(struct v4l2_subdev *sd,
+	unsigned int notification, void *arg)
+{
+	if (notification == NOTIFY_VPE_MSG_EVT)
+		return msm_isp_notify_vpe(sd, arg);
+	else
+		return msm_isp_notify_vfe(sd, notification, arg);
+}
+
 /* This function is called by open() function, so we need to init HW*/
-static int msm_isp_open(struct v4l2_subdev *sd, struct msm_sync *sync)
+static int msm_isp_open(struct v4l2_subdev *sd,
+	struct v4l2_subdev *sd_vpe,
+	struct msm_sync *sync)
 {
 	/* init vfe and senor, register sync callbacks for init*/
 	int rc = 0;
@@ -261,7 +283,12 @@
 		pr_err("%s: vfe_init failed at %d\n",
 					__func__, rc);
 	}
-
+	D("%s: init vpe subdev", __func__);
+	rc = msm_vpe_subdev_init(sd_vpe, sync, sync->pdev);
+	if (rc < 0) {
+		pr_err("%s: vpe_init failed at %d\n",
+					__func__, rc);
+	}
 	return rc;
 }
 
@@ -269,6 +296,7 @@
 {
 	D("%s\n", __func__);
 	msm_vfe_subdev_release(psync->pdev);
+	msm_vpe_subdev_release(psync->pdev);
 }
 
 static int msm_config_vfe(struct v4l2_subdev *sd,
@@ -688,3 +716,15 @@
 	vfe_params.data = data;
 	return v4l2_subdev_call(isp_subdev, core, ioctl, 0, &vfe_params);
 }
+
+int msm_isp_subdev_ioctl_vpe(struct v4l2_subdev *isp_subdev,
+	struct msm_mctl_pp_cmd *cmd, void *data)
+{
+	int rc = 0;
+	struct msm_mctl_pp_params parm;
+	parm.cmd = cmd;
+	parm.data = data;
+	rc = v4l2_subdev_call(isp_subdev, core, ioctl, 0, &parm);
+	return rc;
+}
+
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 9b4823b..f684b4f 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -162,7 +162,7 @@
 /* called by other subdev to notify any changes*/
 
 static int msm_mctl_notify(struct msm_cam_media_controller *p_mctl,
-			unsigned int notification, void *arg)
+	unsigned int notification, void *arg)
 {
 	int rc = -EINVAL;
 	struct msm_camera_sensor_info *sinfo =
@@ -204,76 +204,16 @@
 				&p_mctl->isp_sdev->sd, notification, arg);
 		}
 		break;
-	default:
-		break;
-	}
-
-	return rc;
-}
-
-static int msm_mctl_set_pp_key(struct msm_cam_media_controller *p_mctl,
-				void __user *arg)
-{
-	int rc = 0;
-	unsigned long flags;
-	spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
-	if (copy_from_user(&p_mctl->pp_info.pp_key,
-			arg, sizeof(p_mctl->pp_info.pp_key)))
-		rc = -EFAULT;
-	else
-		D("%s: mctl=0x%p, pp_key_setting=0x%x",
-			__func__, p_mctl, p_mctl->pp_info.pp_key);
-
-	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
-	return rc;
-}
-
-static int msm_mctl_pp_done(struct msm_cam_media_controller *p_mctl,
-				void __user *arg)
-{
-	struct msm_frame frame;
-	int msg_type, image_mode, rc = 0;
-	int dirty = 0;
-	struct msm_free_buf buf;
-	unsigned long flags;
-
-	if (copy_from_user(&frame, arg, sizeof(frame)))
-		return -EFAULT;
-	spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
-	switch (frame.path) {
-	case OUTPUT_TYPE_P:
-		if (!(p_mctl->pp_info.pp_key & PP_PREV)) {
-			rc = -EFAULT;
-			goto err;
+	case NOTIFY_VPE_MSG_EVT:
+		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_notify) {
+			rc = p_mctl->isp_sdev->isp_notify(
+				&p_mctl->isp_sdev->sd_vpe, notification, arg);
 		}
-		msg_type = VFE_MSG_OUTPUT_P;
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
 		break;
-	case OUTPUT_TYPE_S:
-		if (!(p_mctl->pp_info.pp_key & PP_SNAP))
-			return -EFAULT;
-		msg_type = VFE_MSG_OUTPUT_S;
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
-		break;
-	case OUTPUT_TYPE_T:
-	case OUTPUT_TYPE_V:
 	default:
-		rc = -EFAULT;
-		goto err;
+		break;
 	}
-	memcpy(&buf, &p_mctl->pp_info.div_frame[image_mode], sizeof(buf));
-	memset(&p_mctl->pp_info.div_frame[image_mode], 0, sizeof(buf));
-	if (p_mctl->pp_info.cur_frame_id[image_mode] !=
-					frame.frame_id) {
-		/* dirty frame. should not pass to app */
-		dirty = 1;
-	}
-	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
-	/* here buf.addr is phy_addr */
-	rc = msm_mctl_buf_done_pp(p_mctl, msg_type, &buf, dirty);
-	return rc;
-err:
-	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+
 	return rc;
 }
 
@@ -288,7 +228,7 @@
 		pr_err("%s: param is NULL", __func__);
 		return -EINVAL;
 	}
-	D("%s start cmd = %d\n", __func__, _IOC_NR(cmd));
+	D("%s cmd = %d\n", __func__, _IOC_NR(cmd));
 
 	/* ... call sensor, ISPIF or VEF subdev*/
 	switch (cmd) {
@@ -342,13 +282,25 @@
 	case MSM_CAM_IOCTL_PICT_PP_DONE:
 		rc = msm_mctl_pp_done(p_mctl, (void __user *)arg);
 		break;
+	case MSM_CAM_IOCTL_MCTL_POST_PROC:
+		rc = msm_mctl_pp_ioctl(p_mctl, cmd, arg);
+		break;
+	case MSM_CAM_IOCTL_RESERVE_FREE_FRAME:
+		rc = msm_mctl_pp_reserve_free_frame(p_mctl,
+			(void __user *)arg);
+		break;
+	case MSM_CAM_IOCTL_RELEASE_FREE_FRAME:
+		rc = msm_mctl_pp_release_free_frame(p_mctl,
+			(void __user *)arg);
+		break;
 			/* ISFIF config*/
 	default:
 		/* ISP config*/
 		rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg);
 		break;
 	}
-	D("%s: !!! cmd = %d, rc = %d\n", __func__, _IOC_NR(cmd), rc);
+	D("%s: !!! cmd = %d, rc = %d\n",
+		__func__, _IOC_NR(cmd), rc);
 	return rc;
 }
 
@@ -382,8 +334,8 @@
 		/* ISP first*/
 		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_open)
 			rc = p_mctl->isp_sdev->isp_open(
-				&p_mctl->isp_sdev->sd, sync);
-
+				&p_mctl->isp_sdev->sd,
+				&p_mctl->isp_sdev->sd_vpe, sync);
 		if (rc < 0) {
 			pr_err("%s: isp init failed: %d\n", __func__, rc);
 			goto msm_open_done;
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 92549b6..617c8b4 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -352,7 +352,7 @@
 	return 0;
 }
 
-static int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam,
+int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam,
 					int out_type)
 {
 	switch (out_type) {
@@ -374,7 +374,7 @@
 	return 0;
 }
 
-static void msm_mctl_gettimeofday(struct timeval *tv)
+void msm_mctl_gettimeofday(struct timeval *tv)
 {
 	struct timespec ts;
 
@@ -385,7 +385,7 @@
 	tv->tv_usec = ts.tv_nsec/1000;
 }
 
-static struct msm_frame_buffer *msm_mctl_buf_find(
+struct msm_frame_buffer *msm_mctl_buf_find(
 	struct msm_cam_media_controller *pmctl,
 	struct msm_cam_v4l2_dev_inst *pcam_inst, int del_buf,
 	int msg_type, struct msm_free_buf *fbuf)
@@ -442,115 +442,29 @@
 	return 0;
 }
 
-static int msm_mctl_buf_divert(
-			struct msm_cam_media_controller *pmctl,
-			struct msm_cam_v4l2_dev_inst *pcam_inst,
-			struct msm_cam_evt_divert_frame *div)
-{
-	struct v4l2_event v4l2_evt;
-	struct msm_cam_evt_divert_frame *tmp;
-	memset(&v4l2_evt, 0, sizeof(v4l2_evt));
-	v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
-			MSM_CAM_RESP_DIV_FRAME_EVT_MSG;
-	memcpy(&v4l2_evt.u.data[0], div,
-			sizeof(struct msm_cam_evt_divert_frame));
-	D("%s inst=%p, img_mode=%d, frame_id=%d,phy=0x%x,len=%d\n",
-		__func__, pcam_inst, pcam_inst->image_mode, div->frame_id,
-		(uint32_t)div->phy_addr, div->length);
-	tmp = (struct msm_cam_evt_divert_frame *)&v4l2_evt.u.data[0];
-	v4l2_event_queue(
-		pmctl->config_device->config_stat_event_queue.pvdev,
-		&v4l2_evt);
-	return 0;
-}
-
 int msm_mctl_buf_done(struct msm_cam_media_controller *p_mctl,
 			int msg_type, struct msm_free_buf *fbuf,
 			uint32_t frame_id)
 {
-	uint32_t pp_key = 0;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
-	int idx;
-	int del_buf = 0;
-	int image_mode = MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT;
-	unsigned long flags;
-	int path = 0;
+	int idx, rc;
+	int pp_divert_type = 0, pp_type = 0;
 
-
-	idx = msm_mctl_out_type_to_inst_index(
-					p_mctl->sync.pcam_sync, msg_type);
-	pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx];
-	switch (msg_type) {
-	case VFE_MSG_OUTPUT_P:
-		pp_key = PP_PREV;
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
-		path = OUTPUT_TYPE_P;
-		break;
-	case VFE_MSG_OUTPUT_S:
-		pp_key = PP_SNAP;
-		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
-		path = OUTPUT_TYPE_S;
-		break;
-	case VFE_MSG_OUTPUT_T:
-	default:
-	  path = OUTPUT_TYPE_T;
-		break;
+	msm_mctl_check_pp(p_mctl, msg_type, &pp_divert_type, &pp_type);
+	D("%s: pp_type=%d, pp_divert_type = %d",
+		 __func__, pp_type, pp_divert_type);
+	if (pp_type || pp_divert_type)
+		rc = msm_mctl_do_pp_divert(p_mctl,
+		msg_type, fbuf, frame_id, pp_type);
+	else {
+		idx = msm_mctl_out_type_to_inst_index(
+				p_mctl->sync.pcam_sync, msg_type);
+		pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx];
+		rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
+				msg_type, fbuf,
+				&frame_id, 1);
 	}
-	spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
-	if (p_mctl->pp_info.pp_key & pp_key) {
-		int rc = 0;
-		struct msm_cam_evt_divert_frame div;
-		struct msm_frame_buffer *vb = NULL;
-		struct videobuf2_contig_pmem *mem;
-
-		p_mctl->pp_info.cur_frame_id[image_mode]++;
-		if (!p_mctl->pp_info.cur_frame_id[image_mode])
-			p_mctl->pp_info.cur_frame_id[image_mode] = 1;
-		if (!p_mctl->pp_info.div_frame[image_mode].ch_paddr[0]) {
-			/* no frame in postproc. good to divert the frame up */
-			memset(&div, 0, sizeof(div));
-			vb = msm_mctl_buf_find(p_mctl, pcam_inst,
-					del_buf, msg_type, fbuf);
-			if (!vb) {
-				spin_unlock_irqrestore(&p_mctl->pp_info.lock,
-					flags);
-				return -EINVAL;
-			}
-			vb->vidbuf.v4l2_buf.sequence = frame_id;
-			mem = vb2_plane_cookie(&vb->vidbuf, 0);
-			div.image_mode = pcam_inst->image_mode;
-			div.op_mode    = pcam_inst->pcam->op_mode;
-			div.inst_idx   = pcam_inst->my_index;
-			div.node_idx   = pcam_inst->pcam->vnode_id;
-			div.phy_addr   =
-				videobuf2_to_pmem_contig(&vb->vidbuf, 0);
-			div.phy_offset = mem->addr_offset;
-			div.offset   = mem->offset;
-			div.fd         = (int)mem->vaddr;
-			div.frame_id   =
-				p_mctl->pp_info.cur_frame_id[image_mode];
-			div.path       = path;
-			div.length     = mem->size;
-			msm_mctl_gettimeofday(&div.timestamp);
-			vb->vidbuf.v4l2_buf.timestamp = div.timestamp;
-			p_mctl->pp_info.div_frame[image_mode].num_planes =
-				pcam_inst->plane_info.num_planes;
-			p_mctl->pp_info.div_frame[image_mode].ch_paddr[0] =
-				div.phy_addr;
-			p_mctl->pp_info.div_frame[image_mode].ch_paddr[1] =
-				div.phy_addr + div.offset;
-			p_mctl->pp_info.div_frame[image_mode].ch_paddr[2] =
-				0;
-			rc = msm_mctl_buf_divert(p_mctl, pcam_inst, &div);
-			spin_unlock_irqrestore(&p_mctl->pp_info.lock,
-				flags);
-			return rc;
-		}
-	}
-	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
-	return msm_mctl_buf_done_proc(p_mctl, pcam_inst,
-					msg_type, fbuf,
-					&frame_id, 1);
+	return rc;
 }
 
 int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam)
@@ -600,6 +514,7 @@
 				free_buf->ch_paddr[1] =
 					free_buf->ch_paddr[0] + mem->offset;
 			}
+			free_buf->vb = (uint32_t)buf;
 			buf->state = MSM_BUFFER_STATE_RESERVED;
 			D("%s idx=%d,inst=0x%p,idx=%d,paddr=0x%x, "
 				"ch1 addr=0x%x\n", __func__,
@@ -672,3 +587,98 @@
 	return rc;
 }
 
+struct msm_frame_buffer *msm_mctl_get_free_buf(
+		struct msm_cam_media_controller *pmctl,
+		int msg_type)
+{
+	struct msm_cam_v4l2_dev_inst *pcam_inst;
+	unsigned long flags = 0;
+	struct msm_frame_buffer *buf = NULL;
+	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];
+	if (!pcam_inst->streamon) {
+		D("%s: stream 0x%p is off\n", __func__, pcam_inst);
+		return NULL;
+	}
+	spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
+	if (!list_empty(&pcam_inst->free_vq)) {
+		list_for_each_entry(buf, &pcam_inst->free_vq, list) {
+			if (buf->state == MSM_BUFFER_STATE_QUEUED) {
+				buf->state = MSM_BUFFER_STATE_RESERVED;
+				rc = 0;
+				break;
+			}
+		}
+	}
+	if (rc != 0) {
+		D("%s:No free buffer available: inst = 0x%p ",
+				__func__, pcam_inst);
+		buf = NULL;
+	}
+	spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+	return buf;
+}
+
+int msm_mctl_put_free_buf(
+		struct msm_cam_media_controller *pmctl,
+		int msg_type, struct msm_frame_buffer *my_buf)
+{
+	struct msm_cam_v4l2_dev_inst *pcam_inst;
+	unsigned long flags = 0;
+	int rc = 0, idx;
+	struct msm_frame_buffer *buf = NULL;
+
+	idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync,
+		msg_type);
+	pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+	if (!pcam_inst->streamon) {
+		D("%s: stream 0x%p is off\n", __func__, pcam_inst);
+		return rc;
+	}
+	spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
+	if (!list_empty(&pcam_inst->free_vq)) {
+		list_for_each_entry(buf, &pcam_inst->free_vq, list) {
+			if (my_buf == buf) {
+				buf->state = MSM_BUFFER_STATE_QUEUED;
+				spin_unlock_irqrestore(&pcam_inst->vq_irqlock,
+					flags);
+				return 0;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+	return rc;
+}
+
+int msm_mctl_buf_del(struct msm_cam_media_controller *pmctl,
+	int msg_type,
+	struct msm_frame_buffer *my_buf)
+{
+	struct msm_cam_v4l2_dev_inst *pcam_inst;
+	struct msm_frame_buffer *buf = NULL;
+	unsigned long flags = 0;
+	int idx;
+
+	idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync,
+		msg_type);
+	pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+	D("%s: idx = %d, pinst=0x%p", __func__, idx, pcam_inst);
+	spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
+	if (!list_empty(&pcam_inst->free_vq)) {
+		list_for_each_entry(buf, &pcam_inst->free_vq, list) {
+			if (my_buf == buf) {
+				list_del_init(&buf->list);
+				spin_unlock_irqrestore(&pcam_inst->vq_irqlock,
+					flags);
+				return 0;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+	pr_err("%s: buf 0x%p not found", __func__, my_buf);
+	return -EINVAL;
+}
+
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
new file mode 100644
index 0000000..167e721
--- /dev/null
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -0,0 +1,746 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+#include <linux/android_pmem.h>
+
+#include "msm.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static int msm_mctl_pp_buf_divert(
+			struct msm_cam_media_controller *pmctl,
+			struct msm_cam_v4l2_dev_inst *pcam_inst,
+			struct msm_cam_evt_divert_frame *div)
+{
+	struct v4l2_event v4l2_evt;
+
+	D("%s: msm_cam_evt_divert_frame=%d",
+		   __func__, sizeof(struct msm_cam_evt_divert_frame));
+	memset(&v4l2_evt, 0, sizeof(v4l2_evt));
+	v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+			MSM_CAM_RESP_DIV_FRAME_EVT_MSG;
+	memcpy(&v4l2_evt.u.data[0], div,
+			sizeof(struct msm_cam_evt_divert_frame));
+	D("%s inst=%p, img_mode=%d, frame_id=%d,phy=0x%x,len=%d\n",
+		__func__, pcam_inst, pcam_inst->image_mode, div->frame_id,
+		(uint32_t)div->phy_addr, div->length);
+	v4l2_event_queue(
+		pmctl->config_device->config_stat_event_queue.pvdev,
+		&v4l2_evt);
+	return 0;
+}
+
+int msm_mctl_check_pp(struct msm_cam_media_controller *p_mctl,
+	int msg_type, int *pp_divert_type, int *pp_type)
+{
+	int rc = 0;
+	unsigned long flags;
+	uint32_t pp_key = 0;
+	int image_mode = MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT;
+
+	*pp_type = 0;
+	*pp_divert_type = 0;
+	spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
+	switch (msg_type) {
+	case VFE_MSG_OUTPUT_P:
+		pp_key = PP_PREV;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+		if (p_mctl->pp_info.pp_key & pp_key)
+			*pp_divert_type = OUTPUT_TYPE_P;
+		if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_P)
+			*pp_type = OUTPUT_TYPE_P;
+		break;
+	case VFE_MSG_OUTPUT_S:
+		pp_key = PP_SNAP;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+		if (p_mctl->pp_info.pp_key & pp_key)
+			*pp_divert_type = OUTPUT_TYPE_S;
+		if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_S)
+			*pp_type = OUTPUT_TYPE_P;
+		break;
+	case VFE_MSG_OUTPUT_V:
+		if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_V)
+			*pp_type = OUTPUT_TYPE_V;
+		break;
+	case VFE_MSG_OUTPUT_T:
+		if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_T)
+			*pp_type = OUTPUT_TYPE_T;
+		break;
+	default:
+		break;
+	}
+	if (p_mctl->pp_info.div_frame[image_mode].ch_paddr[0])
+		*pp_divert_type = 0;
+	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+	D("%s: pp_type=%d, pp_divert_type = %d",
+		__func__, *pp_type, *pp_divert_type);
+	return rc;
+}
+
+int msm_mctl_do_pp_divert(
+	struct msm_cam_media_controller *p_mctl,
+	int msg_type, struct msm_free_buf *fbuf,
+	uint32_t frame_id, int pp_type)
+{
+	struct msm_cam_v4l2_dev_inst *pcam_inst;
+	int idx, rc = 0;
+	int del_buf = 0; /* delete from free queue */
+	struct msm_cam_evt_divert_frame div;
+	struct msm_frame_buffer *vb = NULL;
+	struct videobuf2_contig_pmem *mem;
+
+	idx = msm_mctl_out_type_to_inst_index(
+		p_mctl->sync.pcam_sync, msg_type);
+	pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx];
+	vb = msm_mctl_buf_find(p_mctl, pcam_inst,
+		  del_buf, msg_type, fbuf);
+	if (!vb)
+		return -EINVAL;
+	vb->vidbuf.v4l2_buf.sequence = frame_id;
+	mem = vb2_plane_cookie(&vb->vidbuf, 0);
+	div.image_mode = pcam_inst->image_mode;
+	div.op_mode    = pcam_inst->pcam->op_mode;
+	div.inst_idx   = pcam_inst->my_index;
+	div.node_idx   = pcam_inst->pcam->vnode_id;
+	div.phy_addr   =
+		videobuf2_to_pmem_contig(&vb->vidbuf, 0);
+	div.phy_offset = mem->addr_offset;
+	div.y_off      = 0;
+	div.cbcr_off   = mem->offset;
+	div.fd         = (int)mem->vaddr;
+	div.vb = (uint32_t)vb;
+	p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode]++;
+	if (p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode] == 0)
+		p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode]++;
+	div.frame_id   =
+		p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode];
+	div.path       = mem->buffer_type;
+	div.length     = mem->size;
+	msm_mctl_gettimeofday(&div.timestamp);
+	vb->vidbuf.v4l2_buf.timestamp = div.timestamp;
+	div.do_pp = pp_type;
+	if (!pp_type) {
+		p_mctl->pp_info.div_frame[pcam_inst->image_mode].ch_paddr[0] =
+			div.phy_addr;
+	}
+	rc = msm_mctl_pp_buf_divert(p_mctl, pcam_inst, &div);
+	return rc;
+}
+
+static int msm_mctl_pp_get_phy_addr(
+	uint32_t frame_handle,
+	struct msm_pp_frame *pp_frame)
+{
+	struct msm_frame_buffer *vb = NULL;
+	struct videobuf2_contig_pmem *mem;
+
+	vb = (struct msm_frame_buffer *)frame_handle;
+	mem = vb2_plane_cookie(&vb->vidbuf, 0);
+	memset(pp_frame, 0, sizeof(struct msm_pp_frame));
+	pp_frame->handle = (uint32_t)vb;
+	pp_frame->frame_id = vb->vidbuf.v4l2_buf.sequence;
+	pp_frame->image_type = (unsigned short)mem->buffer_type;
+	pp_frame->timestamp = vb->vidbuf.v4l2_buf.timestamp;
+	/* hard coded for now. Will need to expand to MP case */
+	pp_frame->num_planes = 1;
+	pp_frame->sp.addr_offset = mem->addr_offset;
+	pp_frame->sp.phy_addr = videobuf2_to_pmem_contig(&vb->vidbuf, 0);
+	pp_frame->sp.y_off = 0;
+	pp_frame->sp.cbcr_off = mem->offset;
+	pp_frame->sp.length = mem->size;
+	pp_frame->sp.fd = (int)mem->vaddr;
+	return 0;
+}
+
+static int msm_mctl_pp_copy_timestamp_and_frame_id(
+	uint32_t src_handle, uint32_t dest_handle)
+{
+	struct msm_frame_buffer *src_vb;
+	struct msm_frame_buffer *dest_vb;
+
+	src_vb = (struct msm_frame_buffer *)src_handle;
+	dest_vb = (struct msm_frame_buffer *)dest_handle;
+	dest_vb->vidbuf.v4l2_buf.timestamp =
+		src_vb->vidbuf.v4l2_buf.timestamp;
+	dest_vb->vidbuf.v4l2_buf.sequence =
+		src_vb->vidbuf.v4l2_buf.sequence;
+	D("%s: timestamp=%ld:%ld,frame_id=0x%x", __func__,
+		dest_vb->vidbuf.v4l2_buf.timestamp.tv_sec,
+		dest_vb->vidbuf.v4l2_buf.timestamp.tv_usec,
+		dest_vb->vidbuf.v4l2_buf.sequence);
+	return 0;
+}
+
+int msm_mctl_pp_proc_vpe_cmd(
+	struct msm_cam_media_controller *p_mctl,
+	struct msm_mctl_pp_cmd *pp_cmd)
+{
+	int rc = 0;
+	void __user *argp = (void __user *)pp_cmd->value;
+	switch (pp_cmd->id) {
+	case VPE_CMD_INIT:
+	case VPE_CMD_DEINIT:
+		rc = msm_isp_subdev_ioctl_vpe(
+			&p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		break;
+	case VPE_CMD_DISABLE:
+	case VPE_CMD_RESET:
+		rc = msm_isp_subdev_ioctl_vpe(
+			&p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		break;
+	case VPE_CMD_ENABLE: {
+		struct msm_vpe_clock_rate clk_rate;
+		if (sizeof(struct msm_vpe_clock_rate) !=
+			pp_cmd->length) {
+			D("%s: vpe cmd size mismatch "
+				"(id=%d, length = %d, expect size = %d",
+				__func__, pp_cmd->id, pp_cmd->length,
+				sizeof(struct msm_vpe_clock_rate));
+				rc = -EINVAL;
+				break;
+		}
+		if (copy_from_user(&clk_rate, pp_cmd->value,
+			sizeof(struct msm_vpe_clock_rate))) {
+			D("%s:clk_rate copy failed", __func__);
+			return -EFAULT;
+		}
+		pp_cmd->value = (void *)&clk_rate;
+		rc = msm_isp_subdev_ioctl_vpe(
+			&p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		pp_cmd->value = argp;
+		break;
+	}
+	case VPE_CMD_FLUSH: {
+		struct msm_vpe_flush_frame_buffer flush_buf;
+		if (sizeof(struct msm_vpe_flush_frame_buffer) !=
+			pp_cmd->length) {
+			D("%s: size mismatch(id=%d, len = %d, expected = %d",
+				__func__, pp_cmd->id, pp_cmd->length,
+				sizeof(struct msm_vpe_flush_frame_buffer));
+				rc = -EINVAL;
+				break;
+		}
+		if (copy_from_user(
+			&flush_buf, pp_cmd->value, sizeof(flush_buf)))
+			return -EFAULT;
+		pp_cmd->value = (void *)&flush_buf;
+		rc = msm_isp_subdev_ioctl_vpe(
+			&p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		if (rc == 0) {
+			if (copy_to_user((void *)argp,
+						&flush_buf,
+						sizeof(flush_buf))) {
+				ERR_COPY_TO_USER();
+				rc = -EFAULT;
+			}
+			pp_cmd->value = argp;
+		}
+	}
+	break;
+	case VPE_CMD_OPERATION_MODE_CFG: {
+		struct msm_vpe_op_mode_cfg op_mode_cfg;
+		if (sizeof(struct msm_vpe_op_mode_cfg) !=
+		pp_cmd->length) {
+			D("%s: size mismatch(id=%d, len = %d, expected = %d",
+				__func__, pp_cmd->id, pp_cmd->length,
+				sizeof(struct msm_vpe_op_mode_cfg));
+				rc = -EINVAL;
+				break;
+		}
+		if (copy_from_user(&op_mode_cfg,
+			pp_cmd->value,
+			sizeof(op_mode_cfg)))
+			return -EFAULT;
+		pp_cmd->value = (void *)&op_mode_cfg;
+		rc = msm_isp_subdev_ioctl_vpe(
+			&p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		break;
+	}
+	case VPE_CMD_INPUT_PLANE_CFG: {
+		struct msm_vpe_input_plane_cfg input_cfg;
+		if (sizeof(struct msm_vpe_input_plane_cfg) !=
+			pp_cmd->length) {
+			D("%s: mismatch(id=%d, len = %d, expected = %d",
+				__func__, pp_cmd->id, pp_cmd->length,
+				sizeof(struct msm_vpe_input_plane_cfg));
+				rc = -EINVAL;
+				break;
+		}
+		if (copy_from_user(
+			&input_cfg, pp_cmd->value, sizeof(input_cfg)))
+			return -EFAULT;
+		pp_cmd->value = (void *)&input_cfg;
+		rc = msm_isp_subdev_ioctl_vpe(
+			&p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		break;
+	}
+	case VPE_CMD_OUTPUT_PLANE_CFG: {
+		struct msm_vpe_output_plane_cfg output_cfg;
+		if (sizeof(struct msm_vpe_output_plane_cfg) !=
+			pp_cmd->length) {
+			D("%s: size mismatch(id=%d, len = %d, expected = %d",
+				__func__, pp_cmd->id, pp_cmd->length,
+				sizeof(struct msm_vpe_output_plane_cfg));
+				rc = -EINVAL;
+				break;
+		}
+		if (copy_from_user(&output_cfg, pp_cmd->value,
+			sizeof(output_cfg))) {
+			D("%s: cannot copy pp_cmd->value, size=%d",
+				__func__, pp_cmd->length);
+			return -EFAULT;
+		}
+		pp_cmd->value = (void *)&output_cfg;
+		rc = msm_isp_subdev_ioctl_vpe(
+			&p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		break;
+	}
+	case VPE_CMD_INPUT_PLANE_UPDATE: {
+		struct msm_vpe_input_plane_update_cfg input_update_cfg;
+		if (sizeof(struct msm_vpe_input_plane_update_cfg) !=
+			pp_cmd->length) {
+			D("%s: size mismatch(id=%d, len = %d, expected = %d",
+				__func__, pp_cmd->id, pp_cmd->length,
+				sizeof(struct msm_vpe_input_plane_update_cfg));
+				rc = -EINVAL;
+				break;
+		}
+		if (copy_from_user(&input_update_cfg, pp_cmd->value,
+			sizeof(input_update_cfg)))
+			return -EFAULT;
+		pp_cmd->value = (void *)&input_update_cfg;
+		rc = msm_isp_subdev_ioctl_vpe(
+			&p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		break;
+	}
+	case VPE_CMD_SCALE_CFG_TYPE: {
+		struct msm_vpe_scaler_cfg scaler_cfg;
+		if (sizeof(struct msm_vpe_scaler_cfg) !=
+			pp_cmd->length) {
+			D("%s: size mismatch(id=%d, len = %d, expected = %d",
+				__func__, pp_cmd->id, pp_cmd->length,
+				sizeof(struct msm_vpe_scaler_cfg));
+				rc = -EINVAL;
+				break;
+		}
+		if (copy_from_user(&scaler_cfg, pp_cmd->value,
+			sizeof(scaler_cfg)))
+			return -EFAULT;
+		pp_cmd->value = (void *)&scaler_cfg;
+		rc = msm_isp_subdev_ioctl_vpe(
+			&p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		break;
+	}
+	case VPE_CMD_ZOOM: {
+		struct msm_mctl_pp_frame_info *zoom;
+		zoom = kmalloc(sizeof(struct msm_mctl_pp_frame_info),
+					GFP_ATOMIC);
+		if (!zoom) {
+			rc = -ENOMEM;
+			break;
+		}
+		if (sizeof(zoom->pp_frame_cmd) != pp_cmd->length) {
+			D("%s: size mismatch(id=%d, len = %d, expected = %d",
+				__func__, pp_cmd->id, pp_cmd->length,
+				sizeof(zoom->pp_frame_cmd));
+				rc = -EINVAL;
+				kfree(zoom);
+				break;
+		}
+		if (copy_from_user(&zoom->pp_frame_cmd, pp_cmd->value,
+			sizeof(zoom->pp_frame_cmd))) {
+			kfree(zoom);
+			return -EFAULT;
+		}
+		D("%s: src=0x%x, dest=0x%x,cookie=0x%x,action=0x%x,path=0x%x",
+				__func__, zoom->pp_frame_cmd.src_buf_handle,
+				zoom->pp_frame_cmd.dest_buf_handle,
+				zoom->pp_frame_cmd.cookie,
+				zoom->pp_frame_cmd.vpe_output_action,
+				zoom->pp_frame_cmd.path);
+
+		zoom->user_cmd = pp_cmd->id;
+		rc = msm_mctl_pp_get_phy_addr(
+			zoom->pp_frame_cmd.src_buf_handle, &zoom->src_frame);
+		if (rc) {
+			kfree(zoom);
+			break;
+		}
+		rc = msm_mctl_pp_get_phy_addr(
+			zoom->pp_frame_cmd.dest_buf_handle, &zoom->dest_frame);
+		if (rc) {
+			kfree(zoom);
+			break;
+		}
+		rc = msm_mctl_pp_copy_timestamp_and_frame_id(
+			zoom->pp_frame_cmd.src_buf_handle,
+
+			zoom->pp_frame_cmd.dest_buf_handle);
+		if (rc) {
+			kfree(zoom);
+			break;
+		}
+		rc = msm_isp_subdev_ioctl_vpe(
+			&p_mctl->isp_sdev->sd_vpe, pp_cmd, (void *)zoom);
+		if (rc) {
+			kfree(zoom);
+			break;
+		}
+		break;
+	}
+	default:
+		rc = -1;
+		break;
+	}
+	return rc;
+}
+
+static int msm_mctl_pp_path_to_msg_type(int path)
+{
+	switch (path) {
+	case OUTPUT_TYPE_P:
+		return VFE_MSG_OUTPUT_P;
+	case OUTPUT_TYPE_V:
+		return VFE_MSG_OUTPUT_V;
+	case OUTPUT_TYPE_S:
+		return VFE_MSG_OUTPUT_S;
+	case OUTPUT_TYPE_T:
+	default:
+		return VFE_MSG_OUTPUT_T;
+	}
+}
+
+int msm_mctl_pp_proc_cmd(struct msm_cam_media_controller *p_mctl,
+			struct msm_mctl_pp_cmd *pp_cmd)
+{
+	int rc = 0;
+	struct msm_mctl_pp_frame_buffer pp_buffer;
+	struct msm_frame_buffer *buf = NULL;
+	void __user *argp = (void __user *)pp_cmd->value;
+	int msg_type = VFE_MSG_OUTPUT_V;
+	unsigned long flags;
+
+	switch (pp_cmd->id) {
+	case MCTL_CMD_GET_FRAME_BUFFER: {
+		if (copy_from_user(&pp_buffer, pp_cmd->value,
+				sizeof(pp_buffer)))
+			return -EFAULT;
+		msg_type = msm_mctl_pp_path_to_msg_type(pp_buffer.path);
+		buf = msm_mctl_get_free_buf(p_mctl, msg_type);
+		pp_buffer.buf_handle = (uint32_t)buf;
+		if (copy_to_user((void *)argp,
+			&pp_buffer,
+			sizeof(struct msm_mctl_pp_frame_buffer))) {
+			ERR_COPY_TO_USER();
+			rc = -EFAULT;
+		}
+		break;
+	}
+	case MCTL_CMD_PUT_FRAME_BUFFER: {
+		if (copy_from_user(&pp_buffer, pp_cmd->value,
+				sizeof(pp_buffer)))
+			return -EFAULT;
+		msg_type = msm_mctl_pp_path_to_msg_type(pp_buffer.path);
+			buf = (struct msm_frame_buffer *)pp_buffer.buf_handle;
+		msm_mctl_put_free_buf(p_mctl, msg_type, buf);
+		break;
+	}
+	case MCTL_CMD_DIVERT_FRAME_PP_PATH: {
+		struct msm_mctl_pp_divert_pp divert_pp;
+		if (copy_from_user(&divert_pp, pp_cmd->value,
+				sizeof(divert_pp)))
+			return -EFAULT;
+		D("%s: PP_PATH, path=%d",
+			   __func__, divert_pp.path);
+		spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
+		p_mctl->pp_info.pp_ctrl.pp_msg_type = divert_pp.path;
+		spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+		D("%s: pp path = %d", __func__,
+			   p_mctl->pp_info.pp_ctrl.pp_msg_type);
+		break;
+	}
+	case MCTL_CMD_DIVERT_FRAME_PP_DONE: {
+		struct msm_frame_buffer *buf = NULL;
+		if (copy_from_user(&pp_buffer, pp_cmd->value,
+				sizeof(pp_buffer)))
+			return -EFAULT;
+		buf = (struct msm_frame_buffer *)pp_buffer.buf_handle;
+		msg_type = msm_mctl_pp_path_to_msg_type(
+						pp_buffer.path);
+		if (msm_mctl_buf_del(p_mctl, msg_type, buf) == 0) {
+			vb2_buffer_done(&buf->vidbuf,
+				VB2_BUF_STATE_DONE);
+		}
+	}
+	break;
+	default:
+		rc = -EPERM;
+	break;
+	}
+	return rc;
+}
+
+
+int msm_mctl_pp_ioctl(struct msm_cam_media_controller *p_mctl,
+			unsigned int cmd, unsigned long arg)
+{
+	int rc = -EINVAL;
+	struct msm_mctl_post_proc_cmd pp_cmd;
+	void __user *argp = (void __user *)arg;
+
+	if (copy_from_user(&pp_cmd, argp, sizeof(pp_cmd)))
+		return -EFAULT;
+
+	switch (pp_cmd.type) {
+	case MSM_PP_CMD_TYPE_VPE:
+		rc = msm_mctl_pp_proc_vpe_cmd(p_mctl, &pp_cmd.cmd);
+		break;
+	case MSM_PP_CMD_TYPE_MCTL:
+		rc = msm_mctl_pp_proc_cmd(p_mctl, &pp_cmd.cmd);
+		break;
+	default:
+		rc = -EPERM;
+		break;
+	}
+	if (!rc) {
+		/* deep copy back the return value */
+		if (copy_to_user((void *)arg,
+			&pp_cmd,
+			sizeof(struct msm_mctl_post_proc_cmd))) {
+			ERR_COPY_TO_USER();
+			rc = -EFAULT;
+		}
+	}
+	return rc;
+}
+
+int msm_mctl_pp_notify(struct msm_cam_media_controller *p_mctl,
+			struct msm_mctl_pp_frame_info *pp_frame_info)
+{
+		struct msm_mctl_pp_frame_cmd *pp_frame_cmd;
+		pp_frame_cmd = &pp_frame_info->pp_frame_cmd;
+
+		D("%s: msm_cam_evt_divert_frame=%d",
+			__func__, sizeof(struct msm_mctl_pp_event_info));
+		if ((MSM_MCTL_PP_VPE_FRAME_TO_APP &
+			pp_frame_cmd->vpe_output_action)) {
+			struct msm_free_buf done_frame;
+			int msg_type =
+				msm_mctl_pp_path_to_msg_type(
+					pp_frame_cmd->path);
+
+			done_frame.ch_paddr[0] =
+				pp_frame_info->dest_frame.sp.phy_addr;
+			done_frame.vb =
+				pp_frame_info->dest_frame.handle;
+			msm_mctl_buf_done_pp(
+				p_mctl, msg_type, &done_frame, 0);
+			pr_err("%s: vpe done to app, vb=0x%x, path=%d, phy=0x%x",
+				__func__, done_frame.vb,
+				pp_frame_cmd->path, done_frame.ch_paddr[0]);
+		}
+		if ((MSM_MCTL_PP_VPE_FRAME_ACK &
+			pp_frame_cmd->vpe_output_action)) {
+			struct v4l2_event v4l2_evt;
+			struct msm_mctl_pp_event_info *pp_event_info;
+			memset(&v4l2_evt, 0, sizeof(v4l2_evt));
+			pp_event_info =
+				(struct msm_mctl_pp_event_info *)v4l2_evt.
+					u.data;
+			pp_event_info->event = MCTL_PP_EVENT_CMD_ACK;
+			pp_event_info->ack.cmd = pp_frame_info->user_cmd;
+			pp_event_info->ack.status = 0;
+			pp_event_info->ack.cookie = pp_frame_cmd->cookie;
+			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+						MSM_CAM_RESP_MCTL_PP_EVENT;
+			v4l2_event_queue(
+				p_mctl->config_device->
+					config_stat_event_queue.pvdev,
+				&v4l2_evt);
+			pr_err("%s: ack to daemon, cookie=0x%x, event = 0x%x",
+				__func__, pp_frame_info->pp_frame_cmd.cookie,
+				v4l2_evt.type);
+		}
+		kfree(pp_frame_info); /* free mem */
+		return 0;
+}
+
+int msm_mctl_pp_reserve_free_frame(
+	struct msm_cam_media_controller *p_mctl,
+	void __user *arg)
+{
+	struct msm_cam_evt_divert_frame frame;
+	int msg_type, image_mode, rc = 0;
+	struct msm_free_buf free_buf;
+	memset(&free_buf, 0, sizeof(struct msm_free_buf));
+	if (copy_from_user(&frame, arg,
+		sizeof(struct msm_cam_evt_divert_frame)))
+		return -EFAULT;
+	switch (frame.path) {
+	case OUTPUT_TYPE_P:
+		msg_type = VFE_MSG_OUTPUT_P;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+		break;
+	case OUTPUT_TYPE_S:
+		msg_type = VFE_MSG_OUTPUT_S;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+		break;
+	case OUTPUT_TYPE_V:
+		msg_type = VFE_MSG_OUTPUT_V;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
+		break;
+	case OUTPUT_TYPE_T:
+	default:
+		rc = -EFAULT;
+		return rc;
+	}
+	rc = msm_mctl_reserve_free_buf(p_mctl, msg_type, &free_buf);
+	if (rc == 0) {
+		frame.phy_addr = free_buf.ch_paddr[0];
+		frame.vb = free_buf.vb;
+		if (copy_to_user((void *)arg,
+				&frame,
+				sizeof(frame))) {
+			ERR_COPY_TO_USER();
+			rc = -EFAULT;
+		}
+	}
+	D("%s: reserve free buf, rc = %d, phy = 0x%x",
+		__func__, rc, free_buf.ch_paddr[0]);
+	return rc;
+}
+
+int msm_mctl_pp_release_free_frame(
+	struct msm_cam_media_controller *p_mctl,
+	void __user *arg)
+{
+	struct msm_cam_evt_divert_frame frame;
+	int msg_type, image_mode, rc = 0;
+	struct msm_free_buf free_buf;
+
+	if (copy_from_user(&frame, arg,
+		sizeof(struct msm_cam_evt_divert_frame)))
+		return -EFAULT;
+	switch (frame.path) {
+	case OUTPUT_TYPE_P:
+		msg_type = VFE_MSG_OUTPUT_P;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+		break;
+	case OUTPUT_TYPE_S:
+		msg_type = VFE_MSG_OUTPUT_S;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+		break;
+	case OUTPUT_TYPE_V:
+		msg_type = VFE_MSG_OUTPUT_V;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
+		break;
+	case OUTPUT_TYPE_T:
+	default:
+		rc = -EFAULT;
+		return rc;
+	}
+	free_buf.ch_paddr[0] = frame.phy_addr;
+	rc = msm_mctl_release_free_buf(p_mctl, msg_type, &free_buf);
+	D("%s: release free buf, rc = %d, phy = 0x%x",
+		__func__, rc, free_buf.ch_paddr[0]);
+
+	return rc;
+}
+
+int msm_mctl_set_pp_key(struct msm_cam_media_controller *p_mctl,
+				void __user *arg)
+{
+	int rc = 0;
+	unsigned long flags;
+	spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
+	if (copy_from_user(&p_mctl->pp_info.pp_key,
+			arg, sizeof(p_mctl->pp_info.pp_key)))
+		rc = -EFAULT;
+	else
+		D("%s: mctl=0x%p, pp_key_setting=0x%x",
+			__func__, p_mctl, p_mctl->pp_info.pp_key);
+	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+	return rc;
+}
+
+int msm_mctl_pp_done(
+	struct msm_cam_media_controller *p_mctl,
+	void __user *arg)
+{
+	struct msm_frame frame;
+	int msg_type, image_mode, rc = 0;
+	int dirty = 0;
+	struct msm_free_buf buf;
+	unsigned long flags;
+
+	if (copy_from_user(&frame, arg, sizeof(frame)))
+		return -EFAULT;
+	spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
+	switch (frame.path) {
+	case OUTPUT_TYPE_P:
+		msg_type = VFE_MSG_OUTPUT_P;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+		break;
+	case OUTPUT_TYPE_S:
+		msg_type = VFE_MSG_OUTPUT_S;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+		break;
+	case OUTPUT_TYPE_V:
+		msg_type = VFE_MSG_OUTPUT_V;
+		image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
+		break;
+	case OUTPUT_TYPE_T:
+	default:
+		rc = -EFAULT;
+		goto err;
+	}
+	if (p_mctl->pp_info.div_frame[image_mode].ch_paddr[0]) {
+		memcpy(&buf,
+			&p_mctl->pp_info.div_frame[image_mode],
+			sizeof(buf));
+		memset(&p_mctl->pp_info.div_frame[image_mode],
+			0, sizeof(buf));
+		if (p_mctl->pp_info.cur_frame_id[image_mode] !=
+					  frame.frame_id) {
+			/* dirty frame. should not pass to app */
+			dirty = 1;
+		}
+	} else
+		buf.ch_paddr[0] = frame.buffer;
+	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+	/* here buf.addr is phy_addr */
+	rc = msm_mctl_buf_done_pp(p_mctl, msg_type, &buf, dirty);
+	return rc;
+err:
+	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+	return rc;
+}
+
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index a6915ff..81362d1 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -23,7 +23,6 @@
 
 #include "msm.h"
 #include "msm_vfe32.h"
-#include "msm_vpe1.h"
 #include "msm_ispif.h"
 
 atomic_t irq_cnt;
@@ -2015,13 +2014,6 @@
 				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out2.ch1]);
 		}
 		vfe32_ctrl->recording_state = VFE_REC_STATE_STARTED;
-		if (vpe_ctrl && vpe_ctrl->dis_en) {
-			old_val = msm_io_r(
-				vfe32_ctrl->vfebase + VFE_MODULE_CFG);
-			old_val |= RS_CS_ENABLE_MASK;
-			msm_io_w(old_val,
-				vfe32_ctrl->vfebase + VFE_MODULE_CFG);
-		}
 		msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 		CDBG("start video triggered .\n");
 	} else if (vfe32_ctrl->recording_state ==
@@ -3372,12 +3364,4 @@
 	vfe_syncdata = NULL;
 }
 
-void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data)
-{
-	fptr->vpe_reg		= msm_vpe_reg;
-	fptr->send_frame_to_vpe	= msm_send_frame_to_vpe;
-	fptr->vpe_config	= msm_vpe_config;
-	fptr->vpe_cfg_update	= msm_vpe_cfg_update;
-	fptr->dis		= &(vpe_ctrl->dis_en);
-	vpe_ctrl->syncdata = data;
-}
+
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 5cd3d78..c59918d 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -16,44 +16,29 @@
 #include <mach/irqs.h>
 #include <linux/io.h>
 #include <linux/slab.h>
-#include "msm_vpe.h"
 #include <linux/pm_qos_params.h>
 #include <linux/clk.h>
 #include <mach/clk.h>
 #include <asm/div64.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include "msm.h"
+#include "msm_vpe.h"
 
 static int vpe_enable(uint32_t);
 static int vpe_disable(void);
-static int vpe_update_scaler(struct video_crop_t *pcrop);
-static struct vpe_device_type  vpe_device_data;
-static struct vpe_device_type  *vpe_device;
-struct vpe_ctrl_type    *vpe_ctrl;
-static const char *vpe_general_cmd[] = {
-	"VPE_DUMMY_0",  /* 0 */
-	"VPE_SET_CLK",
-	"VPE_RESET",
-	"VPE_START",
-	"VPE_ABORT",
-	"VPE_OPERATION_MODE_CFG",  /* 5 */
-	"VPE_INPUT_PLANE_CFG",
-	"VPE_OUTPUT_PLANE_CFG",
-	"VPE_INPUT_PLANE_UPDATE",
-	"VPE_SCALE_CFG_TYPE",
-	"VPE_ROTATION_CFG_TYPE",  /* 10 */
-	"VPE_AXI_OUT_CFG",
-	"VPE_CMD_DIS_OFFSET_CFG",
-	"VPE_ENABLE",
-	"VPE_DISABLE",
-};
-static uint32_t orig_src_y, orig_src_cbcr;
+static int vpe_update_scaler(struct msm_pp_crop *pcrop);
+static struct vpe_device_type *vpe_device;
+struct vpe_ctrl_type *vpe_ctrl;
+static void *vpe_syncdata;
+static atomic_t vpe_init_done = ATOMIC_INIT(0);
 
-#define CHECKED_COPY_FROM_USER(in) {					\
-	if (copy_from_user((in), (void __user *)cmd->value,		\
-			cmd->length)) {					\
-		rc = -EFAULT;						\
-		break;							\
-	}								\
-}
+static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd,
+	struct msm_mctl_pp_frame_info *pp_frame_info);
 
 static long long vpe_do_div(long long num, long long den)
 {
@@ -64,11 +49,15 @@
 static int vpe_start(void)
 {
 	/*  enable the frame irq, bit 0 = Display list 0 ROI done */
-	msm_io_w(1, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
+	msm_io_w_mb(1, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
+	msm_io_dump(vpe_device->vpebase, 0x120);
 	msm_io_dump(vpe_device->vpebase + 0x10000, 0x250);
+	msm_io_dump(vpe_device->vpebase + 0x30000, 0x20);
+	msm_io_dump(vpe_device->vpebase + 0x50000, 0x30);
+	msm_io_dump(vpe_device->vpebase + 0x50400, 0x10);
 	/* this triggers the operation. */
 	msm_io_w(1, vpe_device->vpebase + VPE_DL0_START_OFFSET);
-
+	wmb();
 	return 0;
 }
 
@@ -77,21 +66,15 @@
 	/* initialize local variables for state control, etc.*/
 	vpe_ctrl->op_mode = 0;
 	vpe_ctrl->state = VPE_STATE_INIT;
-	spin_lock_init(&vpe_ctrl->tasklet_lock);
-	spin_lock_init(&vpe_ctrl->state_lock);
-	INIT_LIST_HEAD(&vpe_ctrl->tasklet_q);
 }
 
 static void vpe_config_axi_default(void)
 {
 	msm_io_w(0x25, vpe_device->vpebase + VPE_AXI_ARB_2_OFFSET);
-
 	CDBG("%s: yaddr %ld cbcraddr %ld", __func__,
 		 vpe_ctrl->out_y_addr, vpe_ctrl->out_cbcr_addr);
-
 	if (!vpe_ctrl->out_y_addr || !vpe_ctrl->out_cbcr_addr)
 		return;
-
 	msm_io_w(vpe_ctrl->out_y_addr,
 		vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
 	/* for video  CbCr address */
@@ -103,20 +86,17 @@
 static int vpe_reset(void)
 {
 	uint32_t vpe_version;
-	uint32_t rc;
+	uint32_t rc = 0;
 
 	vpe_reset_state_variables();
 	vpe_version = msm_io_r(vpe_device->vpebase + VPE_HW_VERSION_OFFSET);
 	CDBG("vpe_version = 0x%x\n", vpe_version);
-
 	/* disable all interrupts.*/
 	msm_io_w(0, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
 	/* clear all pending interrupts*/
 	msm_io_w(0x1fffff, vpe_device->vpebase + VPE_INTR_CLEAR_OFFSET);
-
 	/* write sw_reset to reset the core. */
 	msm_io_w(0x10, vpe_device->vpebase + VPE_SW_RESET_OFFSET);
-
 	/* then poll the reset bit, it should be self-cleared. */
 	while (1) {
 		rc =
@@ -124,7 +104,6 @@
 		if (rc == 0)
 			break;
 	}
-
 	/*  at this point, hardware is reset. Then pogram to default
 		values. */
 	msm_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE,
@@ -132,31 +111,27 @@
 
 	msm_io_w(VPE_CGC_ENABLE_VALUE,
 			vpe_device->vpebase + VPE_CGC_EN_OFFSET);
-
 	msm_io_w(1, vpe_device->vpebase + VPE_CMD_MODE_OFFSET);
-
 	msm_io_w(VPE_DEFAULT_OP_MODE_VALUE,
 			vpe_device->vpebase + VPE_OP_MODE_OFFSET);
-
 	msm_io_w(VPE_DEFAULT_SCALE_CONFIG,
 			vpe_device->vpebase + VPE_SCALE_CONFIG_OFFSET);
-
 	vpe_config_axi_default();
-	return 0;
+	return rc;
 }
 
-int msm_vpe_cfg_update(void *pinfo)
+static int msm_vpe_cfg_update(void *pinfo)
 {
 	uint32_t  rot_flag, rc = 0;
-	struct video_crop_t *pcrop = (struct video_crop_t *)pinfo;
+	struct msm_pp_crop *pcrop = (struct msm_pp_crop *)pinfo;
 
 	rot_flag = msm_io_r(vpe_device->vpebase +
 						VPE_OP_MODE_OFFSET) & 0xE00;
 	if (pinfo != NULL) {
-		CDBG("Crop info in2_w = %d, in2_h = %d "
-			"out2_h = %d out2_w = %d\n", pcrop->in2_w,
-			pcrop->in2_h,
-			pcrop->out2_h, pcrop->out2_w);
+		pr_err("%s: Crop info in2_w = %d, in2_h = %d "
+			"out2_w = %d out2_h = %d\n",
+			__func__, pcrop->src_w, pcrop->src_h,
+			pcrop->dst_w, pcrop->dst_h);
 		rc = vpe_update_scaler(pcrop);
 	}
 	CDBG("return rc = %d rot_flag = %d\n", rc, rot_flag);
@@ -184,6 +159,7 @@
 	msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_SIZE_OFFSET);
 	vpe_ctrl->in_h_w = *p;
 	msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_XY_OFFSET);
+	CDBG("%s: in_h_w=0x%x", __func__, vpe_ctrl->in_h_w);
 }
 
 void vpe_output_plane_config(uint32_t *p)
@@ -204,7 +180,6 @@
 	temp = msm_io_r(vpe_device->vpebase + VPE_OUT_SIZE_OFFSET);
 	w = temp & 0xFFF;
 	h = (temp & 0xFFF0000) >> 16;
-
 	if (*p++ & 0xE00) {
 		/* rotation enabled. */
 		vpe_ctrl->out_w = h;
@@ -214,6 +189,8 @@
 		vpe_ctrl->out_h = h;
 	}
 	vpe_ctrl->dis_en = *p;
+	CDBG("%s: out_w=%d, out_h=%d, dis_en=%d",
+		__func__, vpe_ctrl->out_w, vpe_ctrl->out_h, vpe_ctrl->dis_en);
 	return 0;
 }
 
@@ -221,7 +198,7 @@
 *  rotation is enabled, simply swap the destination dimension.
 *  And then pass the already swapped output size to this
 *  function. */
-static int vpe_update_scaler(struct video_crop_t *pcrop)
+static int vpe_update_scaler(struct msm_pp_crop *pcrop)
 {
 	uint32_t out_ROI_width, out_ROI_height;
 	uint32_t src_ROI_width, src_ROI_height;
@@ -240,9 +217,8 @@
 	uint32_t yscale_filter_sel, xscale_filter_sel;
 	uint32_t scale_unit_sel_x, scale_unit_sel_y;
 	uint64_t numerator, denominator;
-
-	if ((pcrop->in2_w >= pcrop->out2_w) &&
-		(pcrop->in2_h >= pcrop->out2_h)) {
+	if ((pcrop->src_w >= pcrop->dst_w) &&
+		(pcrop->src_h >= pcrop->dst_h)) {
 		CDBG(" =======VPE no zoom needed.\n");
 
 		temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET)
@@ -267,10 +243,10 @@
 		msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) | 0x3;
 	msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
 
-	src_ROI_width = pcrop->in2_w;
-	src_ROI_height = pcrop->in2_h;
-	out_ROI_width = pcrop->out2_w;
-	out_ROI_height = pcrop->out2_h;
+	src_ROI_width = pcrop->src_w;
+	src_ROI_height = pcrop->src_h;
+	out_ROI_width = pcrop->dst_w;
+	out_ROI_height = pcrop->dst_h;
 
 	CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n",
 		src_ROI_width, src_ROI_height, out_ROI_width,
@@ -279,8 +255,8 @@
 
 	msm_io_w(src_roi, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET);
 
-	src_x = (out_ROI_width - src_ROI_width)/2;
-	src_y = (out_ROI_height - src_ROI_height)/2;
+	src_x = pcrop->src_x;
+	src_y = pcrop->src_y;
 
 	CDBG("src_x = %d, src_y=%d.\n", src_x, src_y);
 
@@ -439,868 +415,118 @@
 	return 1;
 }
 
-static int vpe_update_scaler_with_dis(struct video_crop_t *pcrop,
-				struct dis_offset_type *dis_offset)
+static inline void vpe_get_zoom_dis_xy(
+		struct dis_offset_type *dis_offset,
+		struct msm_pp_crop *pcrop,
+		int32_t  *zoom_dis_x,
+		int32_t *zoom_dis_y)
 {
-	uint32_t out_ROI_width, out_ROI_height;
-	uint32_t src_ROI_width, src_ROI_height;
-
-	uint32_t rc = 0;  /* default to no zoom. */
-	/*
-	* phase_step_x, phase_step_y, phase_init_x and phase_init_y
-	* are represented in fixed-point, unsigned 3.29 format
-	*/
-	uint32_t phase_step_x = 0;
-	uint32_t phase_step_y = 0;
-	uint32_t phase_init_x = 0;
-	uint32_t phase_init_y = 0;
-
-	uint32_t src_roi, temp;
-	int32_t  src_x, src_y, src_xy;
-	uint32_t yscale_filter_sel, xscale_filter_sel;
-	uint32_t scale_unit_sel_x, scale_unit_sel_y;
-	uint64_t numerator, denominator;
-	int32_t  zoom_dis_x, zoom_dis_y;
-
-	CDBG("%s: pcrop->in2_w = %d, pcrop->in2_h = %d\n", __func__,
-		 pcrop->in2_w, pcrop->in2_h);
-	CDBG("%s: pcrop->out2_w = %d, pcrop->out2_h = %d\n", __func__,
-		 pcrop->out2_w, pcrop->out2_h);
-
-	if ((pcrop->in2_w >= pcrop->out2_w) &&
-		(pcrop->in2_h >= pcrop->out2_h)) {
-		CDBG(" =======VPE no zoom needed, DIS is still enabled.\n");
-
-		temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET)
-		& 0xfffffffc;
-		msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
-
-		/* no zoom, use dis offset directly. */
-		src_xy = dis_offset->dis_offset_y * (1<<16) +
-			dis_offset->dis_offset_x;
-
-		msm_io_w(src_xy, vpe_device->vpebase + VPE_SRC_XY_OFFSET);
-
-		CDBG("vpe_ctrl->in_h_w = 0x%x\n", vpe_ctrl->in_h_w);
-		msm_io_w(vpe_ctrl->in_h_w, vpe_device->vpebase +
-				 VPE_SRC_SIZE_OFFSET);
-		return rc;
-	}
-	/* If fall through then scaler is needed.*/
-
-	CDBG("========VPE zoom needed + DIS enabled.\n");
-	/* assumption is both direction need zoom. this can be
-	 improved. */
-	temp = msm_io_r(vpe_device->vpebase +
-					VPE_OP_MODE_OFFSET) | 0x3;
-	msm_io_w(temp, vpe_device->vpebase +
-			VPE_OP_MODE_OFFSET);
-	zoom_dis_x = dis_offset->dis_offset_x *
-		pcrop->in2_w / pcrop->out2_w;
-	zoom_dis_y = dis_offset->dis_offset_y *
-		pcrop->in2_h / pcrop->out2_h;
-
-	src_x = zoom_dis_x + (pcrop->out2_w-pcrop->in2_w)/2;
-	src_y = zoom_dis_y + (pcrop->out2_h-pcrop->in2_h)/2;
-
-	out_ROI_width = vpe_ctrl->out_w;
-	out_ROI_height = vpe_ctrl->out_h;
-
-	src_ROI_width = out_ROI_width * pcrop->in2_w / pcrop->out2_w;
-	src_ROI_height = out_ROI_height * pcrop->in2_h / pcrop->out2_h;
-
-	/* clamp to output size.  This is because along
-	processing, we mostly do truncation, therefore
-	dis_offset tends to be
-	smaller values.  The intention was to make sure that the
-	offset does not exceed margin.   But in the case it could
-	result src_roi bigger, due to subtract a smaller value. */
-	CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n",
-		src_ROI_width, src_ROI_height, out_ROI_width,
-		out_ROI_height);
-
-	src_roi = (src_ROI_height << 16) + src_ROI_width;
-
-	msm_io_w(src_roi, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET);
-
-	CDBG("src_x = %d, src_y=%d.\n", src_x, src_y);
-
-	src_xy = src_y*(1<<16) + src_x;
-	msm_io_w(src_xy, vpe_device->vpebase +
-			VPE_SRC_XY_OFFSET);
-	CDBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi);
-
-	/* decide whether to use FIR or M/N for scaling */
-	if ((out_ROI_width == 1 && src_ROI_width < 4) ||
-		(src_ROI_width < 4 * out_ROI_width - 3))
-		scale_unit_sel_x = 0;/* use FIR scalar */
-	else
-		scale_unit_sel_x = 1;/* use M/N scalar */
-
-	if ((out_ROI_height == 1 && src_ROI_height < 4) ||
-		(src_ROI_height < 4 * out_ROI_height - 3))
-		scale_unit_sel_y = 0;/* use FIR scalar */
-	else
-		scale_unit_sel_y = 1;/* use M/N scalar */
-	/* calculate phase step for the x direction */
-
-	/* if destination is only 1 pixel wide, the value of
-	phase_step_x is unimportant. Assigning phase_step_x
-	to src ROI width as an arbitrary value. */
-	if (out_ROI_width == 1)
-		phase_step_x = (uint32_t) ((src_ROI_width) <<
-							SCALER_PHASE_BITS);
-	else if (scale_unit_sel_x == 0) { /* if using FIR scalar */
-		/* Calculate the quotient ( src_ROI_width - 1 )
-		/ ( out_ROI_width - 1)with u3.29 precision.
-		Quotient is rounded up to the larger
-		29th decimal point. */
-		numerator =
-			(uint64_t)(src_ROI_width - 1) <<
-			SCALER_PHASE_BITS;
-		/* never equals to 0 because of the "
-		(out_ROI_width == 1 )"*/
-		denominator = (uint64_t)(out_ROI_width - 1);
-		/* divide and round up to the larger 29th
-		decimal point. */
-		phase_step_x = (uint32_t) vpe_do_div(
-			(numerator + denominator - 1), denominator);
-	} else if (scale_unit_sel_x == 1) { /* if M/N scalar */
-		/* Calculate the quotient
-		( src_ROI_width ) / ( out_ROI_width)
-		with u3.29 precision. Quotient is rounded
-		down to the smaller 29th decimal point. */
-		numerator = (uint64_t)(src_ROI_width) <<
-			SCALER_PHASE_BITS;
-		denominator = (uint64_t)(out_ROI_width);
-		phase_step_x =
-			(uint32_t) vpe_do_div(numerator, denominator);
-	}
-	/* calculate phase step for the y direction */
-
-	/* if destination is only 1 pixel wide, the value of
-		phase_step_x is unimportant. Assigning phase_step_x
-		to src ROI width as an arbitrary value. */
-	if (out_ROI_height == 1)
-		phase_step_y =
-		(uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS);
-	else if (scale_unit_sel_y == 0) { /* if FIR scalar */
-		/* Calculate the quotient
-		( src_ROI_height - 1 ) / ( out_ROI_height - 1)
-		with u3.29 precision. Quotient is rounded up to the
-		larger 29th decimal point. */
-		numerator = (uint64_t)(src_ROI_height - 1) <<
-			SCALER_PHASE_BITS;
-		/* never equals to 0 because of the
-		"( out_ROI_height == 1 )" case */
-		denominator = (uint64_t)(out_ROI_height - 1);
-		/* Quotient is rounded up to the larger 29th
-		decimal point. */
-		phase_step_y =
-		(uint32_t) vpe_do_div(
-		(numerator + denominator - 1), denominator);
-	} else if (scale_unit_sel_y == 1) { /* if M/N scalar */
-		/* Calculate the quotient ( src_ROI_height ) / ( out_ROI_height)
-		with u3.29 precision. Quotient is rounded down to the smaller
-		29th decimal point. */
-		numerator = (uint64_t)(src_ROI_height) <<
-			SCALER_PHASE_BITS;
-		denominator = (uint64_t)(out_ROI_height);
-		phase_step_y = (uint32_t) vpe_do_div(
-			numerator, denominator);
-	}
-
-	/* decide which set of FIR coefficients to use */
-	if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
-		xscale_filter_sel = 0;
-	else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
-		xscale_filter_sel = 1;
-	else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
-		xscale_filter_sel = 2;
-	else
-		xscale_filter_sel = 3;
-
-	if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
-		yscale_filter_sel = 0;
-	else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
-		yscale_filter_sel = 1;
-	else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
-		yscale_filter_sel = 2;
-	else
-		yscale_filter_sel = 3;
-
-	/* calculate phase init for the x direction */
-
-	/* if using FIR scalar */
-	if (scale_unit_sel_x == 0) {
-		if (out_ROI_width == 1)
-			phase_init_x =
-			(uint32_t) ((src_ROI_width - 1) <<
-						SCALER_PHASE_BITS);
-		else
-			phase_init_x = 0;
-
-	} else if (scale_unit_sel_x == 1) /* M over N scalar  */
-		phase_init_x = 0;
-
-	/* calculate phase init for the y direction
-	if using FIR scalar */
-	if (scale_unit_sel_y == 0) {
-		if (out_ROI_height == 1)
-			phase_init_y =
-			(uint32_t) ((src_ROI_height -
-						1) << SCALER_PHASE_BITS);
-		else
-			phase_init_y = 0;
-
-	} else if (scale_unit_sel_y == 1) /* M over N scalar   */
-		phase_init_y = 0;
-
-	CDBG("phase step x = %d, step y = %d.\n",
-		phase_step_x, phase_step_y);
-	CDBG("phase init x = %d, init y = %d.\n",
-		phase_init_x, phase_init_y);
-
-	msm_io_w(phase_step_x, vpe_device->vpebase +
-			VPE_SCALE_PHASEX_STEP_OFFSET);
-
-	msm_io_w(phase_step_y, vpe_device->vpebase +
-			VPE_SCALE_PHASEY_STEP_OFFSET);
-
-	msm_io_w(phase_init_x, vpe_device->vpebase +
-			VPE_SCALE_PHASEX_INIT_OFFSET);
-
-	msm_io_w(phase_init_y, vpe_device->vpebase +
-			VPE_SCALE_PHASEY_INIT_OFFSET);
-
-	return 1;
+	*zoom_dis_x = dis_offset->dis_offset_x *
+	pcrop->src_w / pcrop->dst_w;
+	*zoom_dis_y = dis_offset->dis_offset_y *
+	pcrop->src_h / pcrop->dst_h;
 }
 
-void msm_send_frame_to_vpe(uint32_t pyaddr, uint32_t pcbcraddr,
-		struct timespec *ts, int output_type)
+int msm_vpe_is_busy(void)
 {
-	uint32_t temp_pyaddr = 0, temp_pcbcraddr = 0;
-
-	CDBG("vpe input, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
-		pyaddr, pcbcraddr);
-	msm_io_w(pyaddr, vpe_device->vpebase + VPE_SRCP0_ADDR_OFFSET);
-	msm_io_w(pcbcraddr, vpe_device->vpebase + VPE_SRCP1_ADDR_OFFSET);
-
+	int busy = 0;
+	unsigned long flags;
+	spin_lock_irqsave(&vpe_ctrl->lock, flags);
 	if (vpe_ctrl->state == VPE_STATE_ACTIVE)
-		CDBG(" =====VPE is busy!!!  Wrong!========\n");
+		busy = 1;
+	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+	return busy;
+}
+static int msm_send_frame_to_vpe(void)
+{
+	int rc = 0;
+	unsigned long flags;
 
-	if (output_type != OUTPUT_TYPE_ST_R)
-		vpe_ctrl->ts = *ts;
-
-	if (output_type == OUTPUT_TYPE_ST_L) {
-		vpe_ctrl->pcbcr_before_dis = msm_io_r(vpe_device->vpebase +
-			VPE_OUTP1_ADDR_OFFSET);
-		temp_pyaddr = msm_io_r(vpe_device->vpebase +
-			VPE_OUTP0_ADDR_OFFSET);
-		temp_pcbcraddr = temp_pyaddr + PAD_TO_2K(vpe_ctrl->out_w *
-			vpe_ctrl->out_h * 2, vpe_ctrl->pad_2k_bool);
-		msm_io_w(temp_pcbcraddr, vpe_device->vpebase +
-			VPE_OUTP1_ADDR_OFFSET);
-	}
-
-	if (vpe_ctrl->dis_en) {
-		/* Changing the VPE output CBCR address,
-		to make Y/CBCR continuous */
-		vpe_ctrl->pcbcr_before_dis = msm_io_r(vpe_device->vpebase +
-			VPE_OUTP1_ADDR_OFFSET);
-		temp_pyaddr = msm_io_r(vpe_device->vpebase +
-			VPE_OUTP0_ADDR_OFFSET);
-		temp_pcbcraddr = temp_pyaddr + vpe_ctrl->pcbcr_dis_offset;
-		msm_io_w(temp_pcbcraddr, vpe_device->vpebase +
-			VPE_OUTP1_ADDR_OFFSET);
-	}
-
-	vpe_ctrl->output_type = output_type;
+	spin_lock_irqsave(&vpe_ctrl->lock, flags);
+	msm_io_w((vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
+			  vpe_ctrl->pp_frame_info->src_frame.sp.y_off),
+			vpe_device->vpebase + VPE_SRCP0_ADDR_OFFSET);
+	msm_io_w((vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
+			  vpe_ctrl->pp_frame_info->src_frame.sp.cbcr_off),
+			vpe_device->vpebase + VPE_SRCP1_ADDR_OFFSET);
+	msm_io_w((vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
+			  vpe_ctrl->pp_frame_info->dest_frame.sp.y_off),
+			vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
+	msm_io_w((vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
+			  vpe_ctrl->pp_frame_info->dest_frame.sp.cbcr_off),
+			vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET);
 	vpe_ctrl->state = VPE_STATE_ACTIVE;
+	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
 	vpe_start();
-}
-
-static int vpe_proc_general(struct msm_vpe_cmd *cmd)
-{
-	int rc = 0;
-	uint32_t *cmdp = NULL;
-	struct msm_queue_cmd *qcmd = NULL;
-	struct msm_vpe_buf_info *vpe_buf;
-	int turbo_mode = 0;
-	struct msm_sync *sync = (struct msm_sync *)vpe_ctrl->syncdata;
-	CDBG("vpe_proc_general: cmdID = %s, length = %d\n",
-		vpe_general_cmd[cmd->id], cmd->length);
-	switch (cmd->id) {
-	case VPE_ENABLE:
-		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
-		if (!cmdp) {
-			rc = -ENOMEM;
-			goto vpe_proc_general_done;
-		}
-		if (copy_from_user(cmdp,
-			(void __user *)(cmd->value),
-			cmd->length)) {
-			rc = -EFAULT;
-			goto vpe_proc_general_done;
-		}
-		turbo_mode = *((int *)(cmd->value));
-		rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE)
-			: vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
-		break;
-	case VPE_DISABLE:
-		rc = vpe_disable();
-		break;
-	case VPE_RESET:
-	case VPE_ABORT:
-		rc = vpe_reset();
-		break;
-	case VPE_START:
-		rc = vpe_start();
-		break;
-
-	case VPE_INPUT_PLANE_CFG:
-		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
-		if (!cmdp) {
-			rc = -ENOMEM;
-			goto vpe_proc_general_done;
-		}
-		if (copy_from_user(cmdp,
-			(void __user *)(cmd->value),
-			cmd->length)) {
-			rc = -EFAULT;
-			goto vpe_proc_general_done;
-		}
-		vpe_input_plane_config(cmdp);
-		break;
-
-	case VPE_OPERATION_MODE_CFG:
-		CDBG("cmd->length = %d\n", cmd->length);
-		if (cmd->length != VPE_OPERATION_MODE_CFG_LEN) {
-			rc = -EINVAL;
-			goto vpe_proc_general_done;
-		}
-		cmdp = kmalloc(VPE_OPERATION_MODE_CFG_LEN,
-					GFP_ATOMIC);
-		if (copy_from_user(cmdp,
-			(void __user *)(cmd->value),
-			VPE_OPERATION_MODE_CFG_LEN)) {
-			rc = -EFAULT;
-			goto vpe_proc_general_done;
-		}
-		rc = vpe_operation_config(cmdp);
-		CDBG("rc = %d\n", rc);
-		break;
-
-	case VPE_OUTPUT_PLANE_CFG:
-		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
-		if (!cmdp) {
-			rc = -ENOMEM;
-			goto vpe_proc_general_done;
-		}
-		if (copy_from_user(cmdp,
-			(void __user *)(cmd->value),
-			cmd->length)) {
-			rc = -EFAULT;
-			goto vpe_proc_general_done;
-		}
-		vpe_output_plane_config(cmdp);
-		break;
-
-	case VPE_SCALE_CFG_TYPE:
-		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
-		if (!cmdp) {
-			rc = -ENOMEM;
-			goto vpe_proc_general_done;
-		}
-		if (copy_from_user(cmdp,
-			(void __user *)(cmd->value),
-			cmd->length)) {
-			rc = -EFAULT;
-			goto vpe_proc_general_done;
-		}
-		vpe_update_scale_coef(cmdp);
-		break;
-
-	case VPE_CMD_DIS_OFFSET_CFG: {
-		struct msm_vfe_resp *vdata;
-		unsigned long flags;
-		/* first get the dis offset and frame id. */
-		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
-		if (!cmdp) {
-			rc = -ENOMEM;
-			goto vpe_proc_general_done;
-		}
-		if (copy_from_user(cmdp,
-			(void __user *)(cmd->value),
-			cmd->length)) {
-			rc = -EFAULT;
-			goto vpe_proc_general_done;
-		}
-		/* get the offset. */
-		vpe_ctrl->dis_offset = *(struct dis_offset_type *)cmdp;
-		spin_lock_irqsave(&sync->vpe_q.lock, flags);
-		if (!list_empty(&sync->vpe_q.list)) {
-			sync->vpe_q.len--;
-			qcmd = list_first_entry(&sync->vpe_q.list,
-					struct msm_queue_cmd, list_vpe_frame);
-			list_del_init(&qcmd->list_vpe_frame);
-		} else
-			qcmd = NULL;
-		spin_unlock_irqrestore(&sync->vpe_q.lock, flags);
-		if (!qcmd) {
-			pr_err("%s: no video frame.\n", __func__);
-			kfree(cmdp);
-			return -EAGAIN;
-		}
-		vdata = (struct msm_vfe_resp *)(qcmd->command);
-		vpe_buf = &vdata->vpe_bf;
-		vpe_update_scaler_with_dis(&(vpe_buf->vpe_crop),
-					&(vpe_ctrl->dis_offset));
-
-		msm_send_frame_to_vpe(vpe_buf->y_phy, vpe_buf->cbcr_phy,
-						&(vpe_buf->ts), OUTPUT_TYPE_V);
-
-		if (!qcmd || !atomic_read(&qcmd->on_heap)) {
-			kfree(cmdp);
-			return -EAGAIN;
-		}
-		if (!atomic_sub_return(1, &qcmd->on_heap))
-			kfree(qcmd);
-		break;
-	}
-
-	default:
-		break;
-	}
-vpe_proc_general_done:
-	kfree(cmdp);
 	return rc;
 }
 
-static void vpe_addr_convert(struct msm_vpe_phy_info *pinfo,
-	enum vpe_resp_msg type, void *data, void **ext, int32_t *elen)
+static void vpe_send_outmsg(void)
 {
-	CDBG("In vpe_addr_convert type = %d\n", type);
-	switch (type) {
-	case VPE_MSG_OUTPUT_V:
-		pinfo->output_id = OUTPUT_TYPE_V;
-		break;
-	case VPE_MSG_OUTPUT_ST_R:
-		/* output_id will be used by user space only. */
-		pinfo->output_id = OUTPUT_TYPE_V;
-		break;
-	default:
-		break;
-	} /* switch */
-
-	CDBG("In vpe_addr_convert output_id = %d\n", pinfo->output_id);
-
-	pinfo->y_phy =
-		((struct vpe_message *)data)->_u.msgOut.yBuffer;
-	pinfo->cbcr_phy =
-		((struct vpe_message *)data)->_u.msgOut.cbcrBuffer;
-	*ext  = vpe_ctrl->extdata;
-	*elen = vpe_ctrl->extlen;
-}
-
-void vpe_proc_ops(uint8_t id, void *msg, size_t len)
-{
-	struct msm_vpe_resp *rp;
-
-	rp = vpe_ctrl->resp->vpe_alloc(sizeof(struct msm_vpe_resp),
-		vpe_ctrl->syncdata, GFP_ATOMIC);
-	if (!rp) {
-		CDBG("rp: cannot allocate buffer\n");
-		return;
-	}
-
-	CDBG("vpe_proc_ops, msgId = %d rp->evt_msg.msg_id = %d\n",
-		id, rp->evt_msg.msg_id);
-	rp->evt_msg.type   = MSM_CAMERA_MSG;
-	rp->evt_msg.msg_id = id;
-	rp->evt_msg.len    = len;
-	rp->evt_msg.data   = msg;
-
-	switch (rp->evt_msg.msg_id) {
-	case MSG_ID_VPE_OUTPUT_V:
-		rp->type = VPE_MSG_OUTPUT_V;
-		vpe_addr_convert(&(rp->phy), VPE_MSG_OUTPUT_V,
-			rp->evt_msg.data, &(rp->extdata),
-			&(rp->extlen));
-		break;
-
-	case MSG_ID_VPE_OUTPUT_ST_R:
-		rp->type = VPE_MSG_OUTPUT_ST_R;
-		vpe_addr_convert(&(rp->phy), VPE_MSG_OUTPUT_ST_R,
-			rp->evt_msg.data, &(rp->extdata),
-			&(rp->extlen));
-		break;
-
-	case MSG_ID_VPE_OUTPUT_ST_L:
-		rp->type = VPE_MSG_OUTPUT_ST_L;
-		break;
-
-	default:
-		rp->type = VPE_MSG_GENERAL;
-		break;
-	}
-	CDBG("%s: time = %ld\n",
-			__func__, vpe_ctrl->ts.tv_nsec);
-
-	vpe_ctrl->resp->vpe_resp(rp, MSM_CAM_Q_VPE_MSG,
-					vpe_ctrl->syncdata,
-					&(vpe_ctrl->ts), GFP_ATOMIC);
-}
-
-int vpe_config_axi(struct axidata *ad)
-{
-	uint32_t p1;
-	struct msm_pmem_region *regp1 = NULL;
-	CDBG("vpe_config_axi:bufnum1 = %d.\n", ad->bufnum1);
-
-	if (ad->bufnum1 != 1)
-		return -EINVAL;
-
-	regp1 = &(ad->region[0]);
-	/* for video  Y address */
-	p1 = (regp1->paddr + regp1->info.y_off);
-	msm_io_w(p1, vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
-	/* for video  CbCr address */
-	p1 = (regp1->paddr + regp1->info.cbcr_off);
-	msm_io_w(p1, vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET);
-
-	return 0;
-}
-
-int msm_vpe_config(struct msm_vpe_cfg_cmd *cmd, void *data)
-{
-	struct msm_vpe_cmd vpecmd;
-	int rc = 0;
-	if (copy_from_user(&vpecmd,
-			(void __user *)(cmd->value),
-			sizeof(vpecmd))) {
-		pr_err("%s %d: copy_from_user failed\n", __func__,
-				__LINE__);
-		return -EFAULT;
-	}
-	CDBG("%s: cmd_type %d\n", __func__, cmd->cmd_type);
-	switch (cmd->cmd_type) {
-	case CMD_VPE:
-		rc = vpe_proc_general(&vpecmd);
-		CDBG(" rc = %d\n", rc);
-		break;
-
-	case CMD_AXI_CFG_VPE:
-	case CMD_AXI_CFG_SNAP_VPE:
-	case CMD_AXI_CFG_SNAP_THUMB_VPE: {
-		struct axidata *axid;
-		axid = data;
-		if (!axid)
-			return -EFAULT;
-		vpe_config_axi(axid);
-		break;
-	}
-	default:
-		break;
-	}
-	CDBG("%s: rc = %d\n", __func__, rc);
-	return rc;
-}
-
-void msm_vpe_offset_update(int frame_pack, uint32_t pyaddr, uint32_t pcbcraddr,
-	struct timespec *ts, int output_id, struct msm_st_half st_half,
-	int frameid)
-{
-	struct msm_vpe_buf_info vpe_buf;
-	uint32_t input_stride;
-
-	vpe_buf.vpe_crop.in2_w = st_half.stCropInfo.in_w;
-	vpe_buf.vpe_crop.in2_h = st_half.stCropInfo.in_h;
-	vpe_buf.vpe_crop.out2_w = st_half.stCropInfo.out_w;
-	vpe_buf.vpe_crop.out2_h = st_half.stCropInfo.out_h;
-	vpe_ctrl->dis_offset.dis_offset_x = st_half.pix_x_off;
-	vpe_ctrl->dis_offset.dis_offset_y = st_half.pix_y_off;
-	vpe_ctrl->dis_offset.frame_id = frameid;
-	vpe_ctrl->frame_pack = frame_pack;
-	vpe_ctrl->output_type = output_id;
-
-	input_stride = (st_half.buf_cbcr_stride * (1<<16)) +
-		st_half.buf_y_stride;
-
-	msm_io_w(input_stride, vpe_device->vpebase + VPE_SRC_YSTRIDE1_OFFSET);
-
-	vpe_update_scaler_with_dis(&(vpe_buf.vpe_crop),
-		&(vpe_ctrl->dis_offset));
-
-	msm_send_frame_to_vpe(pyaddr, pcbcraddr, ts, output_id);
-}
-
-static void vpe_send_outmsg(uint8_t msgid, uint32_t pyaddr,
-	uint32_t pcbcraddr)
-{
-	struct vpe_message msg;
-	uint8_t outid;
-	msg._d = outid = msgid;
-	msg._u.msgOut.output_id   = msgid;
-	msg._u.msgOut.yBuffer     = pyaddr;
-	msg._u.msgOut.cbcrBuffer  = pcbcraddr;
-	vpe_proc_ops(outid, &msg, sizeof(struct vpe_message));
-	return;
-}
-
-int msm_vpe_reg(struct msm_vpe_callback *presp)
-{
-	if (presp && presp->vpe_resp)
-		vpe_ctrl->resp = presp;
-
-	return 0;
-}
-
-static void vpe_send_msg_no_payload(enum VPE_MESSAGE_ID id)
-{
-	struct vpe_message msg;
-
-	CDBG("vfe31_send_msg_no_payload\n");
-	msg._d = id;
-	vpe_proc_ops(id, &msg, 0);
+	unsigned long flags;
+	struct msm_vpe_resp rp;
+	memset(&rp, 0, sizeof(rp));
+	spin_lock_irqsave(&vpe_ctrl->lock, flags);
+	rp.type = vpe_ctrl->pp_frame_info->pp_frame_cmd.path;
+	rp.extdata = (void *)vpe_ctrl->pp_frame_info;
+	rp.extlen = sizeof(*vpe_ctrl->pp_frame_info);
+	vpe_ctrl->state = VPE_STATE_INIT;   /* put it back to idle. */
+	vpe_ctrl->pp_frame_info = NULL;
+	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+	v4l2_subdev_notify(vpe_ctrl->subdev,
+		NOTIFY_VPE_MSG_EVT, (void *)&rp);
 }
 
 static void vpe_do_tasklet(unsigned long data)
 {
-	unsigned long flags;
-	uint32_t pyaddr = 0, pcbcraddr = 0;
-	uint32_t src_y, src_cbcr, temp;
+	CDBG("%s: irq_status = 0x%x",
+		   __func__, vpe_ctrl->irq_status);
+	if (vpe_ctrl->irq_status & 0x1)
+		vpe_send_outmsg();
 
-	struct vpe_isr_queue_cmd_type *qcmd = NULL;
-
-	CDBG("=== vpe_do_tasklet start ===\n");
-
-	spin_lock_irqsave(&vpe_ctrl->tasklet_lock, flags);
-	qcmd = list_first_entry(&vpe_ctrl->tasklet_q,
-		struct vpe_isr_queue_cmd_type, list);
-
-	if (!qcmd) {
-		spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags);
-		return;
-	}
-
-	list_del(&qcmd->list);
-	spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags);
-
-	/* interrupt to be processed,  *qcmd has the payload.  */
-	if (qcmd->irq_status & 0x1) {
-		if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_L) {
-			CDBG("vpe left frame done.\n");
-			vpe_ctrl->output_type = 0;
-			CDBG("vpe send out msg.\n");
-			orig_src_y = msm_io_r(vpe_device->vpebase +
-				VPE_SRCP0_ADDR_OFFSET);
-			orig_src_cbcr = msm_io_r(vpe_device->vpebase +
-				VPE_SRCP1_ADDR_OFFSET);
-
-			pyaddr = msm_io_r(vpe_device->vpebase +
-				VPE_OUTP0_ADDR_OFFSET);
-			pcbcraddr = msm_io_r(vpe_device->vpebase +
-				VPE_OUTP1_ADDR_OFFSET);
-			CDBG("%s: out_w = %d, out_h = %d\n", __func__,
-				vpe_ctrl->out_w, vpe_ctrl->out_h);
-
-			if ((vpe_ctrl->frame_pack == TOP_DOWN_FULL) ||
-				(vpe_ctrl->frame_pack == TOP_DOWN_HALF)) {
-				msm_io_w(pyaddr + (vpe_ctrl->out_w *
-					vpe_ctrl->out_h), vpe_device->vpebase +
-					VPE_OUTP0_ADDR_OFFSET);
-				msm_io_w(pcbcraddr + (vpe_ctrl->out_w *
-					vpe_ctrl->out_h/2),
-					vpe_device->vpebase +
-					VPE_OUTP1_ADDR_OFFSET);
-			} else if ((vpe_ctrl->frame_pack ==
-				SIDE_BY_SIDE_HALF) || (vpe_ctrl->frame_pack ==
-				SIDE_BY_SIDE_FULL)) {
-				msm_io_w(pyaddr + vpe_ctrl->out_w,
-					vpe_device->vpebase +
-					VPE_OUTP0_ADDR_OFFSET);
-				msm_io_w(pcbcraddr + vpe_ctrl->out_w,
-					vpe_device->vpebase +
-					VPE_OUTP1_ADDR_OFFSET);
-			} else
-				CDBG("%s: Invalid packing = %d\n", __func__,
-					vpe_ctrl->frame_pack);
-
-			vpe_send_msg_no_payload(MSG_ID_VPE_OUTPUT_ST_L);
-			vpe_ctrl->state = VPE_STATE_INIT;
-			kfree(qcmd);
-			return;
-		} else if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_R) {
-			src_y = orig_src_y;
-			src_cbcr = orig_src_cbcr;
-			CDBG("%s: out_w = %d, out_h = %d\n", __func__,
-				vpe_ctrl->out_w, vpe_ctrl->out_h);
-
-			if ((vpe_ctrl->frame_pack == TOP_DOWN_FULL) ||
-				(vpe_ctrl->frame_pack == TOP_DOWN_HALF)) {
-				pyaddr = msm_io_r(vpe_device->vpebase +
-					VPE_OUTP0_ADDR_OFFSET) -
-					(vpe_ctrl->out_w * vpe_ctrl->out_h);
-			} else if ((vpe_ctrl->frame_pack ==
-				SIDE_BY_SIDE_HALF) || (vpe_ctrl->frame_pack ==
-				SIDE_BY_SIDE_FULL)) {
-				pyaddr = msm_io_r(vpe_device->vpebase +
-				VPE_OUTP0_ADDR_OFFSET) - vpe_ctrl->out_w;
-			} else
-				CDBG("%s: Invalid packing = %d\n", __func__,
-					vpe_ctrl->frame_pack);
-
-			pcbcraddr = vpe_ctrl->pcbcr_before_dis;
-		} else {
-			src_y =	msm_io_r(vpe_device->vpebase +
-				VPE_SRCP0_ADDR_OFFSET);
-			src_cbcr = msm_io_r(vpe_device->vpebase +
-				VPE_SRCP1_ADDR_OFFSET);
-			pyaddr = msm_io_r(vpe_device->vpebase +
-				VPE_OUTP0_ADDR_OFFSET);
-			pcbcraddr = msm_io_r(vpe_device->vpebase +
-				VPE_OUTP1_ADDR_OFFSET);
-		}
-
-		if (vpe_ctrl->dis_en)
-			pcbcraddr = vpe_ctrl->pcbcr_before_dis;
-
-		msm_io_w(src_y,
-				vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
-		msm_io_w(src_cbcr,
-				vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET);
-
-		temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) &
-			0xFFFFFFFC;
-		msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
-
-		/*  now pass this frame to msm_camera.c. */
-		if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_R) {
-			CDBG("vpe send out R msg.\n");
-			vpe_send_outmsg(MSG_ID_VPE_OUTPUT_ST_R, pyaddr,
-				pcbcraddr);
-		} else if (vpe_ctrl->output_type == OUTPUT_TYPE_V) {
-			CDBG("vpe send out V msg.\n");
-			vpe_send_outmsg(MSG_ID_VPE_OUTPUT_V, pyaddr, pcbcraddr);
-		}
-
-		vpe_ctrl->output_type = 0;
-		vpe_ctrl->state = VPE_STATE_INIT;   /* put it back to idle. */
-
-	}
-	kfree(qcmd);
 }
 DECLARE_TASKLET(vpe_tasklet, vpe_do_tasklet, 0);
 
 static irqreturn_t vpe_parse_irq(int irq_num, void *data)
 {
-	unsigned long flags;
-	uint32_t irq_status = 0;
-	struct vpe_isr_queue_cmd_type *qcmd;
-
-	CDBG("vpe_parse_irq.\n");
-	/* read and clear back-to-back. */
-	irq_status = msm_io_r_mb(vpe_device->vpebase +
+	vpe_ctrl->irq_status = msm_io_r_mb(vpe_device->vpebase +
 							VPE_INTR_STATUS_OFFSET);
-	msm_io_w_mb(irq_status, vpe_device->vpebase +
+	msm_io_w_mb(vpe_ctrl->irq_status, vpe_device->vpebase +
 				VPE_INTR_CLEAR_OFFSET);
-
 	msm_io_w(0, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
-
-	if (irq_status == 0) {
-		pr_err("%s: irq_status = 0,Something is wrong!\n", __func__);
-		return IRQ_HANDLED;
-	}
-	irq_status &= 0x1;
-	/* apply mask. only interested in bit 0.  */
-	if (irq_status) {
-		qcmd = kzalloc(sizeof(struct vpe_isr_queue_cmd_type),
-			GFP_ATOMIC);
-		if (!qcmd) {
-			pr_err("%s: qcmd malloc failed!\n", __func__);
-			return IRQ_HANDLED;
-		}
-		/* must be 0x1 now. so in bottom half we don't really
-		need to check. */
-		qcmd->irq_status = irq_status & 0x1;
-		spin_lock_irqsave(&vpe_ctrl->tasklet_lock, flags);
-		list_add_tail(&qcmd->list, &vpe_ctrl->tasklet_q);
-		spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags);
-		tasklet_schedule(&vpe_tasklet);
-	}
+	CDBG("%s: vpe_parse_irq =0x%x.\n", __func__, vpe_ctrl->irq_status);
+	tasklet_schedule(&vpe_tasklet);
 	return IRQ_HANDLED;
 }
 
 static int vpe_enable_irq(void)
 {
-	uint32_t   rc = 0;
-	rc = request_irq(vpe_device->vpeirq,
-				vpe_parse_irq,
-				IRQF_TRIGGER_HIGH, "vpe", 0);
+	uint32_t rc = 0;
+	enable_irq(vpe_device->vpeirq);
 	return rc;
 }
 
-int msm_vpe_open(void)
-{
-	int rc = 0;
-
-	CDBG("%s: In\n", __func__);
-
-	vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL);
-	if (!vpe_ctrl) {
-		pr_err("%s: no memory!\n", __func__);
-		return -ENOMEM;
-	}
-
-	spin_lock_init(&vpe_ctrl->ops_lock);
-	CDBG("%s: Out\n", __func__);
-
-	return rc;
-}
-
-int msm_vpe_release(void)
-{
-	/* clean up....*/
-	int rc = 0;
-	CDBG("%s: state %d\n", __func__, vpe_ctrl->state);
-	if (vpe_ctrl->state != VPE_STATE_IDLE)
-		rc = vpe_disable();
-
-	kfree(vpe_ctrl);
-	return rc;
-}
-
-
 int vpe_enable(uint32_t clk_rate)
 {
 	int rc = 0;
 	unsigned long flags = 0;
+	CDBG("%s", __func__);
 	/* don't change the order of clock and irq.*/
-	CDBG("%s: enable_clock rate %u\n", __func__, clk_rate);
-	spin_lock_irqsave(&vpe_ctrl->ops_lock, flags);
+	spin_lock_irqsave(&vpe_ctrl->lock, flags);
 	if (vpe_ctrl->state != VPE_STATE_IDLE) {
-		CDBG("%s: VPE already enabled", __func__);
-		spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
+		pr_err("%s: VPE already enabled", __func__);
+		spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
 		return 0;
 	}
 	vpe_ctrl->state = VPE_STATE_INIT;
-	spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
-
+	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
 	rc = msm_camio_vpe_clk_enable(clk_rate);
 	if (rc < 0) {
 		pr_err("%s: msm_camio_vpe_clk_enable failed", __func__);
 		vpe_ctrl->state = VPE_STATE_IDLE;
 		return rc;
 	}
-
-	CDBG("%s: enable_irq\n", __func__);
 	vpe_enable_irq();
-
-	/* initialize the data structure - lock, queue etc. */
-	spin_lock_init(&vpe_ctrl->tasklet_lock);
-	INIT_LIST_HEAD(&vpe_ctrl->tasklet_q);
-
 	return rc;
 }
 
@@ -1308,44 +534,149 @@
 {
 	int rc = 0;
 	unsigned long flags = 0;
-	CDBG("%s: called", __func__);
-	spin_lock_irqsave(&vpe_ctrl->ops_lock, flags);
+	CDBG("%s", __func__);
+	spin_lock_irqsave(&vpe_ctrl->lock, flags);
 	if (vpe_ctrl->state == VPE_STATE_IDLE) {
 		CDBG("%s: VPE already disabled", __func__);
-		spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
-		return 0;
+		spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+		return rc;
 	}
 	vpe_ctrl->state = VPE_STATE_IDLE;
-	spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
-	vpe_ctrl->out_y_addr = msm_io_r(vpe_device->vpebase +
-		VPE_OUTP0_ADDR_OFFSET);
-	vpe_ctrl->out_cbcr_addr = msm_io_r(vpe_device->vpebase +
-		VPE_OUTP1_ADDR_OFFSET);
-	free_irq(vpe_device->vpeirq, 0);
+	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+	disable_irq(vpe_device->vpeirq);
 	tasklet_kill(&vpe_tasklet);
 	rc = msm_camio_vpe_clk_disable();
 	return rc;
 }
 
-static int __msm_vpe_probe(struct platform_device *pdev)
+static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd,
+			struct msm_mctl_pp_frame_info *pp_frame_info)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vpe_ctrl->lock, flags);
+	if (vpe_ctrl->state == VPE_STATE_ACTIVE) {
+		spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+		pr_err(" =====VPE is busy!!!  Wrong!========\n");
+		return -EBUSY;
+	}
+	spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+	vpe_ctrl->pp_frame_info = pp_frame_info;
+	msm_vpe_cfg_update(
+			&vpe_ctrl->pp_frame_info->pp_frame_cmd.crop);
+	rc = msm_send_frame_to_vpe();
+	return rc;
+}
+
+static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int subdev_cmd, void *arg)
+{
+	struct msm_mctl_pp_params *vpe_params =
+		(struct msm_mctl_pp_params *)arg;
+	struct msm_mctl_pp_cmd *cmd = vpe_params->cmd;
+	int rc = 0;
+	switch (cmd->id) {
+	case VPE_CMD_INIT:
+	case VPE_CMD_DEINIT:
+		break;
+	case VPE_CMD_RESET:
+		rc = vpe_reset();
+		break;
+	case VPE_CMD_OPERATION_MODE_CFG:
+		rc = vpe_operation_config(cmd->value);
+		break;
+	case VPE_CMD_INPUT_PLANE_CFG:
+		vpe_input_plane_config(cmd->value);
+		break;
+	case VPE_CMD_OUTPUT_PLANE_CFG:
+		vpe_output_plane_config(cmd->value);
+		break;
+	case VPE_CMD_SCALE_CFG_TYPE:
+		vpe_update_scale_coef(cmd->value);
+		break;
+	case VPE_CMD_ZOOM: {
+		rc = msm_vpe_do_pp(cmd,
+			(struct msm_mctl_pp_frame_info *)vpe_params->data);
+		break;
+	}
+	case VPE_CMD_ENABLE: {
+		struct msm_vpe_clock_rate *clk_rate = cmd->value;
+		int turbo_mode = (int)clk_rate->rate;
+		rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) :
+			vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
+		break;
+	}
+	case VPE_CMD_DISABLE:
+		rc = vpe_disable();
+		break;
+	case VPE_CMD_INPUT_PLANE_UPDATE:
+	case VPE_CMD_FLUSH:
+	case VPE_CMD_DIS_OFFSET_CFG:
+	default:
+		break;
+	}
+	CDBG("%s: end, id = %d, rc = %d", __func__, cmd->id, rc);
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = {
+	.ioctl = msm_vpe_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_vpe_subdev_ops = {
+	.core = &msm_vpe_subdev_core_ops,
+};
+
+static int msm_vpe_resource_init(struct platform_device *pdev, void *sdata);
+
+int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data,
+	struct platform_device *pdev)
+{
+	int rc = 0;
+	CDBG("%s:begin", __func__);
+	if (atomic_read(&vpe_init_done)) {
+		pr_err("%s: VPE has been initialized", __func__);
+		return -EBUSY;
+	}
+	atomic_set(&vpe_init_done, 1);
+	vpe_syncdata = data;
+	rc = msm_vpe_resource_init(pdev, vpe_syncdata);
+	if (rc < 0) {
+		atomic_set(&vpe_init_done, 0);
+		return rc;
+	}
+	vpe_ctrl->subdev = sd;
+	v4l2_subdev_init(sd, &msm_vpe_subdev_ops);
+	v4l2_set_subdev_hostdata(sd, data);
+	snprintf(sd->name, sizeof(sd->name), "vpe");
+	spin_lock_init(&vpe_ctrl->lock);
+	CDBG("%s:end", __func__);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vpe_subdev_init);
+
+static int msm_vpe_resource_init(struct platform_device *pdev,
+				void *sdata)
 {
 	int rc = 0;
 	struct resource   *vpemem, *vpeirq, *vpeio;
 	void __iomem      *vpebase;
-
 	/* first allocate */
-
-	vpe_device = &vpe_device_data;
-	memset(vpe_device, 0, sizeof(struct vpe_device_type));
-
+	vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL);
+	if (!vpe_ctrl) {
+		rc = -ENOMEM;
+		goto vpe_free_device;
+	}
+	vpe_device = &vpe_ctrl->device_data;
 	/* does the device exist? */
-	vpeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	vpeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
 	if (!vpeirq) {
 		pr_err("%s: no vpe irq resource.\n", __func__);
 		rc = -ENODEV;
 		goto vpe_free_device;
 	}
-	vpemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	vpemem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	if (!vpemem) {
 		pr_err("%s: no vpe mem resource!\n", __func__);
 		rc = -ENODEV;
@@ -1356,9 +687,8 @@
 	if (!vpeio) {
 		pr_err("%s: VPE region already claimed.\n", __func__);
 		rc = -EBUSY;
-		goto vpe_free_device;
+		goto vpe_release_mem_region;
 	}
-
 	vpebase =
 		ioremap(vpemem->start,
 				(vpemem->end - vpemem->start) + 1);
@@ -1373,6 +703,11 @@
 	vpe_device->vpemem = vpemem;
 	vpe_device->vpeio = vpeio;
 	vpe_device->vpebase = vpebase;
+	rc = request_irq(vpe_device->vpeirq,
+				vpe_parse_irq,
+				IRQF_TRIGGER_HIGH, "vpe", 0);
+	disable_irq(vpe_device->vpeirq);
+	CDBG("%s:end: vpebase=0x%p", __func__, vpebase);
 	return rc;  /* this rc should be zero.*/
 
 	iounmap(vpe_device->vpebase);  /* this path should never occur */
@@ -1381,41 +716,32 @@
 vpe_release_mem_region:
 	release_mem_region(vpemem->start, (vpemem->end - vpemem->start) + 1);
 vpe_free_device:
+	kfree(vpe_ctrl);
 	return rc;  /* this rc should have error code. */
 }
 
-static int __msm_vpe_remove(struct platform_device *pdev)
+void msm_vpe_subdev_release(struct platform_device *pdev)
 {
-	struct resource	*vpemem;
-	vpemem = vpe_device->vpemem;
+	struct resource	*vpemem, *vpeio;
+	if (!atomic_read(&vpe_init_done)) {
+		/* no VPE object created */
+		pr_err("%s: no VPE object to release", __func__);
+		return;
+	}
+	CDBG("%s, free_irq\n", __func__);
+	free_irq(vpe_ctrl->device_data.vpeirq, 0);
 
-	iounmap(vpe_device->vpebase);
-	release_mem_region(vpemem->start,
-					(vpemem->end - vpemem->start) + 1);
-	return 0;
+	vpemem = vpe_ctrl->device_data.vpemem;
+	vpeio  = vpe_ctrl->device_data.vpeio;
+
+	kfree(vpe_ctrl->extdata);
+	iounmap(vpe_ctrl->device_data.vpebase);
+	kfree(vpe_ctrl);
+	vpe_ctrl = NULL;
+	release_mem_region(vpemem->start, (vpemem->end - vpemem->start) + 1);
+	CDBG("%s, end\n", __func__);
+	vpe_syncdata = NULL;
+	atomic_set(&vpe_init_done, 0);
 }
+EXPORT_SYMBOL(msm_vpe_subdev_release);
 
-static struct platform_driver msm_vpe_driver = {
-	.probe = __msm_vpe_probe,
-	.remove = __msm_vpe_remove,
-	.driver = {
-		.name = "msm_vpe",
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init msm_vpe_init(void)
-{
-	return platform_driver_register(&msm_vpe_driver);
-}
-module_init(msm_vpe_init);
-
-static void __exit msm_vpe_exit(void)
-{
-	platform_driver_unregister(&msm_vpe_driver);
-}
-module_exit(msm_vpe_exit);
-
-MODULE_DESCRIPTION("msm vpe 1.0 driver");
-MODULE_VERSION("msm vpe driver 1.0");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_vpe.h b/drivers/media/video/msm/msm_vpe.h
index 39f5781..40df0b0 100644
--- a/drivers/media/video/msm/msm_vpe.h
+++ b/drivers/media/video/msm/msm_vpe.h
@@ -72,67 +72,19 @@
 #define VPE_HARDWARE_VERSION          0x00080308
 #define VPE_SW_RESET_VALUE            0x00000010  /* bit 4 for PPP*/
 #define VPE_AXI_RD_ARB_CONFIG_VALUE   0x124924
-#define VPE_CMD_MODE_VALUE        0x1
+#define VPE_CMD_MODE_VALUE            0x1
 #define VPE_DEFAULT_OP_MODE_VALUE     0x40FC0004
 #define VPE_CGC_ENABLE_VALUE          0xffff
 #define VPE_DEFAULT_SCALE_CONFIG      0x3c
 
 #define VPE_NORMAL_MODE_CLOCK_RATE   150000000
 #define VPE_TURBO_MODE_CLOCK_RATE   200000000
-/**************************************************/
-/*********** Start of command id ******************/
-/**************************************************/
-enum VPE_CMD_ID_ENUM {
-	VPE_DUMMY_0 = 0,
-	VPE_SET_CLK,
-	VPE_RESET,
-	VPE_START,
-	VPE_ABORT,
-	VPE_OPERATION_MODE_CFG, /* 5 */
-	VPE_INPUT_PLANE_CFG,
-	VPE_OUTPUT_PLANE_CFG,
-	VPE_INPUT_PLANE_UPDATE,
-	VPE_SCALE_CFG_TYPE,
-	VPE_ROTATION_CFG_TYPE, /* 10 */
-	VPE_AXI_OUT_CFG,
-	VPE_CMD_DIS_OFFSET_CFG,
-	VPE_ENABLE,
-	VPE_DISABLE,
-};
 
-/* Length of each command.  In bytes.  (payload only) */
-#define VPE_OPERATION_MODE_CFG_LEN 8
-#define VPE_INPUT_PLANE_CFG_LEN    24
-#define VPE_OUTPUT_PLANE_CFG_LEN   20
-#define VPE_INPUT_PLANE_UPDATE_LEN 12
-#define VPE_SCALER_CONFIG_LEN      260
-#define VPE_DIS_OFFSET_CFG_LEN     12
+
 /**************************************************/
 /*********** End of command id ********************/
 /**************************************************/
 
-struct msm_vpe_cmd {
-	int32_t  id;
-	uint16_t length;
-	void     *value;
-};
-
-struct vpe_cmd_type {
-	uint16_t id;
-	uint32_t length;
-};
-
-struct vpe_isr_queue_cmd_type {
-	struct list_head            list;
-	uint32_t                    irq_status;
-};
-
-enum VPE_MESSAGE_ID {
-	MSG_ID_VPE_OUTPUT_V = 7, /* To match with that of VFE */
-	MSG_ID_VPE_OUTPUT_ST_L,
-	MSG_ID_VPE_OUTPUT_ST_R,
-};
-
 enum vpe_state {
 	VPE_STATE_IDLE,
 	VPE_STATE_INIT,
@@ -155,11 +107,8 @@
 };
 
 struct vpe_ctrl_type {
-	spinlock_t        tasklet_lock;
-	spinlock_t        state_lock;
-	spinlock_t        ops_lock;
-
-	struct list_head  tasklet_q;
+	spinlock_t        lock;
+	uint32_t          irq_status;
 	void              *syncdata;
 	uint16_t          op_mode;
 	void              *extdata;
@@ -179,6 +128,9 @@
 	enum vpe_state    state;
 	unsigned long     out_y_addr;
 	unsigned long     out_cbcr_addr;
+	struct v4l2_subdev *subdev;
+	struct vpe_device_type device_data;
+	struct msm_mctl_pp_frame_info *pp_frame_info;
 };
 
 /*
@@ -238,28 +190,6 @@
 	int32_t phase_step_y;
 };
 
-extern struct vpe_ctrl_type *vpe_ctrl;
-
-int msm_vpe_open(void);
-int msm_vpe_release(void);
-int msm_vpe_reg(struct msm_vpe_callback *presp);
-void msm_send_frame_to_vpe(uint32_t pyaddr, uint32_t pcbcraddr,
-	struct timespec *ts, int output_id);
-int msm_vpe_config(struct msm_vpe_cfg_cmd *cmd, void *data);
-int msm_vpe_cfg_update(void *pinfo);
-void msm_vpe_offset_update(int frame_pack, uint32_t pyaddr,
-			uint32_t pcbcraddr,
-			struct timespec *ts, int output_id,
-			struct msm_st_half st_half,
-			int frameid);
-void msm_send_frame_with_crop_and_dis_offset(
-			struct msm_vpe_buf_info *src_buf,
-			struct msm_vpe_buf_info *dest_buf,
-			int output_id,
-			struct dis_offset_type *dis_offset);
-
-typedef void (*msm_vpe_buf_cb_t) (struct msm_vpe_buf_info *out_buf,
-			uint8_t output_id, void *cookie);
 
 #endif /*_MSM_VPE_H_*/
 
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index b69ce5d..ad515dd 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -144,6 +144,26 @@
 #define MSM_CAM_IOCTL_ACTUATOR_IO_CFG \
 	_IOW(MSM_CAM_IOCTL_MAGIC, 43, struct msm_actuator_cfg_data *)
 
+#define MSM_CAM_IOCTL_MCTL_POST_PROC \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 44, struct msm_mctl_post_proc_cmd *)
+
+#define MSM_CAM_IOCTL_RESERVE_FREE_FRAME \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 45, struct msm_cam_evt_divert_frame *)
+
+#define MSM_CAM_IOCTL_RELEASE_FREE_FRAME \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 46, struct msm_cam_evt_divert_frame *)
+
+struct msm_mctl_pp_cmd {
+	int32_t  id;
+	uint16_t length;
+	void     *value;
+};
+
+struct msm_mctl_post_proc_cmd {
+	int32_t type;
+	struct msm_mctl_pp_cmd cmd;
+};
+
 #define MSM_CAMERA_LED_OFF  0
 #define MSM_CAMERA_LED_LOW  1
 #define MSM_CAMERA_LED_HIGH 2
@@ -208,12 +228,15 @@
 	unsigned short node_idx;
 	unsigned long  phy_addr;
 	uint32_t       phy_offset;
-	uint32_t       offset;
+	uint32_t       y_off;
+	uint32_t       cbcr_off;
 	int32_t        fd;
 	uint32_t       frame_id;
 	int            path;
 	uint32_t       length;
 	struct timeval timestamp;
+	int            do_pp;
+	uint32_t       vb;
 };
 
 struct msm_isp_stats_event_ctrl {
@@ -224,17 +247,20 @@
 	} isp_data;
 };
 
-#define MSM_CAM_RESP_CTRL         0
-#define MSM_CAM_RESP_STAT_EVT_MSG 1
-#define MSM_CAM_RESP_STEREO_OP_1  2
-#define MSM_CAM_RESP_STEREO_OP_2  3
-#define MSM_CAM_RESP_V4L2         4
+#define MSM_CAM_RESP_CTRL              0
+#define MSM_CAM_RESP_STAT_EVT_MSG      1
+#define MSM_CAM_RESP_STEREO_OP_1       2
+#define MSM_CAM_RESP_STEREO_OP_2       3
+#define MSM_CAM_RESP_V4L2              4
 #define MSM_CAM_RESP_DIV_FRAME_EVT_MSG 5
-#define MSM_CAM_RESP_DONE_EVENT   6
-#define MSM_CAM_RESP_MAX          7
+#define MSM_CAM_RESP_DONE_EVENT        6
+#define MSM_CAM_RESP_MCTL_PP_EVENT     7
+#define MSM_CAM_RESP_MAX               8
 
 #define MSM_CAM_APP_NOTIFY_EVENT  0
+
 /* this one is used to send ctrl/status up to config thread */
+
 struct msm_stats_event_ctrl {
 	/* 0 - ctrl_cmd from control thread,
 	 * 1 - stats/event kernel,
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index b60216f..fd46692 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -172,4 +172,148 @@
 	void     *value;
 };
 
-#endif /* __MSM_ISP_H__ */
+
+#define VPE_CMD_DUMMY_0                                 0
+#define VPE_CMD_INIT                                    1
+#define VPE_CMD_DEINIT                                  2
+#define VPE_CMD_ENABLE                                  3
+#define VPE_CMD_DISABLE                                 4
+#define VPE_CMD_RESET                                   5
+#define VPE_CMD_FLUSH                                   6
+#define VPE_CMD_OPERATION_MODE_CFG                      7
+#define VPE_CMD_INPUT_PLANE_CFG                         8
+#define VPE_CMD_OUTPUT_PLANE_CFG                        9
+#define VPE_CMD_INPUT_PLANE_UPDATE                      10
+#define VPE_CMD_SCALE_CFG_TYPE                          11
+#define VPE_CMD_DIS_OFFSET_CFG                          12
+#define VPE_CMD_ZOOM                                    13
+
+#define MSM_PP_CMD_TYPE_NOT_USED        0  /* not used */
+#define MSM_PP_CMD_TYPE_VPE             1  /* VPE cmd */
+#define MSM_PP_CMD_TYPE_MCTL            2  /* MCTL cmd */
+
+#define MCTL_CMD_DUMMY_0                0  /* not used */
+#define MCTL_CMD_GET_FRAME_BUFFER       1  /* reserve a free frame buffer */
+#define MCTL_CMD_PUT_FRAME_BUFFER       2  /* return the free frame buffer */
+#define MCTL_CMD_DIVERT_FRAME_PP_PATH   3  /* divert frame for pp */
+#define MCTL_CMD_DIVERT_FRAME_PP_DONE   4  /* pp done. buf send to app */
+
+/* event typese sending to MCTL PP module */
+#define MCTL_PP_EVENT_NOTUSED           0
+#define MCTL_PP_EVENT_CMD_ACK           1
+
+#define VPE_OPERATION_MODE_CFG_LEN      8
+#define VPE_INPUT_PLANE_CFG_LEN         24
+#define VPE_OUTPUT_PLANE_CFG_LEN        24
+#define VPE_INPUT_PLANE_UPDATE_LEN      12
+#define VPE_SCALER_CONFIG_LEN           260
+#define VPE_DIS_OFFSET_CFG_LEN          12
+
+struct msm_vpe_op_mode_cfg {
+	uint8_t op_mode_cfg[VPE_OPERATION_MODE_CFG_LEN];
+};
+
+struct msm_vpe_input_plane_cfg {
+	uint8_t input_plane_cfg[VPE_INPUT_PLANE_CFG_LEN];
+};
+
+struct msm_vpe_output_plane_cfg {
+	uint8_t output_plane_cfg[VPE_OUTPUT_PLANE_CFG_LEN];
+};
+
+struct msm_vpe_input_plane_update_cfg {
+	uint8_t input_plane_update_cfg[VPE_INPUT_PLANE_UPDATE_LEN];
+};
+
+struct msm_vpe_scaler_cfg {
+	uint8_t scaler_cfg[VPE_SCALER_CONFIG_LEN];
+};
+
+struct msm_vpe_dis_offset_cfg {
+	uint8_t dis_offset_cfg[VPE_DIS_OFFSET_CFG_LEN];
+};
+
+struct msm_vpe_flush_frame_buffer {
+	uint32_t src_buf_handle;
+	uint32_t dest_buf_handle;
+	int path;
+};
+
+struct msm_mctl_pp_frame_buffer {
+	uint32_t buf_handle;
+	int path;
+};
+struct msm_mctl_pp_divert_pp {
+	int path;
+};
+struct msm_vpe_clock_rate {
+	uint32_t rate;
+};
+struct msm_pp_crop {
+	uint32_t  src_x;
+	uint32_t  src_y;
+	uint32_t  src_w;
+	uint32_t  src_h;
+	uint32_t  dst_x;
+	uint32_t  dst_y;
+	uint32_t  dst_w;
+	uint32_t  dst_h;
+	uint8_t update_flag;
+};
+#define MSM_MCTL_PP_VPE_FRAME_ACK    (1<<0)
+#define MSM_MCTL_PP_VPE_FRAME_TO_APP (1<<1)
+
+struct msm_mctl_pp_frame_cmd {
+	uint32_t cookie;
+	uint8_t  vpe_output_action;
+	uint32_t src_buf_handle;
+	uint32_t dest_buf_handle;
+	struct msm_pp_crop crop;
+	int path;
+	/* TBD: 3D related */
+};
+
+struct msm_mctl_pp_cmd_ack_event {
+	uint32_t cmd;        /* VPE_CMD_ZOOM? */
+	int      status;     /* 0 done, < 0 err */
+	uint32_t cookie;     /* daemon's cookie */
+};
+
+struct msm_pp_frame_sp {
+	unsigned long  phy_addr;
+	uint32_t       y_off;
+	uint32_t       cbcr_off;
+	uint32_t       length;
+	int32_t        fd;
+	uint32_t       addr_offset;
+};
+
+struct msm_pp_frame_mp {
+	unsigned long  phy_addr;
+	uint32_t       data_offset;
+	uint32_t       length;
+	int32_t        fd;
+	uint32_t       addr_offset;
+};
+
+struct msm_pp_frame {
+	uint32_t       handle;
+	uint32_t       frame_id;
+	unsigned short image_type;
+	unsigned short num_planes; /* 1 for sp */
+	struct timeval timestamp;
+	union {
+		struct msm_pp_frame_sp sp;
+	};
+};
+
+struct msm_mctl_pp_event_info {
+	int32_t  event;
+	union {
+		struct msm_mctl_pp_cmd_ack_event ack;
+	};
+};
+
+
+#endif /*__MSM_ISP_H__*/
+