Merge "msm: mpq8064: Allow client to select num bufs for VC to hold onto" into msm-3.4
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 407bf2e..cb33550 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -503,7 +503,7 @@
 			       unsigned int *nplanes, unsigned int sizes[],
 			       void *alloc_ctxs[])
 {
-	*nbuffers += 2;
+	*nbuffers += vcap_ctrl->vc_tot_buf;
 	if (*nbuffers > VIDEO_MAX_FRAME)
 		return -EINVAL;
 	*nplanes = 1;
@@ -524,17 +524,16 @@
 {
 	struct vcap_client_data *c_data = vb2_get_drv_priv(vb->vb2_queue);
 	struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
-	struct vcap_action *vid_vc_action = &c_data->vid_vc_action;
+	struct vc_action *vc_action = &c_data->vc_action;
 	struct vb2_queue *q = vb->vb2_queue;
 	unsigned long flags = 0;
 
 	spin_lock_irqsave(&c_data->cap_slock, flags);
-	list_add_tail(&buf->list, &vid_vc_action->active);
+	list_add_tail(&buf->list, &vc_action->active);
 	spin_unlock_irqrestore(&c_data->cap_slock, flags);
 
 	if (atomic_read(&c_data->dev->vc_enabled) == 0) {
-
-		if (atomic_read(&q->queued_count) > 1)
+		if (atomic_read(&q->queued_count) >= c_data->vc_action.tot_buf)
 			if (vc_hw_kick_off(c_data) == 0)
 				atomic_set(&c_data->dev->vc_enabled, 1);
 	}
@@ -554,9 +553,9 @@
 
 	vc_stop_capture(c_data);
 
-	while (!list_empty(&c_data->vid_vc_action.active)) {
+	while (!list_empty(&c_data->vc_action.active)) {
 		struct vcap_buffer *buf;
-		buf = list_entry(c_data->vid_vc_action.active.next,
+		buf = list_entry(c_data->vc_action.active.next,
 			struct vcap_buffer, list);
 		list_del(&buf->list);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -617,7 +616,7 @@
 {
 	struct vcap_client_data *cd = vb2_get_drv_priv(vb->vb2_queue);
 	struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
-	struct vp_action *vp_act = &cd->vid_vp_action;
+	struct vp_action *vp_act = &cd->vp_action;
 	struct vb2_queue *q = vb->vb2_queue;
 	unsigned long flags = 0;
 
@@ -626,7 +625,7 @@
 	spin_unlock_irqrestore(&cd->cap_slock, flags);
 
 	if (atomic_read(&cd->dev->vp_enabled) == 0) {
-		if (cd->vid_vp_action.vp_state == VP_FRAME1) {
+		if (cd->vp_action.vp_state == VP_FRAME1) {
 			if (atomic_read(&q->queued_count) > 1 &&
 				atomic_read(&cd->vp_out_vidq.queued_count) > 0)
 				/* Valid code flow for VC-VP mode */
@@ -651,9 +650,9 @@
 
 	dprintk(2, "VP stop streaming\n");
 
-	while (!list_empty(&c_data->vid_vp_action.in_active)) {
+	while (!list_empty(&c_data->vp_action.in_active)) {
 		struct vcap_buffer *buf;
-		buf = list_entry(c_data->vid_vp_action.in_active.next,
+		buf = list_entry(c_data->vp_action.in_active.next,
 			struct vcap_buffer, list);
 		list_del(&buf->list);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -715,7 +714,7 @@
 {
 	struct vcap_client_data *cd = vb2_get_drv_priv(vb->vb2_queue);
 	struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
-	struct vp_action *vp_act = &cd->vid_vp_action;
+	struct vp_action *vp_act = &cd->vp_action;
 	struct vb2_queue *q = vb->vb2_queue;
 	unsigned long flags = 0;
 
@@ -724,7 +723,7 @@
 	spin_unlock_irqrestore(&cd->cap_slock, flags);
 
 	if (atomic_read(&cd->dev->vp_enabled) == 0) {
-		if (cd->vid_vp_action.vp_state == VP_FRAME1) {
+		if (cd->vp_action.vp_state == VP_FRAME1) {
 			if (atomic_read(&q->queued_count) > 0 &&
 				atomic_read(&
 					cd->vp_in_vidq.queued_count) > 1)
@@ -749,9 +748,9 @@
 	dprintk(2, "VP out q stop streaming\n");
 	vp_stop_capture(c_data);
 
-	while (!list_empty(&c_data->vid_vp_action.out_active)) {
+	while (!list_empty(&c_data->vp_action.out_active)) {
 		struct vcap_buffer *buf;
-		buf = list_entry(c_data->vid_vp_action.out_active.next,
+		buf = list_entry(c_data->vp_action.out_active.next,
 			struct vcap_buffer, list);
 		list_del(&buf->list);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -884,6 +883,7 @@
 			  struct v4l2_requestbuffers *rb)
 {
 	struct vcap_client_data *c_data = to_client_data(file->private_data);
+	struct vcap_dev *dev = c_data->dev;
 	int rc;
 
 	dprintk(3, "In Req Buf %08x\n", (unsigned int)rb->type);
@@ -905,7 +905,7 @@
 				pr_err("VCAP Err: VP No prog support\n");
 				return -ENOTRECOVERABLE;
 			}
-			if (rb->count < 6) {
+			if (rb->count <= VCAP_VP_MIN_BUF) {
 				pr_err("VCAP Err: Not enough buf for VC_VP\n");
 				return -EINVAL;
 			}
@@ -924,10 +924,13 @@
 			rb->type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
 			rc = vb2_reqbufs(&c_data->vp_in_vidq, rb);
 			rb->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			c_data->vc_action.tot_buf = dev->vc_tot_buf;
 			return rc;
 
 		} else {
-			return vb2_reqbufs(&c_data->vc_vidq, rb);
+			rc = vb2_reqbufs(&c_data->vc_vidq, rb);
+			c_data->vc_action.tot_buf = dev->vc_tot_buf;
+			return rc;
 		}
 	case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
 		return vb2_reqbufs(&c_data->vp_in_vidq, rb);
@@ -1219,13 +1222,13 @@
 		rc = init_motion_buf(c_data);
 		if (rc < 0)
 			goto free_res;
-		if (c_data->vid_vp_action.nr_param.mode) {
+		if (c_data->vp_action.nr_param.mode) {
 			rc = init_nr_buf(c_data);
 			if (rc < 0)
 				goto s_on_deinit_m_buf;
 		}
 
-		c_data->vid_vp_action.vp_state = VP_FRAME1;
+		c_data->vp_action.vp_state = VP_FRAME1;
 		c_data->streaming = 1;
 
 		rc = vb2_streamon(&c_data->vp_in_vidq,
@@ -1308,14 +1311,14 @@
 		if (rc < 0)
 			goto free_res;
 
-		if (c_data->vid_vp_action.nr_param.mode) {
+		if (c_data->vp_action.nr_param.mode) {
 			rc = init_nr_buf(c_data);
 			if (rc < 0)
 				goto s_on_deinit_m_buf;
 		}
 
 		c_data->dev->vc_to_vp_work.cd = c_data;
-		c_data->vid_vp_action.vp_state = VP_FRAME1;
+		c_data->vp_action.vp_state = VP_FRAME1;
 		c_data->streaming = 1;
 
 		/* These stream on calls should not fail */
@@ -1341,7 +1344,7 @@
 	return 0;
 
 s_on_deinit_nr_buf:
-	if (c_data->vid_vp_action.nr_param.mode)
+	if (c_data->vp_action.nr_param.mode)
 		deinit_nr_buf(c_data);
 s_on_deinit_m_buf:
 	deinit_motion_buf(c_data);
@@ -1436,7 +1439,7 @@
 			return rc;
 
 		deinit_motion_buf(c_data);
-		if (c_data->vid_vp_action.nr_param.mode)
+		if (c_data->vp_action.nr_param.mode)
 			deinit_nr_buf(c_data);
 		atomic_set(&c_data->dev->vp_enabled, 0);
 		return rc;
@@ -1484,7 +1487,7 @@
 			return rc;
 
 		deinit_motion_buf(c_data);
-		if (c_data->vid_vp_action.nr_param.mode)
+		if (c_data->vp_action.nr_param.mode)
 			deinit_nr_buf(c_data);
 		atomic_set(&c_data->dev->vc_enabled, 0);
 		atomic_set(&c_data->dev->vp_enabled, 0);
@@ -1535,7 +1538,9 @@
 						int cmd, void *arg)
 {
 	struct vcap_client_data *c_data = to_client_data(file->private_data);
+	struct vcap_dev *dev = c_data->dev;
 	struct nr_param *param;
+	int	val;
 	unsigned long flags = 0;
 	int ret;
 
@@ -1544,7 +1549,7 @@
 
 		if (c_data->streaming != 0 &&
 				(!(!((struct nr_param *) arg)->mode) !=
-				!(!(c_data->vid_vp_action.nr_param.mode)))) {
+				!(!(c_data->vp_action.nr_param.mode)))) {
 			pr_err("ERR: Trying to toggle on/off while VP is already running");
 			return -EBUSY;
 		}
@@ -1557,22 +1562,28 @@
 			return ret;
 		}
 		param = (struct nr_param *) arg;
-		c_data->vid_vp_action.nr_param = *param;
+		c_data->vp_action.nr_param = *param;
 		if (param->mode == NR_AUTO)
-			s_default_nr_val(&c_data->vid_vp_action.nr_param);
-		c_data->vid_vp_action.nr_update = true;
+			s_default_nr_val(&c_data->vp_action.nr_param);
+		c_data->vp_action.nr_update = true;
 		spin_unlock_irqrestore(&c_data->cap_slock, flags);
 		break;
 	case VCAPIOC_NR_G_PARAMS:
-		*((struct nr_param *)arg) = c_data->vid_vp_action.nr_param;
-		if (c_data->vid_vp_action.nr_param.mode != NR_DISABLE) {
+		*((struct nr_param *)arg) = c_data->vp_action.nr_param;
+		if (c_data->vp_action.nr_param.mode != NR_DISABLE) {
 			if (c_data->streaming)
 				nr_g_param(c_data, (struct nr_param *) arg);
 			else
 				(*(struct nr_param *) arg) =
-					c_data->vid_vp_action.nr_param;
+					c_data->vp_action.nr_param;
 		}
 		break;
+	case VCAPIOC_S_NUM_VC_BUF:
+		val = (*(int *) arg);
+		if (val < VCAP_VC_MIN_BUF || val > VCAP_VC_MAX_BUF)
+			return -EINVAL;
+		dev->vc_tot_buf = (uint8_t) val;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1658,9 +1669,9 @@
 	if (ret < 0)
 		goto vp_out_q_failed;
 
-	INIT_LIST_HEAD(&c_data->vid_vc_action.active);
-	INIT_LIST_HEAD(&c_data->vid_vp_action.in_active);
-	INIT_LIST_HEAD(&c_data->vid_vp_action.out_active);
+	INIT_LIST_HEAD(&c_data->vc_action.active);
+	INIT_LIST_HEAD(&c_data->vp_action.in_active);
+	INIT_LIST_HEAD(&c_data->vp_action.out_active);
 
 	v4l2_fh_init(&c_data->vfh, dev->vfd);
 	v4l2_fh_add(&c_data->vfh);
@@ -1722,6 +1733,7 @@
 	mutex_unlock(&dev->dev_mutex);
 	if (ret == 0) {
 		vcap_disable(dev);
+		dev->vc_tot_buf = 2;
 		dev->vp_dummy_complete = false;
 	}
 	v4l2_fh_del(&c_data->vfh);
@@ -1963,6 +1975,7 @@
 		goto rel_vcap_wq;
 	}
 
+	dev->vc_tot_buf = 2;
 	atomic_set(&dev->vc_enabled, 0);
 	atomic_set(&dev->vp_enabled, 0);
 	atomic_set(&dev->open_clients, 0);
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 966fa4b..1825352 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -107,14 +107,30 @@
 	}
 }
 
+static uint8_t correct_buf_num(uint32_t reg)
+{
+	int i;
+	bool block_found = false;
+	for (i = 0; i < VCAP_VC_MAX_BUF; i++) {
+		if (reg & (0x2 << i)) {
+			block_found = true;
+			continue;
+		}
+		if (block_found)
+			return i;
+	}
+	return 0;
+}
+
 irqreturn_t vc_handler(struct vcap_dev *dev)
 {
 	uint32_t irq, timestamp;
-	enum rdy_buf vc_buf_status, buf_ind;
 	struct vcap_buffer *buf;
 	struct vb2_buffer *vb = NULL;
 	struct vcap_client_data *c_data;
 	struct v4l2_event v4l2_evt;
+	uint8_t i, idx, buf_num, tot, done_count = 0;
+	bool work_todo = false;
 
 	irq = readl_relaxed(VCAP_VC_INT_STATUS);
 
@@ -154,106 +170,75 @@
 		v4l2_event_queue(dev->vfd, &v4l2_evt);
 	}
 
-	vc_buf_status = irq & VC_BUFFER_WRITTEN;
-	dprintk(1, "Done buf status = %d\n", vc_buf_status);
-
-	if (vc_buf_status == VC_NO_BUF) {
+	if (!(irq & VC_BUFFER_MASK)) {
 		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
 		pr_err("VC IRQ shows some error\n");
 		return IRQ_HANDLED;
 	}
 
 	if (dev->vc_client == NULL) {
+		/* This should never happen */
 		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
 		pr_err("VC: There is no active vc client\n");
 		return IRQ_HANDLED;
 	}
+	c_data = dev->vc_client;
 
-	spin_lock(&dev->vc_client->cap_slock);
-	if (list_empty(&dev->vc_client->vid_vc_action.active)) {
-		/* Just leave we have no new queued buffers */
-		spin_unlock(&dev->vc_client->cap_slock);
-		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
-			VCAP_VC_BUF_OVERWRITE_EVENT;
-		v4l2_event_queue(dev->vfd, &v4l2_evt);
-		dprintk(1, "We have no more avilable buffers\n");
-		return IRQ_HANDLED;
+	for (i = 0; i < VCAP_VC_MAX_BUF; i++) {
+		if (0x2 & (irq >> i))
+			done_count++;
 	}
-	spin_unlock(&dev->vc_client->cap_slock);
 
+	/* Double check expected buffers are done */
+	buf_num = c_data->vc_action.buf_num;
+	tot = c_data->vc_action.tot_buf;
+	for (i = 0; i < done_count; i++) {
+		if (!(irq & (0x1 << (((buf_num + i) % tot) + 1)))) {
+			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+				VCAP_VC_UNEXPECT_BUF_DONE;
+			v4l2_event_queue(dev->vfd, &v4l2_evt);
+			pr_debug("Unexpected buffer done\n");
+			c_data->vc_action.buf_num =
+				correct_buf_num(irq) % tot;
+			writel_relaxed(irq, VCAP_VC_INT_CLEAR);
+			return IRQ_HANDLED;
+		}
+	}
+
+	/* If here we know which buffers are done */
 	timestamp = readl_relaxed(VCAP_VC_TIMESTAMP);
 
-	buf_ind = dev->vc_client->vid_vc_action.buf_ind;
-
-	if (vc_buf_status == VC_BUF1N2) {
-		/* There are 2 buffer ready */
-		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-		return IRQ_HANDLED;
-	} else if (buf_ind != vc_buf_status) {
-		/* buffer is out of sync */
-		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-		return IRQ_HANDLED;
-	}
-
-	if (buf_ind == VC_BUF1) {
-		dprintk(1, "Got BUF1\n");
-		vb = &dev->vc_client->vid_vc_action.buf1->vb;
-		spin_lock(&dev->vc_client->cap_slock);
-		if (list_empty(&dev->vc_client->vid_vc_action.active)) {
-			spin_unlock(&dev->vc_client->cap_slock);
+	c_data->vc_action.buf_num = (buf_num + done_count) % tot;
+	for (i = 0; i < done_count; i++) {
+		idx = (buf_num + i) % tot;
+		vb = &c_data->vc_action.buf[idx]->vb;
+		spin_lock(&c_data->cap_slock);
+		if (list_empty(&c_data->vc_action.active)) {
+			spin_unlock(&c_data->cap_slock);
 			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
 				VCAP_VC_BUF_OVERWRITE_EVENT;
 			v4l2_event_queue(dev->vfd, &v4l2_evt);
-			writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-			return IRQ_HANDLED;
+			continue;
 		}
-		buf = list_entry(dev->vc_client->vid_vc_action.active.next,
+		buf = list_entry(c_data->vc_action.active.next,
 				struct vcap_buffer, list);
 		list_del(&buf->list);
-		spin_unlock(&dev->vc_client->cap_slock);
+		spin_unlock(&c_data->cap_slock);
 		/* Config vc with this new buffer */
-		config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1,
-				VCAP_VC_C_ADDR_1);
-
-		vb->v4l2_buf.timestamp.tv_usec = timestamp;
+		config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1 + 0x8 * idx,
+				VCAP_VC_C_ADDR_1 + 0x8 * idx);
+		vb->v4l2_buf.timestamp.tv_usec = timestamp -
+			1000000 / c_data->vc_format.frame_rate *
+			(done_count - 1 - i);
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-		dev->vc_client->vid_vc_action.buf1 = buf;
-		dev->vc_client->vid_vc_action.buf_ind = VC_BUF2;
-		irq = VC_BUF1;
-	} else {
-		dprintk(1, "Got BUF2\n");
-		spin_lock(&dev->vc_client->cap_slock);
-		vb = &dev->vc_client->vid_vc_action.buf2->vb;
-		if (list_empty(&dev->vc_client->vid_vc_action.active)) {
-			spin_unlock(&dev->vc_client->cap_slock);
-			writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
-				VCAP_VC_BUF_OVERWRITE_EVENT;
-			v4l2_event_queue(dev->vfd, &v4l2_evt);
-			return IRQ_HANDLED;
-		}
-		buf = list_entry(dev->vc_client->vid_vc_action.active.next,
-						 struct vcap_buffer, list);
-		list_del(&buf->list);
-		spin_unlock(&dev->vc_client->cap_slock);
-		/* Config vc with this new buffer */
-		config_buffer(c_data, buf, VCAP_VC_Y_ADDR_2,
-				VCAP_VC_C_ADDR_2);
-
-		vb->v4l2_buf.timestamp.tv_usec = timestamp;
-		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-
-		dev->vc_client->vid_vc_action.buf2 = buf;
-		dev->vc_client->vid_vc_action.buf_ind = VC_BUF1;
-		irq = VC_BUF2;
+		work_todo = true;
+		c_data->vc_action.buf[idx] = buf;
 	}
 
-	if (c_data->op_mode == VC_AND_VP_VCAP_OP)
+	if (work_todo && c_data->op_mode == VC_AND_VP_VCAP_OP)
 		queue_work(dev->vcap_wq, &dev->vc_to_vp_work.work);
 
 	writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-
 	return IRQ_HANDLED;
 }
 
@@ -264,58 +249,59 @@
 
 int vc_hw_kick_off(struct vcap_client_data *c_data)
 {
-	struct vcap_action *vid_vc_action = &c_data->vid_vc_action;
+	struct vc_action *vc_action = &c_data->vc_action;
 	struct vcap_dev *dev;
 	unsigned long flags = 0;
-	int rc, counter = 0;
+	int rc, i, counter = 0;
 	struct vcap_buffer *buf;
 
 	dev = c_data->dev;
-	vid_vc_action->buf_ind = VC_BUF1;
 	dprintk(2, "Start Kickoff\n");
 
 	if (dev->vc_client == NULL) {
 		pr_err("No active vc client\n");
 		return -ENODEV;
 	}
+	c_data->vc_action.buf_num = 0;
 	spin_lock_irqsave(&dev->vc_client->cap_slock, flags);
-	if (list_empty(&dev->vc_client->vid_vc_action.active)) {
+	if (list_empty(&dev->vc_client->vc_action.active)) {
 		spin_unlock_irqrestore(&dev->vc_client->cap_slock, flags);
 		pr_err("%s: VC We have no more avilable buffers\n",
 				__func__);
 		return -EINVAL;
 	}
 
-	list_for_each_entry(buf, &vid_vc_action->active, list)
+	list_for_each_entry(buf, &vc_action->active, list)
 		counter++;
 
-	if (counter < 2) {
+	if (counter < c_data->vc_action.tot_buf) {
 		/* not enough buffers have been queued */
 		spin_unlock_irqrestore(&dev->vc_client->cap_slock, flags);
 		return -EINVAL;
 	}
 
-	vid_vc_action->buf1 = list_entry(vid_vc_action->active.next,
+	for (i = 0; i < c_data->vc_action.tot_buf; i++) {
+		vc_action->buf[i] = list_entry(vc_action->active.next,
 			struct vcap_buffer, list);
-	list_del(&vid_vc_action->buf1->list);
-
-	vid_vc_action->buf2 = list_entry(vid_vc_action->active.next,
-			struct vcap_buffer, list);
-	list_del(&vid_vc_action->buf2->list);
-
+		list_del(&vc_action->buf[i]->list);
+	}
 	spin_unlock_irqrestore(&dev->vc_client->cap_slock, flags);
 
-	config_buffer(c_data, vid_vc_action->buf1, VCAP_VC_Y_ADDR_1,
-			VCAP_VC_C_ADDR_1);
-	config_buffer(c_data, vid_vc_action->buf2, VCAP_VC_Y_ADDR_2,
-			VCAP_VC_C_ADDR_2);
+	for (i = 0; i < c_data->vc_action.tot_buf; i++) {
+		config_buffer(c_data, vc_action->buf[i],
+			VCAP_VC_Y_ADDR_1 + i * 8,
+			VCAP_VC_C_ADDR_1 + i * 8);
+	}
 
+	rc = 0;
+	for (i = 0; i < c_data->vc_action.tot_buf; i++)
+		rc = rc << 1 | 0x2;
+	writel_relaxed(rc, VCAP_VC_INT_MASK);
+
+	enable_irq(dev->vcirq->start);
 	rc = readl_relaxed(VCAP_VC_CTRL);
 	writel_iowmb(rc | 0x1, VCAP_VC_CTRL);
 
-	writel_relaxed(0x6, VCAP_VC_INT_MASK);
-
-	enable_irq(dev->vcirq->start);
 	return 0;
 }
 
@@ -383,7 +369,9 @@
 	writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
 	writel_iowmb(0x00000004 | vc_format->color_space << 1 |
 			vc_format->mode << 3 |
-			vc_format->mode << 10, VCAP_VC_CTRL);
+			(c_data->vc_action.tot_buf - 2) << 4 |
+			vc_format->mode << 10,
+			VCAP_VC_CTRL);
 
 	writel_relaxed(vc_format->h_polar << 4 |
 			vc_format->v_polar << 0, VCAP_VC_POLARITY);
diff --git a/drivers/media/video/vcap_vc.h b/drivers/media/video/vcap_vc.h
index 76693bb..7f42c7f 100644
--- a/drivers/media/video/vcap_vc.h
+++ b/drivers/media/video/vcap_vc.h
@@ -62,6 +62,7 @@
 #define VCAP_VC_TIMESTAMP (VCAP_BASE + 0x0034)
 
 #define VC_BUFFER_WRITTEN (0x3 << 1)
+#define VC_BUFFER_MASK 0x7E
 
 int vc_start_capture(struct vcap_client_data *c_data);
 int vc_hw_kick_off(struct vcap_client_data *c_data);
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index f8f27d4..12b3208 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -81,7 +81,7 @@
 	}
 
 	/* No need to verify vp_client is not NULL caller does so */
-	vp_act = &dev->vp_client->vid_vp_action;
+	vp_act = &dev->vp_client->vp_action;
 
 	spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
 	if (list_empty(&vp_act->in_active)) {
@@ -173,7 +173,7 @@
 {
 	struct vcap_dev *dev = c_data->dev;
 	struct nr_param *par;
-	par = &c_data->vid_vp_action.nr_param;
+	par = &c_data->vp_action.nr_param;
 	if (par->mode == NR_MANUAL) {
 		writel_relaxed(par->window << 24 | par->decay_ratio << 20,
 			VCAP_VP_NR_CONFIG);
@@ -190,7 +190,7 @@
 			par->chroma.blend_limit_ratio << 0,
 			VCAP_VP_NR_CHROMA_CONFIG);
 	}
-	c_data->vid_vp_action.nr_update = false;
+	c_data->vp_action.nr_update = false;
 }
 
 static void vp_wq_fnc(struct work_struct *work)
@@ -210,7 +210,7 @@
 	else
 		return;
 
-	vp_act = &dev->vp_client->vid_vp_action;
+	vp_act = &dev->vp_client->vp_action;
 
 	rc = readl_relaxed(VCAP_OFFSET(0x048));
 	while (!(rc & 0x00000100))
@@ -244,7 +244,7 @@
 #endif
 
 	/* Cycle Buffers*/
-	if (vp_work->cd->vid_vp_action.nr_param.mode) {
+	if (vp_work->cd->vp_action.nr_param.mode) {
 		if (vp_act->bufNR.nr_pos == TM1_BUF)
 			vp_act->bufNR.nr_pos = BUF_NOT_IN_USE;
 
@@ -340,7 +340,7 @@
 		return IRQ_HANDLED;
 	}
 
-	vp_act = &dev->vp_client->vid_vp_action;
+	vp_act = &dev->vp_client->vp_action;
 	c_data = dev->vp_client;
 
 	if (vp_act->vp_state == VP_UNKNOWN) {
@@ -467,7 +467,7 @@
 	size_t size = ((c_data->vp_out_fmt.width + 63) >> 6) *
 		((c_data->vp_out_fmt.height + 7) >> 3) * 16;
 
-	if (c_data->vid_vp_action.motionHandle) {
+	if (c_data->vp_action.motionHandle) {
 		pr_err("Motion buffer has already been created");
 		return -ENOEXEC;
 	}
@@ -501,7 +501,7 @@
 	}
 
 	memset(vaddr, 0, size);
-	c_data->vid_vp_action.motionHandle = handle;
+	c_data->vp_action.motionHandle = handle;
 
 	vaddr = NULL;
 	ion_unmap_kernel(dev->ion_client, handle);
@@ -513,14 +513,14 @@
 void deinit_motion_buf(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
-	if (!c_data->vid_vp_action.motionHandle) {
+	if (!c_data->vp_action.motionHandle) {
 		pr_err("Motion buffer has not been created");
 		return;
 	}
 
 	writel_iowmb(0x00000000, VCAP_VP_MOTION_EST_ADDR);
-	ion_free(dev->ion_client, c_data->vid_vp_action.motionHandle);
-	c_data->vid_vp_action.motionHandle = NULL;
+	ion_free(dev->ion_client, c_data->vp_action.motionHandle);
+	c_data->vp_action.motionHandle = NULL;
 	return;
 }
 
@@ -532,7 +532,7 @@
 	unsigned long paddr;
 	int rc;
 
-	if (c_data->vid_vp_action.bufNR.nr_handle) {
+	if (c_data->vp_action.bufNR.nr_handle) {
 		pr_err("NR buffer has already been created");
 		return -ENOEXEC;
 	}
@@ -557,16 +557,16 @@
 		return rc;
 	}
 
-	c_data->vid_vp_action.bufNR.nr_handle = handle;
+	c_data->vp_action.bufNR.nr_handle = handle;
 	update_nr_value(c_data);
 
-	c_data->vid_vp_action.bufNR.paddr = paddr;
+	c_data->vp_action.bufNR.paddr = paddr;
 	rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
 	rc |= (((c_data->vp_out_fmt.width / 16) << 20) | 0x1);
 	writel_relaxed(rc, VCAP_VP_NR_CONFIG2);
 	writel_relaxed(paddr, VCAP_VP_NR_T2_Y_BASE_ADDR);
 	writel_relaxed(paddr + frame_size, VCAP_VP_NR_T2_C_BASE_ADDR);
-	c_data->vid_vp_action.bufNR.nr_pos = NRT2_BUF;
+	c_data->vp_action.bufNR.nr_pos = NRT2_BUF;
 	return 0;
 }
 
@@ -576,11 +576,11 @@
 	struct nr_buffer *buf;
 	uint32_t rc;
 
-	if (!c_data->vid_vp_action.bufNR.nr_handle) {
+	if (!c_data->vp_action.bufNR.nr_handle) {
 		pr_err("NR buffer has not been created");
 		return;
 	}
-	buf = &c_data->vid_vp_action.bufNR;
+	buf = &c_data->vp_action.bufNR;
 
 	rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
 	rc &= !(0x0FF00001);
@@ -757,7 +757,7 @@
 		pr_err("No active vp client\n");
 		return -ENODEV;
 	}
-	vp_act = &dev->vp_client->vid_vp_action;
+	vp_act = &dev->vp_client->vp_action;
 
 	spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
 	if (list_empty(&vp_act->in_active)) {
@@ -854,7 +854,7 @@
 		pr_err("No active vp client\n");
 		return -ENODEV;
 	}
-	vp_act = &dev->vp_client->vid_vp_action;
+	vp_act = &dev->vp_client->vp_action;
 
 	if (vp_act->vp_state == VP_UNKNOWN) {
 		pr_err("%s: VP is in an unknown state\n",
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 00e0375..2641720 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -27,7 +27,8 @@
 #define VCAP_VP_REG_W_ERR_EVENT 8
 #define VCAP_VP_IN_HEIGHT_ERR_EVENT 9
 #define VCAP_VP_IN_WIDTH_ERR_EVENT 10
-#define VCAP_MAX_NOTIFY_EVENT 11
+#define VCAP_VC_UNEXPECT_BUF_DONE 11
+#define VCAP_MAX_NOTIFY_EVENT 12
 
 enum hal_vcap_mode {
 	HAL_VCAP_MODE_PRO = 0,
@@ -80,6 +81,7 @@
 #define VCAPIOC_NR_S_PARAMS _IOWR('V', (BASE_VIDIOC_PRIVATE+0), struct nr_param)
 
 #define VCAPIOC_NR_G_PARAMS _IOWR('V', (BASE_VIDIOC_PRIVATE+1), struct nr_param)
+#define VCAPIOC_S_NUM_VC_BUF _IOWR('V', (BASE_VIDIOC_PRIVATE+2), int)
 
 struct v4l2_format_vc_ext {
 	enum hal_vcap_mode     mode;
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index d56e534..81f7922 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -44,15 +44,11 @@
 #define VCAP_SW_RESET_REQ (VCAP_BASE + 0x024)
 #define VCAP_SW_RESET_STATUS (VCAP_BASE + 0x028)
 
+#define VCAP_VP_MIN_BUF 4
+#define VCAP_VC_MAX_BUF 6
+#define VCAP_VC_MIN_BUF 2
 struct vcap_client_data;
 
-enum rdy_buf {
-	VC_NO_BUF = 0,
-	VC_BUF1 = 1 << 1,
-	VC_BUF2 = 1 << 2,
-	VC_BUF1N2 = 0x11 << 1,
-};
-
 enum vp_state {
 	VP_UNKNOWN = 0,
 	VP_FRAME1,
@@ -81,23 +77,18 @@
 	VC_AND_VP_VCAP_OP,
 };
 
-struct vcap_action {
+struct vc_action {
 	struct list_head		active;
 
 	/* thread for generating video stream*/
-	struct task_struct		*kthread;
 	wait_queue_head_t		wq;
 
 	/* Buffer index */
-	enum rdy_buf            buf_ind;
+	uint8_t					tot_buf;
+	uint8_t					buf_num;
 
 	/* Buffers inside vc */
-	struct vcap_buffer      *buf1;
-	struct vcap_buffer      *buf2;
-
-	/* Counters to control fps rate */
-	int						frame;
-	int						ini_jiffies;
+	struct vcap_buffer      *buf[6];
 };
 
 struct nr_buffer {
@@ -176,6 +167,8 @@
 	bool					vp_shutdown;
 	wait_queue_head_t		vp_dummy_waitq;
 
+	uint8_t					vc_tot_buf;
+
 	struct workqueue_struct	*vcap_wq;
 	struct vp_work_t		vp_work;
 	struct vp_work_t		vc_to_vp_work;
@@ -211,8 +204,8 @@
 	struct vp_format_data	vp_in_fmt;
 	struct vp_format_data	vp_out_fmt;
 
-	struct vcap_action		vid_vc_action;
-	struct vp_action		vid_vp_action;
+	struct vc_action		vc_action;
+	struct vp_action		vp_action;
 	struct workqueue_struct *vcap_work_q;
 	struct ion_handle			*vc_ion_handle;