msm: vidc: enable mark_data feature

Use v4l2_buffer.m.planes[0].reserved[3,4] to pass
mark_data and mark_target with userspace.
Use 2 lists to store and pass mark_data between
v4l2_buffer and HFI.

CRs-fixed: 2099825
Change-Id: I2102b80a81041a6283061bcf320de9a21b373156
Signed-off-by: Qiwei Liu <qiweil@codeaurora.org>
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 920e91a..c5d3a4a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -510,6 +510,12 @@
 		msm_comm_update_input_cr(inst, b->index, cr);
 	}
 
+	if (inst->session_type == MSM_VIDC_DECODER &&
+			b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		msm_comm_store_mark_data(&inst->etb_data, b->index,
+			b->m.planes[0].reserved[3], b->m.planes[0].reserved[4]);
+	}
+
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
 		dprintk(VIDC_ERR,
@@ -562,6 +568,13 @@
 		b->m.planes[i].reserved[1] = b->m.planes[i].data_offset;
 	}
 
+	if (inst->session_type == MSM_VIDC_DECODER &&
+			b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		msm_comm_fetch_mark_data(&inst->fbd_data, b->index,
+			&b->m.planes[0].reserved[3],
+			&b->m.planes[0].reserved[4]);
+	}
+
 	return rc;
 }
 EXPORT_SYMBOL(msm_vidc_dqbuf);
@@ -1566,6 +1579,8 @@
 	INIT_MSM_VIDC_LIST(&inst->registeredbufs);
 	INIT_MSM_VIDC_LIST(&inst->reconbufs);
 	INIT_MSM_VIDC_LIST(&inst->eosbufs);
+	INIT_MSM_VIDC_LIST(&inst->etb_data);
+	INIT_MSM_VIDC_LIST(&inst->fbd_data);
 
 	kref_init(&inst->kref);
 
@@ -1673,6 +1688,8 @@
 	DEINIT_MSM_VIDC_LIST(&inst->eosbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->freqs);
 	DEINIT_MSM_VIDC_LIST(&inst->input_crs);
+	DEINIT_MSM_VIDC_LIST(&inst->etb_data);
+	DEINIT_MSM_VIDC_LIST(&inst->fbd_data);
 
 	kfree(inst);
 	inst = NULL;
@@ -1716,6 +1733,10 @@
 		dprintk(VIDC_ERR,
 			"Failed to release persist buffers\n");
 
+	if (msm_comm_release_mark_data(inst))
+		dprintk(VIDC_ERR,
+			"Failed to release mark_data buffers\n");
+
 	/*
 	 * At this point all buffes should be with driver
 	 * irrespective of scenario
@@ -1771,6 +1792,8 @@
 	DEINIT_MSM_VIDC_LIST(&inst->eosbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->freqs);
 	DEINIT_MSM_VIDC_LIST(&inst->input_crs);
+	DEINIT_MSM_VIDC_LIST(&inst->etb_data);
+	DEINIT_MSM_VIDC_LIST(&inst->fbd_data);
 
 	mutex_destroy(&inst->sync_lock);
 	mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 8fd1dd1..bcbd986 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2569,6 +2569,11 @@
 	}
 	vb->timestamp = (time_usec * NSEC_PER_USEC);
 
+	if (inst->session_type == MSM_VIDC_DECODER) {
+		msm_comm_store_mark_data(&inst->fbd_data, vb->index,
+			fill_buf_done->mark_data, fill_buf_done->mark_target);
+	}
+
 	extra_idx = EXTRADATA_IDX(inst->bufq[CAPTURE_PORT].num_planes);
 	if (extra_idx && extra_idx < VIDEO_MAX_PLANES)
 		vb->planes[extra_idx].bytesused = vb->planes[extra_idx].length;
@@ -3955,9 +3960,6 @@
 	data->clnt_data = data->device_addr;
 
 	if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-		bool pic_decoding_mode = msm_comm_g_ctrl_for_id(inst,
-				V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE);
-
 		data->buffer_type = HAL_BUFFER_INPUT;
 		data->filled_len = vb->planes[0].bytesused;
 		data->offset = vb->planes[0].data_offset;
@@ -3974,13 +3976,10 @@
 		if (vbuf->flags & V4L2_QCOM_BUF_TIMESTAMP_INVALID)
 			data->timestamp = LLONG_MAX;
 
-		/* XXX: This is a dirty hack necessitated by the firmware,
-		 * which refuses to issue FBDs for non I-frames in Picture Type
-		 * Decoding mode, unless we pass in non-zero value in mark_data
-		 * and mark_target.
-		 */
-		data->mark_data = data->mark_target =
-			pic_decoding_mode ? 0xdeadbeef : 0;
+		if (inst->session_type == MSM_VIDC_DECODER) {
+			msm_comm_fetch_mark_data(&inst->etb_data, vb->index,
+				&data->mark_data, &data->mark_target);
+		}
 
 	} else if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		data->buffer_type = msm_comm_get_hal_output_buffer(inst);
@@ -6610,3 +6609,93 @@
 	return ret;
 }
 
+void msm_comm_store_mark_data(struct msm_vidc_list *data_list,
+		u32 index, u32 mark_data, u32 mark_target)
+{
+	struct msm_vidc_buf_data *pdata = NULL;
+	bool found = false;
+
+	if (!data_list) {
+		dprintk(VIDC_ERR, "%s: invalid params %pK\n",
+			__func__, data_list);
+		return;
+	}
+
+	mutex_lock(&data_list->lock);
+	list_for_each_entry(pdata, &data_list->list, list) {
+		if (pdata->index == index) {
+			pdata->mark_data = mark_data;
+			pdata->mark_target = mark_target;
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+		if (!pdata)  {
+			dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__);
+			goto exit;
+		}
+		pdata->index = index;
+		pdata->mark_data = mark_data;
+		pdata->mark_target = mark_target;
+		list_add_tail(&pdata->list, &data_list->list);
+	}
+
+exit:
+	mutex_unlock(&data_list->lock);
+}
+
+void msm_comm_fetch_mark_data(struct msm_vidc_list *data_list,
+		u32 index, u32 *mark_data, u32 *mark_target)
+{
+	struct msm_vidc_buf_data *pdata = NULL;
+
+	if (!data_list || !mark_data || !mark_target) {
+		dprintk(VIDC_ERR, "%s: invalid params %pK %pK %pK\n",
+			__func__, data_list, mark_data, mark_target);
+		return;
+	}
+
+	*mark_data = *mark_target = 0;
+	mutex_lock(&data_list->lock);
+	list_for_each_entry(pdata, &data_list->list, list) {
+		if (pdata->index == index) {
+			*mark_data = pdata->mark_data;
+			*mark_target = pdata->mark_target;
+			/* clear after fetch */
+			pdata->mark_data = pdata->mark_target = 0;
+			break;
+		}
+	}
+	mutex_unlock(&data_list->lock);
+}
+
+int msm_comm_release_mark_data(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_buf_data *pdata, *next;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid params %pK\n",
+			__func__, inst);
+		return -EINVAL;
+	}
+
+	mutex_lock(&inst->etb_data.lock);
+	list_for_each_entry_safe(pdata, next, &inst->etb_data.list, list) {
+		list_del(&pdata->list);
+		kfree(pdata);
+	}
+	mutex_unlock(&inst->etb_data.lock);
+
+	mutex_lock(&inst->fbd_data.lock);
+	list_for_each_entry_safe(pdata, next, &inst->fbd_data.list, list) {
+		list_del(&pdata->list);
+		kfree(pdata);
+	}
+	mutex_unlock(&inst->fbd_data.lock);
+
+	return 0;
+}
+
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 05e2b91..053a250 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -154,5 +154,10 @@
 		struct v4l2_buffer *v4l2);
 void kref_put_mbuf(struct msm_vidc_buffer *mbuf);
 bool kref_get_mbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf);
+void msm_comm_store_mark_data(struct msm_vidc_list *data_list,
+		u32 index, u32 mark_data, u32 mark_target);
+void msm_comm_fetch_mark_data(struct msm_vidc_list *data_list,
+		u32 index, u32 *mark_data, u32 *mark_target);
+int msm_comm_release_mark_data(struct msm_vidc_inst *inst);
 
 #endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index ba05059..a0f7d2e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -175,6 +175,13 @@
 	u32 *vpe_csc_custom_limit_coeff;
 };
 
+struct msm_vidc_buf_data {
+	struct list_head list;
+	u32 index;
+	u32 mark_data;
+	u32 mark_target;
+};
+
 struct msm_vidc_common_data {
 	char key[128];
 	int value;
@@ -349,6 +356,8 @@
 	struct msm_vidc_list reconbufs;
 	struct msm_vidc_list eosbufs;
 	struct msm_vidc_list registeredbufs;
+	struct msm_vidc_list etb_data;
+	struct msm_vidc_list fbd_data;
 	struct buffer_requirements buff_req;
 	struct smem_client *mem_client;
 	struct v4l2_ctrl_handler ctrl_handler;