瀏覽代碼

video: driver: handle dpb list property

- subscribe for dpb list property in combined
 mode on output port.
- copy dpb list property payload from fw to
 static array.
- using this array, mark read_only list buffers
 as non-reference if not part of array. if count
 of such buffers is greater than output min count,
 send to fw for release.
- once fw returns them, destroy these buffers.
- unmap stale output mappings due to lazy unmap feature.
- unify release internal functions into common function.

Change-Id: Id32f04efb19eecaff453cc4383ee8296a0246263
Signed-off-by: Darshana Patil <[email protected]>
Darshana Patil 4 年之前
父節點
當前提交
23605ffffb

+ 9 - 0
driver/platform/waipio/src/msm_vidc_waipio.c

@@ -1168,6 +1168,15 @@ static struct msm_platform_inst_capability instance_data_waipio[] = {
 		V4L2_CID_MPEG_VIDC_ENC_INPUT_COMPRESSION_RATIO,
 		0, CAP_FLAG_DYNAMIC_ALLOWED},
 
+	{DPB_LIST, DEC, CODECS_ALL,
+		V4L2_MPEG_MSM_VIDC_DISABLE, V4L2_MPEG_MSM_VIDC_ENABLE,
+		1, V4L2_MPEG_MSM_VIDC_DISABLE,
+		0,
+		HFI_PROP_DPB_LIST,
+		CAP_FLAG_OUTPUT_PORT,
+		{0}, {0},
+		NULL, NULL},
+
 	{META_LTR_MARK_USE, ENC, H264|HEVC,
 		V4L2_MPEG_MSM_VIDC_DISABLE, V4L2_MPEG_MSM_VIDC_ENABLE,
 		1, V4L2_MPEG_MSM_VIDC_DISABLE,

+ 2 - 0
driver/vidc/inc/msm_vdec.h

@@ -30,5 +30,7 @@ int msm_vdec_input_port_settings_change(struct msm_vidc_inst *inst);
 int msm_vdec_output_port_settings_change(struct msm_vidc_inst *inst);
 int msm_vdec_process_cmd(struct msm_vidc_inst *inst, u32 cmd);
 int msm_vidc_queue_buffer_batch(struct msm_vidc_inst *inst);
+int msm_vdec_handle_release_buffer(struct msm_vidc_inst *inst,
+	struct msm_vidc_buffer *buf);
 
 #endif // _MSM_VDEC_H_

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

@@ -332,6 +332,9 @@ void put_inst(struct msm_vidc_inst *inst);
 bool msm_vidc_allow_s_fmt(struct msm_vidc_inst *inst, u32 type);
 bool msm_vidc_allow_s_ctrl(struct msm_vidc_inst *inst, u32 id);
 bool msm_vidc_allow_metadata(struct msm_vidc_inst *inst, u32 cap_id);
+bool msm_vidc_allow_property(struct msm_vidc_inst *inst, u32 hfi_id);
+int msm_vidc_update_property_cap(struct msm_vidc_inst *inst, u32 hfi_id,
+	bool allow);
 bool msm_vidc_allow_reqbufs(struct msm_vidc_inst *inst, u32 type);
 enum msm_vidc_allow msm_vidc_allow_stop(struct msm_vidc_inst *inst);
 bool msm_vidc_allow_start(struct msm_vidc_inst *inst);

+ 2 - 1
driver/vidc/inc/msm_vidc_inst.h

@@ -63,6 +63,7 @@ struct msm_vidc_buffers_info {
 	struct msm_vidc_buffers        input;
 	struct msm_vidc_buffers        output;
 	struct msm_vidc_buffers        read_only;
+	struct msm_vidc_buffers        release;
 	struct msm_vidc_buffers        input_meta;
 	struct msm_vidc_buffers        output_meta;
 	struct msm_vidc_buffers        bin;
@@ -149,6 +150,6 @@ struct msm_vidc_inst {
 	u64                                last_qbuf_time_ns;
 	bool                               vb2q_init;
 	u32                                max_input_data_size;
+	u32                                dpb_list_payload[MAX_DPB_LIST_ARRAY_SIZE];
 };
-
 #endif // _MSM_VIDC_INST_H_

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

@@ -111,6 +111,23 @@
 #define HW_RESPONSE_TIMEOUT_VALUE     (1000)
 #define SW_PC_DELAY_VALUE             (HW_RESPONSE_TIMEOUT_VALUE + 500)
 #define FW_UNLOAD_DELAY_VALUE         (SW_PC_DELAY_VALUE + 1500)
+/*
+ * MAX_MAPPED_OUTPUT_COUNT: maximum mappings which can
+ * be present in output map list with refcount 1. These
+ * mappings exist due to lazy unmap feature. Current
+ * threshold is kept as 50 to handle vpp usecases
+ * which might have many output buffers.
+ */
+#define MAX_MAPPED_OUTPUT_COUNT 50
+ /*
+  * max dpb count = 16
+  * each dpb: 4 words - <base_address, addr_offset, data_offset>
+  * dpb list array size = 16 * 4
+  * dpb payload size = 16 * 4 * 4
+  */
+#define MAX_DPB_COUNT 16
+#define MAX_DPB_LIST_ARRAY_SIZE (MAX_DPB_COUNT * 4)
+#define MAX_DPB_LIST_PAYLOAD_SIZE (MAX_DPB_COUNT * 4 * 4)
 
 enum msm_vidc_domain_type {
 	MSM_VIDC_ENCODER           = BIT(0),
@@ -420,6 +437,7 @@ enum msm_vidc_inst_capability_type {
 	SEQ_CHANGE_AT_SYNC_FRAME,
 	PRIORITY,
 	ENC_IP_CR,
+	DPB_LIST,
 	META_LTR_MARK_USE,
 	META_DPB_MISR,
 	META_OPB_MISR,

+ 163 - 12
driver/vidc/src/msm_vdec.c

@@ -17,6 +17,7 @@
 #include "msm_vidc_debug.h"
 #include "msm_vidc_power.h"
 #include "msm_vidc_control.h"
+#include "msm_vidc_memory.h"
 #include "venus_hfi.h"
 #include "hfi_packet.h"
 /* TODO: update based on clips */
@@ -63,6 +64,7 @@ static const u32 msm_vdec_output_subscribe_for_properties[] = {
 	HFI_PROP_WORST_COMPRESSION_RATIO,
 	HFI_PROP_WORST_COMPLEXITY_FACTOR,
 	HFI_PROP_PICTURE_TYPE,
+	HFI_PROP_DPB_LIST,
 };
 
 static const u32 msm_vdec_internal_buffer_type[] = {
@@ -1021,8 +1023,8 @@ static int msm_vdec_subscribe_property(struct msm_vidc_inst *inst,
 	int rc = 0;
 	struct msm_vidc_core *core;
 	u32 payload[32] = {0};
-	u32 i;
-	u32 payload_size = 0;
+	u32 i, count = 0;
+	bool allow = false;
 
 	if (!inst || !inst->core) {
 		d_vpr_e("%s: invalid params\n", __func__);
@@ -1034,15 +1036,21 @@ static int msm_vdec_subscribe_property(struct msm_vidc_inst *inst,
 	payload[0] = HFI_MODE_PROPERTY;
 
 	if (port == INPUT_PORT) {
-		for (i = 0; i < ARRAY_SIZE(msm_vdec_input_subscribe_for_properties); i++)
-			payload[i + 1] = msm_vdec_input_subscribe_for_properties[i];
-		payload_size = (ARRAY_SIZE(msm_vdec_input_subscribe_for_properties) + 1) *
-			sizeof(u32);
+		for (i = 0; i < ARRAY_SIZE(msm_vdec_input_subscribe_for_properties); i++) {
+			payload[count + 1] = msm_vdec_input_subscribe_for_properties[i];
+			count++;
+		}
 	} else if (port == OUTPUT_PORT) {
-		for (i = 0; i < ARRAY_SIZE(msm_vdec_output_subscribe_for_properties); i++)
-			payload[i + 1] = msm_vdec_output_subscribe_for_properties[i];
-		payload_size = (ARRAY_SIZE(msm_vdec_output_subscribe_for_properties) + 1) *
-			sizeof(u32);
+		for (i = 0; i < ARRAY_SIZE(msm_vdec_output_subscribe_for_properties); i++) {
+			allow = msm_vidc_allow_property(inst,
+				msm_vdec_output_subscribe_for_properties[i]);
+			if (allow) {
+				payload[count + 1] = msm_vdec_output_subscribe_for_properties[i];
+				count++;
+			}
+			msm_vidc_update_property_cap(inst,
+				msm_vdec_output_subscribe_for_properties[i], allow);
+		}
 	} else {
 		i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port);
 		return -EINVAL;
@@ -1053,7 +1061,7 @@ static int msm_vdec_subscribe_property(struct msm_vidc_inst *inst,
 			port,
 			HFI_PAYLOAD_U32_ARRAY,
 			&payload[0],
-			payload_size);
+			(count + 1) * sizeof(u32));
 
 	return rc;
 }
@@ -1780,15 +1788,158 @@ static int msm_vdec_qbuf_batch(struct msm_vidc_inst *inst,
 	return rc;
 }
 
+static int msm_vdec_release_nonref_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	u32 fw_ro_count = 0, nonref_ro_count = 0;
+	struct msm_vidc_buffer *ro_buf, *rel_buf, *dummy;
+	int i = 0;
+	bool found = false;
+
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/* count num buffers in read_only list */
+	list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list)
+		fw_ro_count++;
+
+	if (fw_ro_count <= MAX_DPB_COUNT)
+		return 0;
+
+	/*
+	 * Mark those buffers present in read_only list as non-reference
+	 * if that buffer is not part of dpb_list_payload
+	 * count such non-ref read only buffers as nonref_ro_count
+	 * dpb_list_payload details:
+	 * payload[0-1]           : 64 bits base_address of DPB-1
+	 * payload[2]             : 32 bits addr_offset  of DPB-1
+	 * payload[3]             : 32 bits data_offset  of DPB-1
+	 */
+	list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) {
+		found = false;
+		for (i = 0; (i + 3) < MAX_DPB_LIST_ARRAY_SIZE; i = i + 4) {
+			if (ro_buf->device_addr == inst->dpb_list_payload[i] &&
+				ro_buf->data_offset == inst->dpb_list_payload[i + 3]) {
+				found = true;
+				break;
+			}
+		}
+		if (!found) {
+			ro_buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY;
+			nonref_ro_count++;
+		}
+	}
+
+	if (nonref_ro_count <= inst->buffers.output.min_count)
+		return 0;
+
+	i_vpr_l(inst, "%s: fw ro buf count %d, non-ref ro count %d\n",
+		__func__, fw_ro_count, nonref_ro_count);
+	/*
+	 * move non-ref read only buffers from read_only list to
+	 * release list
+	 */
+	list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
+		if (!(ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY)) {
+			list_del(&ro_buf->list);
+			INIT_LIST_HEAD(&ro_buf->list);
+			list_add_tail(&ro_buf->list, &inst->buffers.release.list);
+		}
+	}
+
+	/* send release flag along with read only flag for release list bufs*/
+	list_for_each_entry(rel_buf, &inst->buffers.release.list, list) {
+		/* fw needs RO flag for FTB release buffer */
+		rel_buf->attr |= MSM_VIDC_ATTR_READ_ONLY;
+		print_vidc_buffer(VIDC_HIGH, "high", "release buf", inst, rel_buf);
+		rc = venus_hfi_release_buffer(inst, rel_buf);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+int msm_vdec_handle_release_buffer(struct msm_vidc_inst *inst,
+	struct msm_vidc_buffer *buf)
+{
+	int rc = 0;
+
+	if (!inst || !buf) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	print_vidc_buffer(VIDC_HIGH, "high", "release done", inst, buf);
+	msm_vidc_unmap_driver_buf(inst, buf);
+
+	/* delete the buffer from release list */
+	list_del(&buf->list);
+	msm_vidc_put_vidc_buffer(inst, buf);
+
+	return rc;
+}
+
+static int msm_vidc_unmap_excessive_mappings(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_map *map;
+	u32 refcount_one_bufs_count = 0;
+
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * count entries from map list whose refcount is 1
+	 * these are excess mappings present due to lazy
+	 * unmap feature.
+	 */
+	list_for_each_entry(map, &inst->mappings.output.list, list) {
+		if (map->refcount == 1)
+			refcount_one_bufs_count++;
+	}
+
+	if (refcount_one_bufs_count <= MAX_MAPPED_OUTPUT_COUNT)
+		return 0;
+
+	/* unmap these buffers as they are stale entries */
+	list_for_each_entry(map, &inst->mappings.output.list, list) {
+		if (map->refcount == 1) {
+			d_vpr_h(
+				"%s: type %11s, device_addr %#x, refcount %d, region %d\n",
+				__func__, buf_name(map->type), map->device_addr, map->refcount,
+				map->region);
+			msm_vidc_memory_unmap(inst->core, map);
+		}
+	}
+	return rc;
+}
+
 int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2)
 {
 	int rc = 0;
 
-	if (!inst || !vb2) {
+	if (!inst || !vb2 || !inst->capabilities) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
 
+	if (vb2->type == OUTPUT_MPLANE) {
+		if (inst->capabilities->cap[DPB_LIST].value) {
+			rc = msm_vdec_release_nonref_buffers(inst);
+			if (rc)
+				return rc;
+		}
+
+		rc = msm_vidc_unmap_excessive_mappings(inst);
+		if (rc)
+			return rc;
+	}
+
 	/* batch decoder output & meta buffer only */
 	if (inst->decode_batch.enable && vb2->type == OUTPUT_MPLANE)
 		rc = msm_vdec_qbuf_batch(inst, vb2);

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

@@ -824,6 +824,7 @@ 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.read_only.list);
+	INIT_LIST_HEAD(&inst->buffers.release.list);
 	INIT_LIST_HEAD(&inst->buffers.bin.list);
 	INIT_LIST_HEAD(&inst->buffers.arp.list);
 	INIT_LIST_HEAD(&inst->buffers.comv.list);

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

@@ -159,6 +159,7 @@ static const struct msm_vidc_cap_name cap_name_arr[] = {
 	{SEQ_CHANGE_AT_SYNC_FRAME,       "SEQ_CHANGE_AT_SYNC_FRAME"   },
 	{PRIORITY,                       "PRIORITY"                   },
 	{ENC_IP_CR,                      "ENC_IP_CR"                  },
+	{DPB_LIST,                       "DPB_LIST"                   },
 	{META_LTR_MARK_USE,              "META_LTR_MARK_USE"          },
 	{META_DPB_MISR,                  "META_DPB_MISR"              },
 	{META_OPB_MISR,                  "META_OPB_MISR"              },
@@ -1174,6 +1175,64 @@ bool msm_vidc_allow_metadata(struct msm_vidc_inst *inst, u32 cap_id)
 	return is_allowed;
 }
 
+bool msm_vidc_allow_property(struct msm_vidc_inst *inst, u32 hfi_id)
+{
+	bool is_allowed = true;
+
+	if (!inst || !inst->capabilities) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return false;
+	}
+
+	switch (hfi_id) {
+	case HFI_PROP_WORST_COMPRESSION_RATIO:
+	case HFI_PROP_WORST_COMPLEXITY_FACTOR:
+	case HFI_PROP_PICTURE_TYPE:
+		is_allowed = true;
+		break;
+	case HFI_PROP_DPB_LIST:
+		if (!is_ubwc_colorformat(inst->capabilities->cap[PIX_FMTS].value)) {
+			i_vpr_h(inst,
+				"%s: cap: %24s not allowed for split mode\n",
+				__func__, cap_name(DPB_LIST));
+			is_allowed = false;
+		}
+		break;
+	default:
+		is_allowed = true;
+		break;
+	}
+
+	return is_allowed;
+}
+
+int msm_vidc_update_property_cap(struct msm_vidc_inst *inst, u32 hfi_id,
+	bool allow)
+{
+	int rc = 0;
+
+	if (!inst || !inst->capabilities) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (hfi_id) {
+	case HFI_PROP_WORST_COMPRESSION_RATIO:
+	case HFI_PROP_WORST_COMPLEXITY_FACTOR:
+	case HFI_PROP_PICTURE_TYPE:
+		break;
+	case HFI_PROP_DPB_LIST:
+		if (!allow)
+			memset(inst->dpb_list_payload, 0, MAX_DPB_LIST_ARRAY_SIZE);
+		msm_vidc_update_cap_value(inst, DPB_LIST, allow, __func__);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
 bool msm_vidc_allow_reqbufs(struct msm_vidc_inst *inst, u32 type)
 {
 	bool allow = false;
@@ -4119,6 +4178,12 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst)
 		msm_vidc_put_vidc_buffer(inst, buf);
 	}
 
+	list_for_each_entry_safe(buf, dummy, &inst->buffers.release.list, list) {
+		print_vidc_buffer(VIDC_ERR, "err", "destroying release buffer", inst, buf);
+		list_del(&buf->list);
+		msm_vidc_put_vidc_buffer(inst, buf);
+	}
+
 	/* destroy buffers from pool */
 	msm_vidc_destroy_vidc_buffer(inst);
 	msm_vidc_destroy_alloc_buffer(inst);

+ 1 - 8
driver/vidc/src/venus_hfi.c

@@ -3440,18 +3440,11 @@ int venus_hfi_release_buffer(struct msm_vidc_inst *inst,
 		goto unlock;
 	}
 
-	if (!is_internal_buffer(buffer->type)) {
-		i_vpr_e(inst, "release not allowed for buffer_type %s\n",
-			buf_name(buffer->type));
-		goto unlock;
-	}
-	core = inst->core;
-
 	rc = get_hfi_buffer(inst, buffer, &hfi_buffer);
 	if (rc)
 		goto unlock;
 
-	/* add pending release flag */
+	/* add release flag */
 	hfi_buffer.flags |= HFI_BUF_HOST_FLAG_RELEASE;
 
 	rc = hfi_create_header(inst->packet, inst->packet_size,

+ 165 - 240
driver/vidc/src/venus_hfi_response.c

@@ -482,18 +482,21 @@ static int get_driver_buffer_flags(struct msm_vidc_inst *inst, u32 hfi_flags)
 }
 
 static int handle_read_only_buffer(struct msm_vidc_inst *inst,
-	struct msm_vidc_buffer *buffer)
+	struct msm_vidc_buffer *buf)
 {
 	struct msm_vidc_buffer *ro_buf;
 	struct msm_vidc_buffers *ro_buffers;
 	bool found = false;
 
-	if (!inst || !buffer) {
+	if (!inst || !buf) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
 
-	if (!is_decode_session(inst) || !is_output_buffer(buffer->type))
+	if (!is_decode_session(inst) || !is_output_buffer(buf->type))
+		return 0;
+
+	if (!(buf->attr & MSM_VIDC_ATTR_READ_ONLY))
 		return 0;
 
 	ro_buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_READ_ONLY, __func__);
@@ -501,38 +504,70 @@ static int handle_read_only_buffer(struct msm_vidc_inst *inst,
 		return -EINVAL;
 
 	list_for_each_entry(ro_buf, &ro_buffers->list, list) {
-		if (ro_buf->device_addr == buffer->device_addr) {
+		if (ro_buf->device_addr == buf->device_addr) {
 			found = true;
 			break;
 		}
 	}
-
 	/*
 	 * RO flag: add to read_only list if buffer is not present
 	 *          if present, do nothing
-	 * Without RO flag: remove buffer from read_only list if present
-	 *          if not present, do not error out
 	 */
-	if (buffer->attr & MSM_VIDC_ATTR_READ_ONLY) {
-		if (!found) {
-			ro_buf = msm_vidc_get_vidc_buffer(inst);
-			if (!ro_buf) {
-				i_vpr_e(inst, "%s: buffer alloc failed\n", __func__);
-				return -ENOMEM;
-			}
-			memcpy(ro_buf, buffer, sizeof(struct msm_vidc_buffer));
-			INIT_LIST_HEAD(&ro_buf->list);
-			list_add_tail(&ro_buf->list, &ro_buffers->list);
-			print_vidc_buffer(VIDC_LOW, "low", "ro buf added", inst, ro_buf);
+	if (!found) {
+		ro_buf = msm_vidc_get_vidc_buffer(inst);
+		if (!ro_buf) {
+			i_vpr_e(inst, "%s: buffer alloc failed\n", __func__);
+			return -ENOMEM;
 		}
-	} else {
-		if (found) {
-			print_vidc_buffer(VIDC_LOW, "low", "ro buf deleted", inst, ro_buf);
-			list_del(&ro_buf->list);
-			msm_vidc_put_vidc_buffer(inst, ro_buf);
+		memcpy(ro_buf, buf, sizeof(struct msm_vidc_buffer));
+		INIT_LIST_HEAD(&ro_buf->list);
+		list_add_tail(&ro_buf->list, &ro_buffers->list);
+		print_vidc_buffer(VIDC_LOW, "low", "ro buf added", inst, ro_buf);
+	}
+	ro_buf->attr |= MSM_VIDC_ATTR_READ_ONLY;
+
+	return 0;
+}
+
+static int handle_non_read_only_buffer(struct msm_vidc_inst *inst,
+	struct hfi_buffer *buffer)
+{
+	struct msm_vidc_buffer *ro_buf;
+	struct msm_vidc_buffers *ro_buffers;
+	bool found = false;
+
+	if (!inst || !buffer) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!is_decode_session(inst) || buffer->type != HFI_BUFFER_RAW)
+		return 0;
+
+	if (buffer->flags & HFI_BUF_FW_FLAG_READONLY)
+		return 0;
+
+	ro_buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_READ_ONLY, __func__);
+	if (!ro_buffers)
+		return -EINVAL;
+
+	list_for_each_entry(ro_buf, &ro_buffers->list, list) {
+		if (ro_buf->device_addr == buffer->base_address) {
+			found = true;
+			break;
 		}
 	}
 
+	/*
+	 * Without RO flag: remove buffer from read_only list if present
+	 *          if not present, do not error out
+	 */
+	if (found) {
+		print_vidc_buffer(VIDC_LOW, "low", "ro buf deleted", inst, ro_buf);
+		list_del(&ro_buf->list);
+		msm_vidc_put_vidc_buffer(inst, ro_buf);
+	}
+
 	return 0;
 }
 
@@ -607,6 +642,19 @@ static int handle_output_buffer(struct msm_vidc_inst *inst,
 	struct msm_vidc_buffer *buf;
 	bool found, fatal = false;
 
+	if (!inst || !inst->capabilities) {
+		d_vpr_e("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (is_decode_session(inst)) {
+		if (!(buffer->flags & HFI_BUF_FW_FLAG_READONLY)) {
+			rc = handle_non_read_only_buffer(inst, buffer);
+			if (rc)
+				msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
+		}
+	}
+
 	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_OUTPUT, __func__);
 	if (!buffers)
 		return -EINVAL;
@@ -622,12 +670,9 @@ static int handle_output_buffer(struct msm_vidc_inst *inst,
 		if (found)
 			break;
 	}
-	if (!found) {
-		i_vpr_e(inst, "%s: invalid idx %d daddr %#x data_offset %d\n",
-			__func__, buffer->index, buffer->base_address,
-			buffer->data_offset);
-		return -EINVAL;
-	}
+	if (!found)
+		return 0;
+
 	buf->data_offset = buffer->data_offset;
 	buf->data_size = buffer->data_size;
 	buf->timestamp = buffer->timestamp;
@@ -678,13 +723,22 @@ static int handle_output_buffer(struct msm_vidc_inst *inst,
 	}
 
 	if (is_decode_session(inst)) {
-		if (buffer->flags & HFI_BUF_FW_FLAG_READONLY)
+		/* RO flag is not expected for linear colorformat */
+		if (is_linear_colorformat(inst->capabilities->cap[PIX_FMTS].value) &&
+			(buffer->flags & HFI_BUF_FW_FLAG_READONLY)) {
+			buffer->flags &= ~HFI_BUF_FW_FLAG_READONLY;
+			print_vidc_buffer(
+				VIDC_HIGH, "err", "RO flag in linear colorformat", inst, buf);
+		}
+
+		if (buffer->flags & HFI_BUF_FW_FLAG_READONLY) {
 			buf->attr |= MSM_VIDC_ATTR_READ_ONLY;
-		else
+			rc = handle_read_only_buffer(inst, buf);
+			if (rc)
+				msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
+		} else {
 			buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY;
-		rc = handle_read_only_buffer(inst, buf);
-		if (rc)
-			return rc;
+		}
 	}
 
 	buf->flags = 0;
@@ -832,66 +886,7 @@ static int handle_dequeue_buffers(struct msm_vidc_inst* inst)
 	return rc;
 }
 
-/* todo: remove below funcs once fw supports rel done flag for internl buf*/
-static int handle_dpb_buffer(struct msm_vidc_inst *inst,
-	struct hfi_buffer *buffer)
-{
-	int rc = 0;
-	struct msm_vidc_buffers *buffers;
-	struct msm_vidc_buffer *buf;
-	bool found;
-
-	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_DPB, __func__);
-	if (!buffers)
-		return -EINVAL;
-
-	found = false;
-	list_for_each_entry(buf, &buffers->list, list) {
-		if (buf->device_addr == buffer->base_address) {
-			found = true;
-			break;
-		}
-	}
-	if (found) {
-		rc = msm_vidc_destroy_internal_buffer(inst, buf);
-	} else {
-		i_vpr_e(inst, "%s: invalid idx %d daddr %#x\n",
-			__func__, buffer->index, buffer->base_address);
-		return -EINVAL;
-	}
-	return rc;
-}
-
-static int handle_persist_buffer(struct msm_vidc_inst *inst,
-	struct hfi_buffer *buffer)
-{
-	int rc = 0;
-	struct msm_vidc_buffers *buffers;
-	struct msm_vidc_buffer *buf;
-	bool found;
-
-	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_PERSIST, __func__);
-	if (!buffers)
-		return -EINVAL;
-
-	found = false;
-	list_for_each_entry(buf, &buffers->list, list) {
-		if (buf->device_addr == buffer->base_address) {
-			found = true;
-			break;
-		}
-	}
-	if (found) {
-		rc = msm_vidc_destroy_internal_buffer(inst, buf);
-	} else {
-		i_vpr_e(inst, "%s: invalid idx %d daddr %#x\n",
-			__func__, buffer->index, buffer->base_address);
-		return -EINVAL;
-	}
-	return rc;
-}
-
-static int handle_line_buffer(struct msm_vidc_inst *inst,
+static int handle_release_internal_buffer(struct msm_vidc_inst *inst,
 	struct hfi_buffer *buffer)
 {
 	int rc = 0;
@@ -899,94 +894,8 @@ static int handle_line_buffer(struct msm_vidc_inst *inst,
 	struct msm_vidc_buffer *buf;
 	bool found;
 
-	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_LINE, __func__);
-	if (!buffers)
-		return -EINVAL;
-
-	found = false;
-	list_for_each_entry(buf, &buffers->list, list) {
-		if (buf->device_addr == buffer->base_address) {
-			found = true;
-			break;
-		}
-	}
-	if (found) {
-		rc = msm_vidc_destroy_internal_buffer(inst, buf);
-	} else {
-		i_vpr_e(inst, "%s: invalid idx %d daddr %#x\n",
-			__func__, buffer->index, buffer->base_address);
-		return -EINVAL;
-	}
-	return rc;
-}
-
-static int handle_non_comv_buffer(struct msm_vidc_inst *inst,
-	struct hfi_buffer *buffer)
-{
-	int rc = 0;
-	struct msm_vidc_buffers *buffers;
-	struct msm_vidc_buffer *buf;
-	bool found;
-
-	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_NON_COMV, __func__);
-	if (!buffers)
-		return -EINVAL;
-
-	found = false;
-	list_for_each_entry(buf, &buffers->list, list) {
-		if (buf->device_addr == buffer->base_address) {
-			found = true;
-			break;
-		}
-	}
-	if (found) {
-		rc = msm_vidc_destroy_internal_buffer(inst, buf);
-	} else {
-		i_vpr_e(inst, "%s: invalid idx %d daddr %#x\n",
-			__func__, buffer->index, buffer->base_address);
-		return -EINVAL;
-	}
-	return rc;
-}
-
-static int handle_comv_buffer(struct msm_vidc_inst *inst,
-	struct hfi_buffer *buffer)
-{
-	int rc = 0;
-	struct msm_vidc_buffers *buffers;
-	struct msm_vidc_buffer *buf;
-	bool found;
-
-	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_COMV, __func__);
-	if (!buffers)
-		return -EINVAL;
-
-	found = false;
-	list_for_each_entry(buf, &buffers->list, list) {
-		if (buf->device_addr == buffer->base_address) {
-			found = true;
-			break;
-		}
-	}
-	if (found) {
-		rc = msm_vidc_destroy_internal_buffer(inst, buf);
-	} else {
-		i_vpr_e(inst, "%s: invalid idx %d daddr %#x\n",
-			__func__, buffer->index, buffer->base_address);
-		return -EINVAL;
-	}
-	return rc;
-}
-
-static int handle_bin_buffer(struct msm_vidc_inst *inst,
-	struct hfi_buffer *buffer)
-{
-	int rc = 0;
-	struct msm_vidc_buffers *buffers;
-	struct msm_vidc_buffer *buf;
-	bool found;
-
-	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_BIN, __func__);
+	buffers = msm_vidc_get_buffers(inst, hfi_buf_type_to_driver(inst->domain,
+		buffer->type, HFI_PORT_NONE), __func__);
 	if (!buffers)
 		return -EINVAL;
 
@@ -997,37 +906,14 @@ static int handle_bin_buffer(struct msm_vidc_inst *inst,
 			break;
 		}
 	}
-	if (found) {
-		rc = msm_vidc_destroy_internal_buffer(inst, buf);
-	} else {
-		i_vpr_e(inst, "%s: invalid idx %d daddr %#x\n",
-			__func__, buffer->index, buffer->base_address);
-		return -EINVAL;
-	}
-	return rc;
-}
-
-static int handle_arp_buffer(struct msm_vidc_inst *inst,
-	struct hfi_buffer *buffer)
-{
-	int rc = 0;
-	struct msm_vidc_buffers *buffers;
-	struct msm_vidc_buffer *buf;
-	bool found;
 
-	buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_ARP, __func__);
-	if (!buffers)
-		return -EINVAL;
+	if (!is_internal_buffer(buf->type))
+		return 0;
 
-	found = false;
-	list_for_each_entry(buf, &buffers->list, list) {
-		if (buf->device_addr == buffer->base_address) {
-			found = true;
-			break;
-		}
-	}
 	if (found) {
 		rc = msm_vidc_destroy_internal_buffer(inst, buf);
+		if (rc)
+			return rc;
 	} else {
 		i_vpr_e(inst, "%s: invalid idx %d daddr %#x\n",
 			__func__, buffer->index, buffer->base_address);
@@ -1036,21 +922,14 @@ static int handle_arp_buffer(struct msm_vidc_inst *inst,
 	return rc;
 }
 
-static int handle_release_buffer(struct msm_vidc_inst *inst,
+static int handle_release_output_buffer(struct msm_vidc_inst *inst,
 	struct hfi_buffer *buffer, enum hfi_packet_port_type port_type)
 {
 	int rc = 0;
-	struct msm_vidc_buffers *buffers;
 	struct msm_vidc_buffer *buf;
-	bool found;
-
-	buffers = msm_vidc_get_buffers(inst, hfi_buf_type_to_driver(inst->domain,
-		buffer->type, port_type), __func__);
-	if (!buffers)
-		return -EINVAL;
+	bool found = false;
 
-	found = false;
-	list_for_each_entry(buf, &buffers->list, list) {
+	list_for_each_entry(buf, &inst->buffers.release.list, list) {
 		if (buf->device_addr == buffer->base_address) {
 			found = true;
 			break;
@@ -1061,10 +940,8 @@ static int handle_release_buffer(struct msm_vidc_inst *inst,
 			__func__, buffer->index, buffer->base_address);
 		return -EINVAL;
 	}
-	if (is_internal_buffer(buf->type))
-		rc = msm_vidc_destroy_internal_buffer(inst, buf);
-	else
-		rc = msm_vidc_put_driver_buf(inst, buf);
+
+	rc = msm_vdec_handle_release_buffer(inst, buf);
 	if (rc)
 		return rc;
 
@@ -1085,26 +962,26 @@ static int handle_session_buffer(struct msm_vidc_inst *inst,
 	static const struct msm_vidc_hfi_buffer_handle enc_output_hfi_handle[] = {
 		{HFI_BUFFER_METADATA,       handle_output_metadata_buffer     },
 		{HFI_BUFFER_BITSTREAM,      handle_output_buffer              },
-		{HFI_BUFFER_BIN,            handle_bin_buffer                 },
-		{HFI_BUFFER_COMV,           handle_comv_buffer                },
-		{HFI_BUFFER_NON_COMV,       handle_non_comv_buffer            },
-		{HFI_BUFFER_LINE,           handle_line_buffer                },
-		{HFI_BUFFER_ARP,            handle_arp_buffer                 },
-		{HFI_BUFFER_DPB,            handle_dpb_buffer                 },
+		{HFI_BUFFER_BIN,            handle_release_internal_buffer    },
+		{HFI_BUFFER_COMV,           handle_release_internal_buffer    },
+		{HFI_BUFFER_NON_COMV,       handle_release_internal_buffer    },
+		{HFI_BUFFER_LINE,           handle_release_internal_buffer    },
+		{HFI_BUFFER_ARP,            handle_release_internal_buffer    },
+		{HFI_BUFFER_DPB,            handle_release_internal_buffer    },
 	};
 	static const struct msm_vidc_hfi_buffer_handle dec_input_hfi_handle[] = {
 		{HFI_BUFFER_METADATA,       handle_input_metadata_buffer      },
 		{HFI_BUFFER_BITSTREAM,      handle_input_buffer               },
-		{HFI_BUFFER_BIN,            handle_bin_buffer                 },
-		{HFI_BUFFER_COMV,           handle_comv_buffer                },
-		{HFI_BUFFER_NON_COMV,       handle_non_comv_buffer            },
-		{HFI_BUFFER_LINE,           handle_line_buffer                },
-		{HFI_BUFFER_PERSIST,        handle_persist_buffer             },
+		{HFI_BUFFER_BIN,            handle_release_internal_buffer    },
+		{HFI_BUFFER_COMV,           handle_release_internal_buffer    },
+		{HFI_BUFFER_NON_COMV,       handle_release_internal_buffer    },
+		{HFI_BUFFER_LINE,           handle_release_internal_buffer    },
+		{HFI_BUFFER_PERSIST,        handle_release_internal_buffer    },
 	};
 	static const struct msm_vidc_hfi_buffer_handle dec_output_hfi_handle[] = {
 		{HFI_BUFFER_METADATA,       handle_output_metadata_buffer     },
 		{HFI_BUFFER_RAW,            handle_output_buffer              },
-		{HFI_BUFFER_DPB,            handle_dpb_buffer                 },
+		{HFI_BUFFER_DPB,            handle_release_internal_buffer    },
 	};
 
 	if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) {
@@ -1129,8 +1006,9 @@ static int handle_session_buffer(struct msm_vidc_inst *inst,
 		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
 		return 0;
 	}
-	if (buffer->flags & HFI_BUF_FW_FLAG_RELEASE_DONE)
-		return handle_release_buffer(inst, buffer, pkt->port);
+	if (is_decode_session(inst) && buffer->type == HFI_BUFFER_RAW &&
+		buffer->flags & HFI_BUF_FW_FLAG_RELEASE_DONE)
+		return handle_release_output_buffer(inst, buffer, pkt->port);
 
 	if (is_encode_session(inst)) {
 		if (pkt->port == HFI_PORT_RAW) {
@@ -1272,6 +1150,36 @@ static int handle_session_command(struct msm_vidc_inst *inst,
 	return 0;
 }
 
+static int handle_dpb_list_property(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	u32 payload_size, num_words_in_payload;
+	u8 *payload_start;
+	int i = 0;
+
+	payload_size = pkt->size - sizeof(struct hfi_packet);
+	num_words_in_payload = payload_size / 4;
+	payload_start = (u8 *)((u8 *)pkt + sizeof(struct hfi_packet));
+	memset(inst->dpb_list_payload, 0, MAX_DPB_LIST_ARRAY_SIZE);
+
+	if (payload_size > MAX_DPB_LIST_PAYLOAD_SIZE) {
+		i_vpr_e(inst,
+			"%s: dpb list payload size %d exceeds expected max size %d\n",
+			__func__, payload_size, MAX_DPB_LIST_PAYLOAD_SIZE);
+		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
+	}
+	memcpy(inst->dpb_list_payload, payload_start, payload_size);
+
+	for (i = 0; (i + 3) < num_words_in_payload; i = i + 4) {
+		i_vpr_l(inst,
+			"%s: base addr %#x %#x, addr offset %#x, data offset %#x\n",
+			__func__, inst->dpb_list_payload[i], inst->dpb_list_payload[i + 1],
+			inst->dpb_list_payload[i + 2], inst->dpb_list_payload[i + 3]);
+	}
+
+	return 0;
+}
+
 static int handle_session_property(struct msm_vidc_inst *inst,
 	struct hfi_packet *pkt)
 {
@@ -1279,6 +1187,11 @@ static int handle_session_property(struct msm_vidc_inst *inst,
 	u32 port;
 	u32 *payload_ptr;
 
+	if (!inst || !inst->capabilities) {
+		d_vpr_e("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
 	i_vpr_l(inst, "%s: property type %#x\n", __func__, pkt->type);
 
 	port = vidc_port_from_hfi(inst, pkt->port);
@@ -1327,7 +1240,6 @@ static int handle_session_property(struct msm_vidc_inst *inst,
 		break;
 	case HFI_PROP_NO_OUTPUT:
 		if (port != INPUT_PORT) {
-			rc = -EINVAL;
 			i_vpr_e(inst,
 				"%s: invalid port: %d for property %#x\n",
 				__func__, pkt->port, pkt->type);
@@ -1341,10 +1253,23 @@ static int handle_session_property(struct msm_vidc_inst *inst,
 	case HFI_PROP_WORST_COMPLEXITY_FACTOR:
 		inst->power.fw_cf = payload_ptr[0];
 		break;
+	case HFI_PROP_DPB_LIST:
+		if (is_decode_session(inst) && port == OUTPUT_PORT &&
+			inst->capabilities->cap[DPB_LIST].value) {
+			rc = handle_dpb_list_property(inst, pkt);
+			if (rc)
+				break;
+		} else {
+			i_vpr_e(inst,
+				"%s: invalid property %#x for %s port %d dpb cap value %d\n",
+				__func__, is_decode_session(inst) ? "decode" : "encode",
+				port, inst->capabilities->cap[DPB_LIST].value);
+		}
+		break;
 	default:
-		i_vpr_e(inst, "%s: invalid port settings property %#x\n",
+		i_vpr_e(inst, "%s: invalid property %#x\n",
 			__func__, pkt->type);
-		return -EINVAL;
+		break;
 	}
 
 	return rc;