msm: camera: support output-duplication in cpp

If two streams need same output buffer from cpp, duplication
functionality from cpp hardware can be used. This elminates need for
redundant 2-pass processing.

Change-Id: I672362360472fe9485acebc6abef89ba8a587b72
Signed-off-by: Punit Soni <punits@codeaurora.org>
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index df166ef..4dd3f3d 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -43,6 +43,9 @@
 
 #define CONFIG_MSM_CPP_DBG 0
 
+/* dump the frame command before writing to the hardware */
+#define  MSM_CPP_DUMP_FRM_CMD 0
+
 #if CONFIG_MSM_CPP_DBG
 #define CPP_DBG(fmt, args...) pr_err(fmt, ##args)
 #else
@@ -897,8 +900,7 @@
 		event_qcmd->command = processed_frame;
 		CPP_DBG("fid %d\n", processed_frame->frame_id);
 		msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
-
-		if (!processed_frame->output_buffer_info.processed_divert) {
+		if (!processed_frame->output_buffer_info[0].processed_divert) {
 			memset(&buff_mgr_info, 0 ,
 				sizeof(struct msm_buf_mngr_info));
 			buff_mgr_info.session_id =
@@ -908,7 +910,7 @@
 			buff_mgr_info.frame_id = processed_frame->frame_id;
 			buff_mgr_info.timestamp = processed_frame->timestamp;
 			buff_mgr_info.index =
-				processed_frame->output_buffer_info.index;
+				processed_frame->output_buffer_info[0].index;
 			rc = msm_cpp_buffer_ops(cpp_dev,
 				VIDIOC_MSM_BUF_MNGR_BUF_DONE,
 				&buff_mgr_info);
@@ -917,6 +919,28 @@
 				rc = -EINVAL;
 			}
 		}
+
+		if (processed_frame->duplicate_output  &&
+			!processed_frame->
+				output_buffer_info[1].processed_divert) {
+			memset(&buff_mgr_info, 0 ,
+				sizeof(struct msm_buf_mngr_info));
+			buff_mgr_info.session_id =
+			((processed_frame->duplicate_identity >> 16) & 0xFFFF);
+			buff_mgr_info.stream_id =
+				(processed_frame->duplicate_identity & 0xFFFF);
+			buff_mgr_info.frame_id = processed_frame->frame_id;
+			buff_mgr_info.timestamp = processed_frame->timestamp;
+			buff_mgr_info.index =
+				processed_frame->output_buffer_info[1].index;
+			rc = msm_cpp_buffer_ops(cpp_dev,
+				VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+					&buff_mgr_info);
+			if (rc < 0) {
+				pr_err("error putting buffer\n");
+				rc = -EINVAL;
+			}
+		}
 		v4l2_evt.id = processed_frame->inst_id;
 		v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
 		v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
@@ -924,6 +948,23 @@
 	return rc;
 }
 
+#if MSM_CPP_DUMP_FRM_CMD
+static int msm_cpp_dump_frame_cmd(uint32_t *cmd, int32_t len)
+{
+	int i;
+	pr_err("%s: -------- cpp frame cmd msg start --------", __func__);
+	for (i = 0; i < len; i++)
+		pr_err("%s: msg[%03d] = 0x%08x", __func__, i, cmd[i]);
+	pr_err("%s: --------- cpp frame cmd msg end ---------", __func__);
+	return 0;
+}
+#else
+static int msm_cpp_dump_frame_cmd(uint32_t *cmd, int32_t len)
+{
+	return 0;
+}
+#endif
+
 static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
 	struct msm_queue_cmd *frame_qcmd)
 {
@@ -936,6 +977,8 @@
 		msm_enqueue(&cpp_dev->processing_q,
 					&frame_qcmd->list_frame);
 		msm_cpp_write(0x6, cpp_dev->base);
+		msm_cpp_dump_frame_cmd(process_frame->cpp_cmd_msg,
+				process_frame->msg_len);
 		for (i = 0; i < process_frame->msg_len; i++)
 			msm_cpp_write(process_frame->cpp_cmd_msg[i],
 				cpp_dev->base);
@@ -960,7 +1003,7 @@
 	struct msm_cpp_frame_info_t *new_frame =
 		kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL);
 	uint32_t *cpp_frame_msg;
-	unsigned long in_phyaddr, out_phyaddr;
+	unsigned long in_phyaddr, out_phyaddr0, out_phyaddr1;
 	uint16_t num_stripes = 0;
 	struct msm_buf_mngr_info buff_mgr_info;
 	struct msm_cpp_frame_info_t *u_frame_info =
@@ -1010,7 +1053,7 @@
 		goto ERROR2;
 	}
 
-	memset(&new_frame->output_buffer_info, 0,
+	memset(&new_frame->output_buffer_info[0], 0,
 		sizeof(struct msm_cpp_buffer_info_t));
 	memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
 	buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
@@ -1022,17 +1065,49 @@
 		pr_debug("error getting buffer rc:%d\n", rc);
 		goto ERROR2;
 	}
-
-	new_frame->output_buffer_info.index = buff_mgr_info.index;
-	out_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
-		&new_frame->output_buffer_info,
+	new_frame->output_buffer_info[0].index = buff_mgr_info.index;
+	out_phyaddr0 = msm_cpp_fetch_buffer_info(cpp_dev,
+		&new_frame->output_buffer_info[0],
 		((new_frame->identity >> 16) & 0xFFFF),
 		(new_frame->identity & 0xFFFF));
-	if (!out_phyaddr) {
+	if (!out_phyaddr0) {
 		pr_err("error gettting output physical address\n");
 		rc = -EINVAL;
 		goto ERROR3;
 	}
+	out_phyaddr1 = out_phyaddr0;
+
+	/* get buffer for duplicate output */
+	if (new_frame->duplicate_output) {
+		CPP_DBG("duplication enabled, dup_id=0x%x",
+			new_frame->duplicate_identity);
+		memset(&new_frame->output_buffer_info[1], 0,
+			sizeof(struct msm_cpp_buffer_info_t));
+		memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+		buff_mgr_info.session_id =
+			((new_frame->duplicate_identity >> 16) & 0xFFFF);
+		buff_mgr_info.stream_id =
+			(new_frame->duplicate_identity & 0xFFFF);
+		rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
+			&buff_mgr_info);
+		if (rc < 0) {
+			rc = -EAGAIN;
+			pr_err("error getting buffer rc:%d\n", rc);
+			goto ERROR2;
+		}
+		new_frame->output_buffer_info[1].index = buff_mgr_info.index;
+		out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev,
+			&new_frame->output_buffer_info[1],
+			((new_frame->duplicate_identity >> 16) & 0xFFFF),
+			(new_frame->duplicate_identity & 0xFFFF));
+		if (!out_phyaddr1) {
+			pr_err("error gettting output physical address\n");
+			rc = -EINVAL;
+			goto ERROR3;
+		}
+		/* set duplicate enable bit */
+		cpp_frame_msg[5] |= 0x1;
+	}
 
 	num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) +
 		((cpp_frame_msg[12] >> 10) & 0x3FF) +
@@ -1040,10 +1115,10 @@
 
 	for (i = 0; i < num_stripes; i++) {
 		cpp_frame_msg[133 + i * 27] += (uint32_t) in_phyaddr;
-		cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr;
-		cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr;
-		cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr;
-		cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr;
+		cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr0;
+		cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr1;
+		cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr0;
+		cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr1;
 	}
 
 	frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index aead2d2..6cd4995 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -112,9 +112,10 @@
 	struct timeval in_time, out_time;
 	void *cookie;
 	int32_t *status;
-
+	int32_t duplicate_output;
+	uint32_t duplicate_identity;
 	struct msm_cpp_buffer_info_t input_buffer_info;
-	struct msm_cpp_buffer_info_t output_buffer_info;
+	struct msm_cpp_buffer_info_t output_buffer_info[2];
 };
 
 struct cpp_hw_info {