Procházet zdrojové kódy

video: driver: Add support to enc start/stop streaming

Add support to encoder start and stop streaming sequence.

Change-Id: Ie4f124af212ed030178d0e2fe5af3d6f9f639aa0
Signed-off-by: Akshata Sahukar <[email protected]>
Akshata Sahukar před 4 roky
rodič
revize
9476ecc5fe

+ 5 - 2
driver/variant/iris2/src/msm_vidc_buffer_iris2.c

@@ -575,6 +575,7 @@ static u32 calculate_enc_scratch_size(struct msm_vidc_inst *inst,
 
 	bitstream_size = ALIGN(bitstream_size, VENUS_DMA_ALIGNMENT);
 	if (1) { // TODO: work_mode == HFI_WORKMODE_2) {
+		s_vpr_e(inst->sid, "work mode 2\n");
 		total_bitbin_buffers = 3;
 		bitbin_size = bitstream_size * 17 / 10;
 		bitbin_size = ALIGN(bitbin_size, VENUS_DMA_ALIGNMENT);
@@ -1288,7 +1289,8 @@ int msm_buffer_size_iris2(struct msm_vidc_inst *inst,
 		case MSM_VIDC_BUF_DPB:
 			size = msm_vidc_encoder_dpb_size_iris2(inst);
 			break;
-		case MSM_VIDC_BUF_PERSIST:
+		//case MSM_VIDC_BUF_PERSIST:
+		case MSM_VIDC_BUF_ARP:
 			size = msm_vidc_encoder_persist_size_iris2(inst);
 			break;
 		default:
@@ -1344,7 +1346,8 @@ int msm_buffer_min_count_iris2(struct msm_vidc_inst *inst,
 		case MSM_VIDC_BUF_NON_COMV:
 		case MSM_VIDC_BUF_LINE:
 		case MSM_VIDC_BUF_DPB:
-		case MSM_VIDC_BUF_PERSIST:
+		//case MSM_VIDC_BUF_PERSIST:
+		case MSM_VIDC_BUF_ARP:
 			count = 1;
 			break;
 		default:

+ 4 - 0
driver/vidc/inc/msm_venc.h

@@ -9,6 +9,10 @@
 #include "msm_vidc_core.h"
 #include "msm_vidc_inst.h"
 
+int msm_venc_stop_input(struct msm_vidc_inst *inst);
+int msm_venc_start_input(struct msm_vidc_inst *inst);
+int msm_venc_stop_output(struct msm_vidc_inst *inst);
+int msm_venc_start_output(struct msm_vidc_inst *inst);
 int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
 int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
 int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f);

+ 1 - 0
driver/vidc/inc/msm_vidc_driver.h

@@ -50,6 +50,7 @@ static inline is_output_meta_buffer(enum msm_vidc_buffer_type buffer_type)
 static inline is_internal_buffer(enum msm_vidc_buffer_type buffer_type)
 {
 	return buffer_type == MSM_VIDC_BUF_BIN ||
+		buffer_type == MSM_VIDC_BUF_ARP ||
 		buffer_type == MSM_VIDC_BUF_COMV ||
 		buffer_type == MSM_VIDC_BUF_NON_COMV ||
 		buffer_type == MSM_VIDC_BUF_LINE ||

+ 3 - 0
driver/vidc/inc/msm_vidc_inst.h

@@ -27,6 +27,7 @@ struct msm_vidc_session_ops {
 
 struct msm_vidc_allocations_info {
 	struct msm_vidc_allocations     bin;
+	struct msm_vidc_allocations     arp;
 	struct msm_vidc_allocations     comv;
 	struct msm_vidc_allocations     non_comv;
 	struct msm_vidc_allocations     line;
@@ -40,6 +41,7 @@ struct msm_vidc_mappings_info {
 	struct msm_vidc_mappings        input_meta;
 	struct msm_vidc_mappings        output_meta;
 	struct msm_vidc_mappings        bin;
+	struct msm_vidc_mappings        arp;
 	struct msm_vidc_mappings        comv;
 	struct msm_vidc_mappings        non_comv;
 	struct msm_vidc_mappings        line;
@@ -53,6 +55,7 @@ struct msm_vidc_buffers_info {
 	struct msm_vidc_buffers        input_meta;
 	struct msm_vidc_buffers        output_meta;
 	struct msm_vidc_buffers        bin;
+	struct msm_vidc_buffers        arp;
 	struct msm_vidc_buffers        comv;
 	struct msm_vidc_buffers        non_comv;
 	struct msm_vidc_buffers        line;

+ 5 - 0
driver/vidc/inc/msm_vidc_internal.h

@@ -68,6 +68,10 @@
 	(V4L2_CTRL_ID2WHICH(idx) == V4L2_CTRL_CLASS_MPEG) && \
 	V4L2_CTRL_DRIVER_PRIV(idx))
 
+#define BUFFER_ALIGNMENT_SIZE(x) x
+#define NUM_MBS_720P (((1280 + 15) >> 4) * ((720 + 15) >> 4))
+#define NUM_MBS_4k (((4096 + 15) >> 4) * ((2304 + 15) >> 4))
+
 /*
  * Convert Q16 number into Integer and Fractional part upto 2 places.
  * Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752;
@@ -110,6 +114,7 @@ enum msm_vidc_buffer_type {
 	MSM_VIDC_BUF_OUTPUT_META,
 	MSM_VIDC_BUF_QUEUE,
 	MSM_VIDC_BUF_BIN,
+	MSM_VIDC_BUF_ARP,
 	MSM_VIDC_BUF_COMV,
 	MSM_VIDC_BUF_NON_COMV,
 	MSM_VIDC_BUF_LINE,

+ 3 - 0
driver/vidc/src/hfi_packet.c

@@ -86,6 +86,7 @@ u32 get_hfi_port_from_buffer_type(struct msm_vidc_inst *inst,
 		case MSM_VIDC_BUF_INPUT:
 		case MSM_VIDC_BUF_INPUT_META:
 		case MSM_VIDC_BUF_BIN:
+		case MSM_VIDC_BUF_ARP:
 		case MSM_VIDC_BUF_COMV:
 		case MSM_VIDC_BUF_NON_COMV:
 		case MSM_VIDC_BUF_LINE:
@@ -131,6 +132,8 @@ u32 get_hfi_buffer_type(enum msm_vidc_domain_type domain,
 		return HFI_BUFFER_METADATA;
 	case MSM_VIDC_BUF_BIN:
 		return HFI_BUFFER_BIN;
+	case MSM_VIDC_BUF_ARP:
+		return HFI_BUFFER_ARP;
 	case MSM_VIDC_BUF_COMV:
 		return HFI_BUFFER_COMV;
 	case MSM_VIDC_BUF_NON_COMV:

+ 652 - 0
driver/vidc/src/msm_venc.c

@@ -13,6 +13,47 @@
 #include "msm_vidc_internal.h"
 #include "msm_vidc_platform.h"
 #include "msm_vidc_debug.h"
+#include "venus_hfi.h"
+#include "hfi_packet.h"
+
+u32 msm_venc_input_set_prop[] = {
+	HFI_PROP_COLOR_FORMAT,
+	HFI_PROP_ALIGN_RESOLUTION,
+	HFI_PROP_CROP_COORDINATE_TOP_LEFT,
+	HFI_PROP_CROP_RESOLUTION,
+};
+
+u32 msm_venc_output_set_prop[] = {
+	HFI_PROP_ALIGN_RESOLUTION,
+	HFI_PROP_CROP_COORDINATE_TOP_LEFT,
+	HFI_PROP_CROP_RESOLUTION,
+};
+
+u32 msm_venc_input_subscribe_for_properties[] = {
+	HFI_PROP_TAG_NOT_PROPAGATED_TO_OUTPUT,
+};
+
+u32 msm_venc_deliver_as_metadata[] = {
+	HFI_PROP_BUFFER_TAG,
+	HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR,
+	HFI_PROP_SEI_CONTENT_LIGHT_LEVEL,
+	HFI_PROP_SEI_HDR10PLUS_USERDATA,
+	HFI_PROP_CVP_STAT_INFO,
+};
+
+u32 msm_venc_subscribe_for_metadata[] = {
+	HFI_PROP_BUFFER_TAG,
+	HFI_PROP_METADATA_SEQ_HEADER_NAL,
+	HFI_PROP_TIMESTAMP,
+	HFI_PROP_LTR_MARK_USE_DETAILS,
+	HFI_PROP_SUBFRAME_OUTPUT,
+	HFI_PROP_ENC_QP_METADATA,
+};
+
+u32 msm_venc_output_subscribe_for_properties[] = {
+	HFI_PROP_PICTURE_TYPE,
+	HFI_PROP_BUFFER_MARK,
+};
 
 static int msm_venc_codec_change(struct msm_vidc_inst *inst, u32 codec)
 {
@@ -25,6 +66,617 @@ static int msm_venc_codec_change(struct msm_vidc_inst *inst, u32 codec)
 	return rc;
 }
 
+static int msm_venc_set_colorformat(struct msm_vidc_inst *inst,
+	enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 pixelformat;
+	enum msm_vidc_colorformat_type colorformat;
+	u32 hfi_colorformat;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		s_vpr_e(inst->sid, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	pixelformat = inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat;
+	if (pixelformat != V4L2_PIX_FMT_NV12_UBWC &&
+	    pixelformat != V4L2_PIX_FMT_NV12_TP10_UBWC) {
+		s_vpr_e(inst->sid, "%s: invalid pixelformat %#x\n",
+			__func__, pixelformat);
+		return -EINVAL;
+	}
+	colorformat = v4l2_colorformat_to_driver(pixelformat, __func__);
+	hfi_colorformat = get_hfi_colorformat(inst, colorformat);
+	rc = venus_hfi_session_property(inst,
+			HFI_PROP_COLOR_FORMAT,
+			HFI_HOST_FLAGS_NONE,
+			get_hfi_port(inst, port),
+			HFI_PAYLOAD_U32_ENUM,
+			&hfi_colorformat,
+			sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_resolution(struct msm_vidc_inst *inst,
+	enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 resolution;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		s_vpr_e(inst->sid, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	resolution = inst->fmts[port].fmt.pix_mp.width << 16 |
+		inst->fmts[port].fmt.pix_mp.height;
+	rc = venus_hfi_session_property(inst,
+			HFI_PROP_ALIGN_RESOLUTION,
+			HFI_HOST_FLAGS_NONE,
+			get_hfi_port(inst, port),
+			HFI_PAYLOAD_32_PACKED,
+			&resolution,
+			sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_crop_top_left(struct msm_vidc_inst *inst,
+	enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 crop_top_left;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		s_vpr_e(inst->sid, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	crop_top_left = 0;
+	rc = venus_hfi_session_property(inst,
+			HFI_PROP_CROP_COORDINATE_TOP_LEFT,
+			HFI_HOST_FLAGS_NONE,
+			get_hfi_port(inst, port),
+			HFI_PAYLOAD_32_PACKED,
+			&crop_top_left,
+			sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_crop_resolution(struct msm_vidc_inst *inst,
+	enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	u32 crop;
+
+	if (port != INPUT_PORT && port != OUTPUT_PORT) {
+		s_vpr_e(inst->sid, "%s: invalid port %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	/* output buffer resolution is nothing but crop */
+	crop = inst->fmts[INPUT_PORT].fmt.pix_mp.width << 16 |
+		inst->fmts[INPUT_PORT].fmt.pix_mp.height;
+	rc = venus_hfi_session_property(inst,
+			HFI_PROP_CROP_RESOLUTION,
+			HFI_HOST_FLAGS_NONE,
+			get_hfi_port(inst, port),
+			HFI_PAYLOAD_32_PACKED,
+			&crop,
+			sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_stage(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core = inst->core;
+
+	rc = call_session_op(core, decide_work_mode, inst);
+	if (rc) {
+		s_vpr_e(inst->sid, "%s: decide_work_mode failed\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	rc = venus_hfi_session_property(inst,
+			HFI_PROP_STAGE,
+			HFI_HOST_FLAGS_NONE,
+			HFI_PORT_NONE,
+			HFI_PAYLOAD_U32,
+			&inst->stage,
+			sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_pipe(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core = inst->core;
+
+	rc = call_session_op(core, decide_work_route, inst);
+	if (rc) {
+		s_vpr_e(inst->sid, "%s: decide_work_route failed\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	rc = venus_hfi_session_property(inst,
+			HFI_PROP_PIPE,
+			HFI_HOST_FLAGS_NONE,
+			HFI_PORT_NONE,
+			HFI_PAYLOAD_U32,
+			&inst->pipe,
+			sizeof(u32));
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static int msm_venc_set_input_properties(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int i = 0;
+
+	d_vpr_h("%s()\n", __func__);
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(msm_venc_input_set_prop);
+	     i++) {
+		switch (msm_venc_input_set_prop[i]) {
+		case HFI_PROP_COLOR_FORMAT:
+			rc = msm_venc_set_colorformat(inst, INPUT_PORT);
+			break;
+		case HFI_PROP_ALIGN_RESOLUTION:
+			rc = msm_venc_set_resolution(inst, INPUT_PORT);
+			break;
+		case HFI_PROP_CROP_COORDINATE_TOP_LEFT:
+			rc = msm_venc_set_crop_top_left(inst, INPUT_PORT);
+			break;
+		case HFI_PROP_CROP_RESOLUTION:
+			rc = msm_venc_set_crop_resolution(inst, INPUT_PORT);
+			break;
+		default:
+			d_vpr_e("%s: unknown property %#x\n", __func__,
+				msm_venc_input_set_prop[i]);
+			rc = -EINVAL;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int msm_venc_set_output_properties(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int i = 0;
+
+	d_vpr_h("%s()\n", __func__);
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	//TODO: set HFI_PORT_NONE properties at master port streamon.
+	rc = msm_venc_set_stage(inst);
+	if (rc)
+		return rc;
+
+	rc = msm_venc_set_pipe(inst);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < ARRAY_SIZE(msm_venc_output_set_prop);
+	     i++) {
+		switch (msm_venc_output_set_prop[i]) {
+		case HFI_PROP_ALIGN_RESOLUTION:
+			rc = msm_venc_set_resolution(inst, OUTPUT_PORT);
+			break;
+		case HFI_PROP_CROP_COORDINATE_TOP_LEFT:
+			rc = msm_venc_set_crop_top_left(inst, OUTPUT_PORT);
+			break;
+		case HFI_PROP_CROP_RESOLUTION:
+			rc = msm_venc_set_crop_resolution(inst, OUTPUT_PORT);
+			break;
+		default:
+			d_vpr_e("%s: unknown property %#x\n", __func__,
+				msm_venc_output_set_prop[i]);
+			rc = -EINVAL;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int msm_venc_get_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+
+	inst->buffers.arp.size = call_session_op(core, buffer_size,
+			inst, MSM_VIDC_BUF_ARP);
+	inst->buffers.bin.size = call_session_op(core, buffer_size,
+			inst, MSM_VIDC_BUF_BIN);
+	/* inst->buffers.comv.size = call_session_op(core, buffer_size,
+			inst, MSM_VIDC_BUF_COMV);
+	inst->buffers.non_comv.size = call_session_op(core, buffer_size,
+			inst, MSM_VIDC_BUF_NON_COMV); */
+	inst->buffers.line.size = call_session_op(core, buffer_size,
+			inst, MSM_VIDC_BUF_LINE);
+	inst->buffers.dpb.size = call_session_op(core, buffer_size,
+			inst, MSM_VIDC_BUF_DPB);
+	/* inst->buffers.persist.size = call_session_op(core, buffer_size,
+			inst, MSM_VIDC_BUF_PERSIST); */
+
+	inst->buffers.arp.min_count = call_session_op(core, min_count,
+			inst, MSM_VIDC_BUF_ARP);
+	inst->buffers.bin.min_count = call_session_op(core, min_count,
+			inst, MSM_VIDC_BUF_BIN);
+	/* inst->buffers.comv.min_count = call_session_op(core, min_count,
+			inst, MSM_VIDC_BUF_COMV);
+	inst->buffers.non_comv.min_count = call_session_op(core, min_count,
+			inst, MSM_VIDC_BUF_NON_COMV); */
+	inst->buffers.line.min_count = call_session_op(core, min_count,
+			inst, MSM_VIDC_BUF_LINE);
+	inst->buffers.dpb.min_count = call_session_op(core, min_count,
+			inst, MSM_VIDC_BUF_DPB);
+	/* inst->buffers.persist.min_count = call_session_op(core, min_count,
+			inst, MSM_VIDC_BUF_PERSIST); */
+
+	s_vpr_h(inst->sid, "internal buffer: min     size\n");
+	s_vpr_h(inst->sid, "arp  buffer: %d      %d\n",
+		inst->buffers.arp.min_count,
+		inst->buffers.arp.size);
+	s_vpr_h(inst->sid, "bin  buffer: %d      %d\n",
+		inst->buffers.bin.min_count,
+		inst->buffers.bin.size);
+	/* s_vpr_h(inst->sid, "comv  buffer: %d      %d\n",
+		inst->buffers.comv.min_count,
+		inst->buffers.comv.size);
+	s_vpr_h(inst->sid, "non_comv  buffer: %d      %d\n",
+		inst->buffers.non_comv.min_count,
+		inst->buffers.non_comv.size); */
+	s_vpr_h(inst->sid, "line buffer: %d      %d\n",
+		inst->buffers.line.min_count,
+		inst->buffers.line.size);
+	s_vpr_h(inst->sid, "dpb buffer: %d      %d\n",
+		inst->buffers.dpb.min_count,
+		inst->buffers.dpb.size);
+	/* s_vpr_h(inst->sid, "persist buffer: %d      %d\n",
+		inst->buffers.persist.min_count,
+		inst->buffers.persist.size); */
+
+	return rc;
+}
+
+static int msm_venc_create_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	d_vpr_h("%s()\n", __func__);
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_vidc_create_internal_buffers(inst, MSM_VIDC_BUF_ARP);
+	if (rc)
+		return rc;
+	rc = msm_vidc_create_internal_buffers(inst, MSM_VIDC_BUF_BIN);
+	if (rc)
+		return rc;
+	/* rc = msm_vidc_create_internal_buffers(inst, MSM_VIDC_BUF_COMV);
+	if (rc)
+		return rc;
+	rc = msm_vidc_create_internal_buffers(inst, MSM_VIDC_BUF_NON_COMV);
+	if (rc)
+		return rc; */
+	rc = msm_vidc_create_internal_buffers(inst, MSM_VIDC_BUF_LINE);
+	if (rc)
+		return rc;
+	rc = msm_vidc_create_internal_buffers(inst, MSM_VIDC_BUF_DPB);
+	if (rc)
+		return rc;
+	/* rc = msm_vidc_create_internal_buffers(inst, MSM_VIDC_BUF_PERSIST);
+	if (rc)
+		return rc; */
+
+	return 0;
+}
+
+static int msm_venc_queue_input_internal_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	d_vpr_h("%s()\n", __func__);
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_ARP);
+	if (rc)
+		return rc;
+	rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_BIN);
+	if (rc)
+		return rc;
+	/* rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_COMV);
+	if (rc)
+		return rc;
+	rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_NON_COMV);
+	if (rc)
+		return rc; */
+	rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_LINE);
+	if (rc)
+		return rc;
+	rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_DPB);
+	if (rc)
+		return rc;
+	// TODO: fw is not accepting persist buffer and returning session error.
+	//rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_PERSIST);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int msm_venc_property_subscription(struct msm_vidc_inst *inst,
+	enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	u32 payload[32] = {0};
+	u32 i;
+	u32 payload_size = 0;
+
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	d_vpr_h("%s()\n", __func__);
+
+	payload[0] = HFI_MODE_PROPERTY;
+	if (port == INPUT_PORT) {
+		for (i = 0; i < ARRAY_SIZE(msm_venc_input_subscribe_for_properties); i++)
+			payload[i + 1] = msm_venc_input_subscribe_for_properties[i];
+		payload_size = (ARRAY_SIZE(msm_venc_input_subscribe_for_properties) + 1) *
+				sizeof(u32);
+	} else if (port == OUTPUT_PORT) {
+		for (i = 0; i < ARRAY_SIZE(msm_venc_output_subscribe_for_properties); i++)
+			payload[i + 1] = msm_venc_output_subscribe_for_properties[i];
+		payload_size = (ARRAY_SIZE(msm_venc_output_subscribe_for_properties) + 1) *
+				sizeof(u32);
+	} else {
+		s_vpr_e(inst->sid, "%s: invalid port: %d\n", __func__, port);
+		return -EINVAL;
+	}
+
+	rc = venus_hfi_session_command(inst,
+			HFI_CMD_SUBSCRIBE_MODE,
+			port,
+			HFI_PAYLOAD_U32_ARRAY,
+			&payload[0],
+			payload_size);
+
+	return rc;
+}
+
+static int msm_venc_metadata_delivery(struct msm_vidc_inst *inst,
+	enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	u32 payload[32] = {0};
+	u32 i;
+
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	d_vpr_h("%s()\n", __func__);
+
+	payload[0] = HFI_MODE_METADATA;
+	for (i = 0; i < ARRAY_SIZE(msm_venc_deliver_as_metadata); i++)
+		payload[i + 1] = msm_venc_deliver_as_metadata[i];
+
+	rc = venus_hfi_session_command(inst,
+			HFI_CMD_DELIVERY_MODE,
+			port,
+			HFI_PAYLOAD_U32_ARRAY,
+			&payload[0],
+			(ARRAY_SIZE(msm_venc_deliver_as_metadata) + 1) *
+			sizeof(u32));
+
+	return rc;
+}
+
+static int msm_venc_metadata_subscription(struct msm_vidc_inst *inst,
+	enum msm_vidc_port_type port)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	u32 payload[32] = {0};
+	u32 i;
+
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	d_vpr_h("%s()\n", __func__);
+
+	payload[0] = HFI_MODE_METADATA;
+	for (i = 0; i < ARRAY_SIZE(msm_venc_subscribe_for_metadata); i++)
+		payload[i + 1] = msm_venc_subscribe_for_metadata[i];
+
+	rc = venus_hfi_session_command(inst,
+			HFI_CMD_SUBSCRIBE_MODE,
+			port,
+			HFI_PAYLOAD_U32_ARRAY,
+			&payload[0],
+			(ARRAY_SIZE(msm_venc_subscribe_for_metadata) + 1) *
+			sizeof(u32));
+
+	return rc;
+}
+
+int msm_venc_stop_input(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_vidc_session_stop(inst, INPUT_PORT);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_venc_start_input(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	s_vpr_h(inst->sid, "%s()\n", __func__);
+
+	//rc = msm_vidc_check_session_supported(inst);
+	if (rc)
+		goto error;
+	//rc = msm_vidc_check_scaling_supported(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_set_input_properties(inst);
+	if (rc)
+		goto error;
+
+	/* Decide bse vpp delay after work mode */
+	//msm_vidc_set_bse_vpp_delay(inst);
+
+	rc = msm_venc_get_input_internal_buffers(inst);
+	if (rc)
+		goto error;
+	/* check for memory after all buffers calculation */
+	//rc = msm_vidc_check_memory_supported(inst);
+	if (rc)
+		goto error;
+
+	//msm_vidc_update_dcvs(inst);
+	//msm_vidc_update_batching(inst);
+	//msm_vidc_scale_power(inst);
+
+	rc = msm_venc_create_input_internal_buffers(inst);
+	rc = 0; // TODO
+	if (rc)
+		goto error;
+	rc = msm_venc_queue_input_internal_buffers(inst);
+	rc = 0; // TODO
+	if (rc)
+		goto error;
+
+	rc = msm_venc_property_subscription(inst, INPUT_PORT);
+	if (rc)
+		return rc;
+
+	rc = msm_venc_metadata_delivery(inst, INPUT_PORT);
+	if (rc)
+		return rc;
+
+	rc = venus_hfi_start(inst, INPUT_PORT);
+	if (rc)
+		goto error;
+
+	s_vpr_h(inst->sid, "%s: done\n", __func__);
+	return 0;
+
+error:
+	s_vpr_e(inst->sid, "%s: failed\n", __func__);
+	msm_venc_stop_input(inst);
+	return rc;
+}
+
+int msm_venc_stop_output(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_vidc_session_stop(inst, OUTPUT_PORT);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+int msm_venc_start_output(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	d_vpr_h("%s()\n", __func__);
+	if (!inst || !inst->core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_venc_set_output_properties(inst);
+	if (rc)
+		goto error;
+
+	rc = msm_venc_property_subscription(inst, OUTPUT_PORT);
+	if (rc)
+		return rc;
+
+	rc = msm_venc_metadata_subscription(inst, OUTPUT_PORT);
+	if (rc)
+		return rc;
+
+	rc = venus_hfi_start(inst, OUTPUT_PORT);
+	if (rc)
+		goto error;
+
+	d_vpr_h("%s: done\n", __func__);
+	return 0;
+
+error:
+	msm_venc_stop_output(inst);
+	return rc;
+}
+
 int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 {
 	int rc = 0;

+ 3 - 0
driver/vidc/src/msm_vidc.c

@@ -760,12 +760,14 @@ void *msm_vidc_open(void *vidc_core, u32 session_type)
 	INIT_LIST_HEAD(&inst->buffers.output.list);
 	INIT_LIST_HEAD(&inst->buffers.output_meta.list);
 	INIT_LIST_HEAD(&inst->buffers.bin.list);
+	INIT_LIST_HEAD(&inst->buffers.arp.list);
 	INIT_LIST_HEAD(&inst->buffers.comv.list);
 	INIT_LIST_HEAD(&inst->buffers.non_comv.list);
 	INIT_LIST_HEAD(&inst->buffers.line.list);
 	INIT_LIST_HEAD(&inst->buffers.dpb.list);
 	INIT_LIST_HEAD(&inst->buffers.persist.list);
 	INIT_LIST_HEAD(&inst->allocations.bin.list);
+	INIT_LIST_HEAD(&inst->allocations.arp.list);
 	INIT_LIST_HEAD(&inst->allocations.comv.list);
 	INIT_LIST_HEAD(&inst->allocations.non_comv.list);
 	INIT_LIST_HEAD(&inst->allocations.line.list);
@@ -776,6 +778,7 @@ void *msm_vidc_open(void *vidc_core, u32 session_type)
 	INIT_LIST_HEAD(&inst->mappings.output.list);
 	INIT_LIST_HEAD(&inst->mappings.output_meta.list);
 	INIT_LIST_HEAD(&inst->mappings.bin.list);
+	INIT_LIST_HEAD(&inst->mappings.arp.list);
 	INIT_LIST_HEAD(&inst->mappings.comv.list);
 	INIT_LIST_HEAD(&inst->mappings.non_comv.list);
 	INIT_LIST_HEAD(&inst->mappings.line.list);

+ 42 - 3
driver/vidc/src/msm_vidc_buffer.c

@@ -9,6 +9,7 @@
 #include "msm_vidc_core.h"
 #include "msm_vidc_driver.h"
 #include "msm_vidc_debug.h"
+#include "msm_vidc_internal.h"
 
 #define MIN_INPUT_BUFFERS 4
 #define MIN_ENC_OUTPUT_BUFFERS 4
@@ -182,9 +183,47 @@ u32 msm_vidc_encoder_input_size(struct msm_vidc_inst *inst)
 
 u32 msm_vidc_encoder_output_size(struct msm_vidc_inst *inst)
 {
-	u32 size = ALIGN(15 * 1024 * 1024, SZ_4K);
-	size = 4; // TODO
-	return size;
+	u32 frame_size;
+	u32 mbs_per_frame;
+	u32 width, height;
+	struct v4l2_format *f;
+
+	f = &inst->fmts[OUTPUT_PORT];
+	/*
+	 * Encoder output size calculation: 32 Align width/height
+	 * For resolution < 720p : YUVsize * 4
+	 * For resolution > 720p & <= 4K : YUVsize / 2
+	 * For resolution > 4k : YUVsize / 4
+	 * Initially frame_size = YUVsize * 2;
+	 */
+
+	/* if (is_grid_session(inst)) {
+		f->fmt.pix_mp.width = f->fmt.pix_mp.height = HEIC_GRID_DIMENSION;
+	} */
+	width = ALIGN(f->fmt.pix_mp.width, BUFFER_ALIGNMENT_SIZE(32));
+	height = ALIGN(f->fmt.pix_mp.height, BUFFER_ALIGNMENT_SIZE(32));
+	mbs_per_frame = NUM_MBS_PER_FRAME(width, height);
+	frame_size = (width * height * 3);
+
+	if (mbs_per_frame < NUM_MBS_720P)
+		frame_size = frame_size << 1;
+	else if (mbs_per_frame <= NUM_MBS_4k)
+		frame_size = frame_size >> 2;
+	else
+		frame_size = frame_size >> 3;
+
+	/*if ((inst->rc_type == RATE_CONTROL_OFF) ||
+		(inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ))
+		frame_size = frame_size << 1;
+
+	if (inst->rc_type == RATE_CONTROL_LOSSLESS)
+		frame_size = (width * height * 9) >> 2; */
+
+	/* multiply by 10/8 (1.25) to get size for 10 bit case */
+	if (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_HEVC)
+		frame_size = frame_size + (frame_size >> 2);
+
+	return ALIGN(frame_size, SZ_4K);
 }
 
 u32 msm_vidc_encoder_input_meta_size(struct msm_vidc_inst *inst)

+ 8 - 0
driver/vidc/src/msm_vidc_driver.c

@@ -308,6 +308,8 @@ u32 msm_vidc_get_buffer_region(struct msm_vidc_inst *inst,
 		region = MSM_VIDC_SECURE_PIXEL;
 		break;
 	case MSM_VIDC_BUF_PERSIST:
+	// TODO: Need to revisit for ARP
+	case MSM_VIDC_BUF_ARP:
 		region = MSM_VIDC_SECURE_NONPIXEL;
 		break;
 	default:
@@ -332,6 +334,8 @@ struct msm_vidc_buffers *msm_vidc_get_buffers(
 		return &inst->buffers.output_meta;
 	case MSM_VIDC_BUF_BIN:
 		return &inst->buffers.bin;
+	case MSM_VIDC_BUF_ARP:
+		return &inst->buffers.arp;
 	case MSM_VIDC_BUF_COMV:
 		return &inst->buffers.comv;
 	case MSM_VIDC_BUF_NON_COMV:
@@ -364,6 +368,8 @@ struct msm_vidc_mappings *msm_vidc_get_mappings(
 		return &inst->mappings.output_meta;
 	case MSM_VIDC_BUF_BIN:
 		return &inst->mappings.bin;
+	case MSM_VIDC_BUF_ARP:
+		return &inst->mappings.arp;
 	case MSM_VIDC_BUF_COMV:
 		return &inst->mappings.comv;
 	case MSM_VIDC_BUF_NON_COMV:
@@ -388,6 +394,8 @@ struct msm_vidc_allocations *msm_vidc_get_allocations(
 	switch (buffer_type) {
 	case MSM_VIDC_BUF_BIN:
 		return &inst->allocations.bin;
+	case MSM_VIDC_BUF_ARP:
+		return &inst->allocations.arp;
 	case MSM_VIDC_BUF_COMV:
 		return &inst->allocations.comv;
 	case MSM_VIDC_BUF_NON_COMV:

+ 26 - 11
driver/vidc/src/msm_vidc_vb2.c

@@ -171,19 +171,26 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
 	if (q->type == INPUT_MPLANE) {
 		if (is_decode_session(inst))
 			rc = msm_vdec_start_input(inst);
-		//else if (is_encode_session(inst))
-		//	rc = msm_venc_start_input(inst);
+		else if (is_encode_session(inst))
+			rc = msm_venc_start_input(inst);
+		else
+			goto error;
 	} else if (q->type == OUTPUT_MPLANE) {
 		if (is_decode_session(inst))
 			rc = msm_vdec_start_output(inst);
-		//else if (is_encode_session(inst))
-		//	rc = msm_venc_start_output(inst);
+		else if (is_encode_session(inst))
+			rc = msm_venc_start_output(inst);
+		else
+			goto error;
 	} else {
-		s_vpr_e(inst->sid, "%s: invalid type %d\n", __func__, q->type);
-		rc = -EINVAL;
+		goto error;
 	}
 
 	return rc;
+
+error:
+	s_vpr_e(inst->sid, "%s: invalid session/qtype, qtype %d\n", __func__, q->type);
+	return -EINVAL;
 }
 
 void msm_vidc_stop_streaming(struct vb2_queue *q)
@@ -215,21 +222,29 @@ void msm_vidc_stop_streaming(struct vb2_queue *q)
 	if (q->type == INPUT_MPLANE) {
 		if (is_decode_session(inst))
 			rc = msm_vdec_stop_input(inst);
-		//else if (is_encode_session(inst))
-		//	rc = msm_venc_start_input(inst);
+		else if (is_encode_session(inst))
+			rc = msm_venc_stop_input(inst);
+		else
+			goto error;
 	} else if (q->type == OUTPUT_MPLANE) {
 		if (is_decode_session(inst))
 			rc = msm_vdec_stop_output(inst);
-		//else if (is_encode_session(inst))
-		//	rc = msm_venc_start_output(inst);
+		else if (is_encode_session(inst))
+			rc = msm_venc_stop_output(inst);
+		else
+			goto error;
 	} else {
-		s_vpr_e(inst->sid, "%s: invalid type %d\n", __func__, q->type);
+		goto error;
 	}
 
 	if (rc)
 		s_vpr_e(inst->sid, "%s: stop failed for qtype: %d\n",
 			__func__, q->type);
+	return;
 
+error:
+	s_vpr_e(inst->sid, "%s: invalid session/qtype, qtype: %d\n",
+			__func__, q->type);
 	return;
 }
 

+ 1 - 0
driver/vidc/src/venus_hfi_response.c

@@ -36,6 +36,7 @@ bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst,
 	    buffer_type != HFI_BUFFER_RAW &&
 	    buffer_type != HFI_BUFFER_METADATA &&
 	    buffer_type != HFI_BUFFER_BIN &&
+	    buffer_type != HFI_BUFFER_ARP &&
 	    buffer_type != HFI_BUFFER_COMV &&
 	    buffer_type != HFI_BUFFER_NON_COMV &&
 	    buffer_type != HFI_BUFFER_LINE &&