Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73aab53e authored by Praneeth Paladugu's avatar Praneeth Paladugu
Browse files

msm: vidc: Add support for decoder downscaling



Venus FW supports downscaling for decoder. Venus
FW sends the supported downscaled ratios. Driver
needs to make sure that the scaling is inside the
supported range. This change adds the support for
decoder downscaling.

Change-Id: I919e563a6ba64751b3355658bcdbcec9d9ef17eb
Signed-off-by: default avatarPraneeth Paladugu <ppaladug@codeaurora.org>
parent 6135ac7d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -294,12 +294,18 @@ static u32 get_hfi_buffer(int hal_buffer)
	case HAL_BUFFER_OUTPUT:
		buffer = HFI_BUFFER_OUTPUT;
		break;
	case HAL_BUFFER_OUTPUT2:
		buffer = HFI_BUFFER_OUTPUT2;
		break;
	case HAL_BUFFER_EXTRADATA_INPUT:
		buffer = HFI_BUFFER_EXTRADATA_INPUT;
		break;
	case HAL_BUFFER_EXTRADATA_OUTPUT:
		buffer = HFI_BUFFER_EXTRADATA_OUTPUT;
		break;
	case HAL_BUFFER_EXTRADATA_OUTPUT2:
		buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
		break;
	case HAL_BUFFER_INTERNAL_SCRATCH:
		buffer = HFI_BUFFER_INTERNAL_SCRATCH;
		break;
+1 −0
Original line number Diff line number Diff line
@@ -957,6 +957,7 @@ static void hfi_process_session_ftb_done(
		data_done.output_done.packet_buffer1 = pkt->packet_buffer;
		data_done.output_done.extra_data_buffer =
			pkt->extra_data_buffer;
		data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
		dprintk(VIDC_DBG, "FBD: Received buf: %p, of len: %d\n",
				   pkt->packet_buffer, pkt->filled_len);
	} else if (is_decoder == 1) {
+221 −23
Original line number Diff line number Diff line
@@ -308,6 +308,22 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
		.qmenu = NULL,
		.cluster = 0,
	},
	{
		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE,
		.name = "Video decoder multi stream",
		.type = V4L2_CTRL_TYPE_BOOLEAN,
		.minimum =
			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
		.maximum =
			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY,
		.default_value =
			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
		.step = 1,
		.menu_skip_mask = 0,
		.step = 1,
		.qmenu = NULL,
		.cluster = 0,
	},
};

#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
@@ -497,7 +513,8 @@ int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
				b->m.planes[i].length);
			}
			buffer_info.buffer_size = b->m.planes[0].length;
			buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
			buffer_info.buffer_type =
				msm_comm_get_hal_output_buffer(inst);
			buffer_info.num_buffers = 1;
			buffer_info.align_device_addr =
				b->m.planes[0].m.userptr;
@@ -581,7 +598,8 @@ int msm_vdec_release_buf(struct msm_vidc_inst *inst,
				b->m.planes[i].length);
			}
			buffer_info.buffer_size = b->m.planes[0].length;
			buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
			buffer_info.buffer_type =
				msm_comm_get_hal_output_buffer(inst);
			buffer_info.num_buffers = 1;
			buffer_info.align_device_addr =
				 b->m.planes[0].m.userptr;
@@ -669,7 +687,6 @@ int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
	const struct msm_vidc_format *fmt = NULL;
	struct hal_frame_size frame_sz;
	struct hfi_device *hdev;
	int stride, scanlines;
	int extra_idx = 0;
@@ -691,8 +708,22 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
		f->fmt.pix_mp.pixelformat = fmt->fourcc;
		f->fmt.pix_mp.num_planes = fmt->num_planes;
		if (inst->in_reconfig == true) {
			inst->prop.height[CAPTURE_PORT] = inst->reconfig_height;
			inst->prop.width[CAPTURE_PORT] = inst->reconfig_width;
			if (msm_comm_get_stream_output_mode(inst) ==
				HAL_VIDEO_DECODER_PRIMARY) {
				inst->prop.height[CAPTURE_PORT] =
					inst->reconfig_height;
				inst->prop.width[CAPTURE_PORT] =
					inst->reconfig_width;
				inst->prop.height[OUTPUT_PORT] =
					inst->reconfig_height;
				inst->prop.width[OUTPUT_PORT] =
					inst->reconfig_width;
			} else {
				inst->prop.height[OUTPUT_PORT] =
					inst->reconfig_height;
				inst->prop.width[OUTPUT_PORT] =
					inst->reconfig_width;
			}
			rc = msm_vidc_check_session_supported(inst);
			if (rc) {
				dprintk(VIDC_ERR,
@@ -704,11 +735,6 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
		f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
		stride = inst->prop.width[CAPTURE_PORT];
		scanlines = inst->prop.height[CAPTURE_PORT];
		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
		frame_sz.width = inst->prop.width[CAPTURE_PORT];
		frame_sz.height = inst->prop.height[CAPTURE_PORT];
		dprintk(VIDC_DBG, "width = %d, height = %d\n",
				frame_sz.width, frame_sz.height);
		rc = msm_comm_try_get_bufreqs(inst);
		if (rc) {
			dprintk(VIDC_ERR,
@@ -734,7 +760,8 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
					"Color format not recognized\n");
			}
			buff_req_buffer =
				get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
				get_buff_req_buffer(inst,
					msm_comm_get_hal_output_buffer(inst));
			if (buff_req_buffer)
				f->fmt.pix_mp.plane_fmt[0].sizeimage =
				buff_req_buffer->buffer_size;
@@ -838,8 +865,7 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
	int max_input_size = 0;

	if (!inst || !f) {
		dprintk(VIDC_ERR,
			"Invalid input, inst = %p, format = %p\n", inst, f);
		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
		return -EINVAL;
	}
	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
@@ -856,9 +882,24 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
		}
		inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
		inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
		if (msm_comm_get_stream_output_mode(inst) ==
			HAL_VIDEO_DECODER_PRIMARY) {
			inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
			inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
		}
		inst->fmts[fmt->type] = fmt;
		if (msm_comm_get_stream_output_mode(inst) ==
			HAL_VIDEO_DECODER_SECONDARY) {
			frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
			frame_sz.width = inst->prop.width[CAPTURE_PORT];
			frame_sz.height = inst->prop.height[CAPTURE_PORT];
			dprintk(VIDC_DBG,
				"buffer type = %d width = %d, height = %d\n",
				frame_sz.buffer_type, frame_sz.width,
				frame_sz.height);
			ret = msm_comm_try_set_prop(inst,
				HAL_PARAM_FRAME_SIZE, &frame_sz);
		}
		ret = ret || msm_comm_try_get_bufreqs(inst);
		if (ret) {
			for (i = 0; i < fmt->num_planes; ++i) {
@@ -869,7 +910,8 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
			}
		} else {
			buff_req_buffer =
				get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
				get_buff_req_buffer(inst,
					msm_comm_get_hal_output_buffer(inst));
			if (buff_req_buffer)
				f->fmt.pix_mp.plane_fmt[0].sizeimage =
				buff_req_buffer->buffer_size;
@@ -896,8 +938,11 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
		inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
		inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
		if (msm_comm_get_stream_output_mode(inst) ==
			HAL_VIDEO_DECODER_PRIMARY) {
			inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
			inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
		}
		rc = msm_vidc_check_session_supported(inst);
		if (rc) {
			dprintk(VIDC_ERR,
@@ -924,6 +969,10 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
		frame_sz.buffer_type = HAL_BUFFER_INPUT;
		frame_sz.width = inst->prop.width[OUTPUT_PORT];
		frame_sz.height = inst->prop.height[OUTPUT_PORT];
		dprintk(VIDC_DBG,
			"buffer type = %d width = %d, height = %d\n",
			frame_sz.buffer_type, frame_sz.width,
			frame_sz.height);
		msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);

		max_input_size = fmt->get_frame_size(0,
@@ -1056,7 +1105,8 @@ static int msm_vdec_queue_setup(struct vb2_queue *q,
			break;
		}
		mutex_lock(&inst->lock);
		bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
		bufreq = get_buff_req_buffer(inst,
			msm_comm_get_hal_output_buffer(inst));
		if (!bufreq) {
			dprintk(VIDC_ERR,
				"No buffer requirement for buffer type %x\n",
@@ -1068,7 +1118,8 @@ static int msm_vdec_queue_setup(struct vb2_queue *q,
		*num_buffers = max(*num_buffers, bufreq->buffer_count_min);
		if (*num_buffers != bufreq->buffer_count_actual) {
			property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
			new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
			new_buf_count.buffer_type =
				msm_comm_get_hal_output_buffer(inst);
			new_buf_count.buffer_count_actual = *num_buffers;
			rc = call_hfi_op(hdev, session_set_property,
				inst->session, property_id, &new_buf_count);
@@ -1098,14 +1149,75 @@ static int msm_vdec_queue_setup(struct vb2_queue *q,
	return rc;
}

static int msm_vdec_queue_output_buffers(struct msm_vidc_inst *inst)
{
	struct internal_buf *binfo;
	struct hfi_device *hdev;
	struct msm_smem *handle;
	struct vidc_frame_data frame_data = {0};
	struct hal_buffer_requirements *output_buf, *extradata_buf;
	int rc = 0;
	hdev = inst->core->device;

	output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
	if (!output_buf) {
		dprintk(VIDC_DBG,
			"This output buffer not required, buffer_type: %x\n",
			HAL_BUFFER_OUTPUT);
		return 0;
	}
	dprintk(VIDC_DBG,
		"output: num = %d, size = %d\n",
		output_buf->buffer_count_actual,
		output_buf->buffer_size);

	extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
	if (!extradata_buf) {
		dprintk(VIDC_DBG,
			"This extradata buffer not required, buffer_type: %x\n",
			HAL_BUFFER_EXTRADATA_OUTPUT);
		return 0;
	}

	hdev = inst->core->device;

	mutex_lock(&inst->lock);
	if (!list_empty(&inst->outputbufs)) {
		list_for_each_entry(binfo, &inst->outputbufs, list) {
			if (!binfo) {
				dprintk(VIDC_ERR, "Invalid parameter\n");
				mutex_unlock(&inst->lock);
				return -EINVAL;
			}
			handle = binfo->handle;
			frame_data.alloc_len = output_buf->buffer_size;
			frame_data.filled_len = 0;
			frame_data.offset = 0;
			frame_data.device_addr = handle->device_addr;
			frame_data.flags = 0;
			frame_data.extradata_addr = handle->device_addr +
				output_buf->buffer_size;
			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
			rc = call_hfi_op(hdev, session_ftb,
					(void *) inst->session, &frame_data);
			binfo->buffer_ownership = FIRMWARE;
		}
	}
	mutex_unlock(&inst->lock);
	return 0;
}

static inline int start_streaming(struct msm_vidc_inst *inst)
{
	int rc = 0;
	struct vb2_buf_entry *temp;
	struct hfi_device *hdev;
	struct list_head *ptr, *next;

	hdev = inst->core->device;
	inst->in_reconfig = false;
	if (inst->capability.pixelprocess_capabilities &
		HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)
	if (msm_comm_get_stream_output_mode(inst) ==
		HAL_VIDEO_DECODER_SECONDARY)
		rc = msm_vidc_check_scaling_supported(inst);
	if (rc) {
		dprintk(VIDC_ERR, "H/w scaling is not in valid range");
@@ -1124,6 +1236,15 @@ static inline int start_streaming(struct msm_vidc_inst *inst)
		goto fail_start;
	}

	if (msm_comm_get_stream_output_mode(inst) ==
		HAL_VIDEO_DECODER_SECONDARY) {
		rc = msm_comm_set_output_buffers(inst);
		if (rc) {
			dprintk(VIDC_ERR,
				"Failed to set output buffers: %d\n", rc);
			goto fail_start;
		}
	}
	mutex_lock(&inst->core->sync_lock);
	msm_comm_scale_clocks_and_bus(inst);
	mutex_unlock(&inst->core->sync_lock);
@@ -1134,7 +1255,15 @@ static inline int start_streaming(struct msm_vidc_inst *inst)
			"Failed to move inst: %p to start done state\n", inst);
		goto fail_start;
	}

	if (msm_comm_get_stream_output_mode(inst) ==
		HAL_VIDEO_DECODER_SECONDARY) {
		rc = msm_vdec_queue_output_buffers(inst);
		if (rc) {
			dprintk(VIDC_ERR,
				"Failed to queue output buffers: %d\n", rc);
			goto fail_start;
		}
	}
	mutex_lock(&inst->sync_lock);
	if (!list_empty(&inst->pendingq)) {
		list_for_each_safe(ptr, next, &inst->pendingq) {
@@ -1390,6 +1519,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
	struct hfi_device *hdev;
	struct hal_extradata_enable extra;
	struct hal_buffer_alloc_mode alloc_mode;
	struct hal_multi_stream multi_stream;

	if (!inst || !inst->core || !inst->core->device) {
		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1518,6 +1648,70 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
		inst->buffer_mode_set[CAPTURE_PORT] = alloc_mode.buffer_mode;
		break;

	case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
		if (ctrl->val && !(inst->capability.pixelprocess_capabilities &
				HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)) {
			dprintk(VIDC_ERR, "Downscaling not supported: 0x%x",
				ctrl->id);
			rc = -ENOTSUPP;
			break;
		}
		switch (ctrl->val) {
		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY:
			multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
			multi_stream.enable = true;
			pdata = &multi_stream;
			rc = call_hfi_op(hdev, session_set_property, (void *)
				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
				pdata);
			if (rc) {
				dprintk(VIDC_ERR,
					"Failed : Enabling OUTPUT port : %d\n",
					rc);
				break;
			}
			multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
			multi_stream.enable = false;
			pdata = &multi_stream;
			rc = call_hfi_op(hdev, session_set_property, (void *)
				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
				pdata);
			if (rc)
				dprintk(VIDC_ERR,
					"Failed:Disabling OUTPUT2 port : %d\n",
					rc);
			break;
		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY:
			multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
			multi_stream.enable = true;
			pdata = &multi_stream;
			rc = call_hfi_op(hdev, session_set_property, (void *)
				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
				pdata);
			if (rc) {
				dprintk(VIDC_ERR,
					"Failed :Enabling OUTPUT2 port : %d\n",
					rc);
					break;
			}
			multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
			multi_stream.enable = false;
			pdata = &multi_stream;
			rc = call_hfi_op(hdev, session_set_property, (void *)
				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
				pdata);
			if (rc)
				dprintk(VIDC_ERR,
					"Failed :Disabling OUTPUT port : %d\n",
					rc);
			break;
		default:
			dprintk(VIDC_ERR,
				"Failed : Unsupported multi stream setting\n");
			rc = -ENOTSUPP;
			break;
		}
		break;
	default:
		break;
	}
@@ -1538,6 +1732,10 @@ static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
	int rc = 0, c = 0;
	struct msm_vidc_inst *inst = container_of(ctrl->handler,
				struct msm_vidc_inst, ctrl_handler);
	if (!inst) {
		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
		return -EINVAL;
	}
	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
	if (rc) {
		dprintk(VIDC_ERR,
+12 −0
Original line number Diff line number Diff line
@@ -1140,6 +1140,7 @@ void *msm_vidc_open(int core_id, int session_type)
	INIT_LIST_HEAD(&inst->persistbufs);
	INIT_LIST_HEAD(&inst->ctrl_clusters);
	INIT_LIST_HEAD(&inst->registered_bufs);
	INIT_LIST_HEAD(&inst->outputbufs);
	init_waitqueue_head(&inst->kernel_event_queue);
	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
	inst->core = core;
@@ -1247,6 +1248,17 @@ static void cleanup_instance(struct msm_vidc_inst *inst)
				mutex_lock(&inst->lock);
			}
		}
		if (!list_empty(&inst->outputbufs)) {
			list_for_each_safe(ptr, next, &inst->outputbufs) {
				buf = list_entry(ptr, struct internal_buf,
						list);
				list_del(&buf->list);
				mutex_unlock(&inst->lock);
				msm_smem_free(inst->mem_client, buf->handle);
				kfree(buf);
				mutex_lock(&inst->lock);
			}
		}
		if (inst->extradata_handle) {
			mutex_unlock(&inst->lock);
			msm_smem_free(inst->mem_client, inst->extradata_handle);
+297 −6
Original line number Diff line number Diff line
@@ -83,7 +83,21 @@ static bool is_thumbnail_session(struct msm_vidc_inst *inst)
	}
	return false;
}
enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst)
{
	if (inst->session_type == MSM_VIDC_DECODER) {
		int rc = 0;
		struct v4l2_control ctrl = {
			.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE
		};
		rc = v4l2_g_ctrl(&inst->ctrl_handler, &ctrl);
		if (!rc && ctrl.value)
			return HAL_VIDEO_DECODER_SECONDARY;
	}
	return HAL_VIDEO_DECODER_PRIMARY;


}
static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst)
{
	int height, width;
@@ -656,13 +670,51 @@ static void handle_release_res_done(enum command_response cmd, void *data)
			"Failed to get valid response for release resource\n");
	}
}
void validate_output_buffers(struct msm_vidc_inst *inst)
{
	struct internal_buf *binfo;
	u32 buffers_owned_by_driver = 0;
	struct hal_buffer_requirements *output_buf;
	output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
	if (!output_buf) {
		dprintk(VIDC_DBG,
			"This output buffer not required, buffer_type: %x\n",
			HAL_BUFFER_OUTPUT);
		return;
	}
	list_for_each_entry(binfo, &inst->outputbufs, list) {
		if (!binfo) {
			dprintk(VIDC_ERR, "Invalid parameter\n");
			return;
		}
		if (binfo->buffer_ownership != DRIVER) {
			dprintk(VIDC_ERR,
					"Failed : This buffer is with FW 0x%lx\n",
					binfo->handle->device_addr);
			return;
		}
		buffers_owned_by_driver++;
	}
	if (buffers_owned_by_driver != output_buf->buffer_count_actual)
		dprintk(VIDC_ERR,
			"OUTPUT Buffer count mismatch %d of %d",
			buffers_owned_by_driver,
			output_buf->buffer_count_actual);

	return;
}
static void handle_session_flush(enum command_response cmd, void *data)
{
	struct msm_vidc_cb_cmd_done *response = data;
	struct msm_vidc_inst *inst;
	if (response) {
		inst = (struct msm_vidc_inst *)response->session_id;
		if (msm_comm_get_stream_output_mode(inst) ==
			HAL_VIDEO_DECODER_SECONDARY) {
			mutex_lock(&inst->lock);
			validate_output_buffers(inst);
			mutex_unlock(&inst->lock);
		}
		msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
	} else {
		dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
@@ -986,12 +1038,55 @@ static void handle_dynamic_buffer(struct msm_vidc_inst *inst,
	}
}

static int handle_multi_stream_buffers(struct msm_vidc_inst *inst,
	u32 dev_addr)
{
	struct internal_buf *binfo;
	struct msm_smem *handle;
	bool found = false;
	mutex_lock(&inst->lock);
	list_for_each_entry(binfo, &inst->outputbufs, list) {
		if (!binfo) {
			dprintk(VIDC_ERR, "Invalid parameter\n");
			break;
		}
		handle = binfo->handle;
		if (handle && dev_addr == handle->device_addr) {
			if (binfo->buffer_ownership == DRIVER) {
				dprintk(VIDC_ERR,
					"FW returned same buffer : 0x%x\n",
					dev_addr);
				break;
			}
			binfo->buffer_ownership = DRIVER;
			found = true;
			break;
		}
	}
	if (!found)
		dprintk(VIDC_ERR,
			"Failed to find output buffer in queued list: 0x%x\n",
			dev_addr);
	mutex_unlock(&inst->lock);
	return 0;
}

enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst)
{
	if (msm_comm_get_stream_output_mode(inst) ==
		HAL_VIDEO_DECODER_SECONDARY)
		return HAL_BUFFER_OUTPUT2;
	else
		return HAL_BUFFER_OUTPUT;
}

static void handle_fbd(enum command_response cmd, void *data)
{
	struct msm_vidc_cb_data_done *response = data;
	struct msm_vidc_inst *inst;
	struct vb2_buffer *vb;
	struct vb2_buffer *vb = NULL;
	struct vidc_hal_fbd *fill_buf_done;
	enum hal_buffer buffer_type;

	if (!response) {
		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
@@ -999,8 +1094,18 @@ static void handle_fbd(enum command_response cmd, void *data)
	}
	inst = (struct msm_vidc_inst *)response->session_id;
	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
	buffer_type = msm_comm_get_hal_output_buffer(inst);
	if (fill_buf_done->buffer_type == buffer_type)
		vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
			(u32)fill_buf_done->packet_buffer1);
	else {
		if (handle_multi_stream_buffers(inst,
			(u32)fill_buf_done->packet_buffer1))
			dprintk(VIDC_ERR,
				"Failed : Output buffer not found 0x%x\n",
				(u32)fill_buf_done->packet_buffer1);
		return;
	}
	if (vb) {
		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
		vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
@@ -1829,6 +1934,110 @@ struct hal_buffer_requirements *get_buff_req_buffer(
	return NULL;
}

static int set_output_buffers(struct msm_vidc_inst *inst,
	enum hal_buffer buffer_type)
{
	int rc = 0;
	struct msm_smem *handle;
	struct internal_buf *binfo;
	struct vidc_buffer_addr_info buffer_info;
	u32 smem_flags = 0, buffer_size;
	struct hal_buffer_requirements *output_buf, *extradata_buf;
	int i;
	struct hfi_device *hdev;

	hdev = inst->core->device;

	output_buf = get_buff_req_buffer(inst, buffer_type);
	if (!output_buf) {
		dprintk(VIDC_DBG,
			"This output buffer not required, buffer_type: %x\n",
			buffer_type);
		return 0;
	}
	dprintk(VIDC_DBG,
		"output: num = %d, size = %d\n",
		output_buf->buffer_count_actual,
		output_buf->buffer_size);

	extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
	if (!extradata_buf) {
		dprintk(VIDC_DBG,
			"This extradata buffer not required, buffer_type: %x\n",
			buffer_type);
		return 0;
	}
	dprintk(VIDC_DBG,
		"extradata: num = %d, size = %d\n",
		extradata_buf->buffer_count_actual,
		extradata_buf->buffer_size);

	buffer_size = output_buf->buffer_size + extradata_buf->buffer_size;
	if (inst->flags & VIDC_SECURE)
		smem_flags |= SMEM_SECURE;

	if (output_buf->buffer_size) {
		for (i = 0; i < output_buf->buffer_count_actual;
				i++) {
			handle = msm_smem_alloc(inst->mem_client,
					buffer_size, 1, smem_flags,
					buffer_type, 0);
			if (!handle) {
				dprintk(VIDC_ERR,
					"Failed to allocate output memory\n");
				rc = -ENOMEM;
				goto err_no_mem;
			}
			rc = msm_smem_cache_operations(inst->mem_client,
					handle, SMEM_CACHE_CLEAN);
			if (rc) {
				dprintk(VIDC_WARN,
					"Failed to clean cache may cause undefined behavior\n");
			}
			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
			if (!binfo) {
				dprintk(VIDC_ERR, "Out of memory\n");
				rc = -ENOMEM;
				goto fail_kzalloc;
			}
			mutex_lock(&inst->lock);
			binfo->handle = handle;
			buffer_info.buffer_size = output_buf->buffer_size;
			buffer_info.buffer_type = buffer_type;
			binfo->buffer_type = buffer_type;
			buffer_info.num_buffers = 1;
			binfo->buffer_ownership = DRIVER;
			buffer_info.align_device_addr = handle->device_addr;
			buffer_info.extradata_addr = handle->device_addr +
				output_buf->buffer_size;
			buffer_info.extradata_size = extradata_buf->buffer_size;
			dprintk(VIDC_DBG, "Output buffer address: %x",
					buffer_info.align_device_addr);
			dprintk(VIDC_DBG, "Output extradata address: %x",
					buffer_info.extradata_addr);
			rc = call_hfi_op(hdev, session_set_buffers,
					(void *) inst->session, &buffer_info);
			mutex_unlock(&inst->lock);
			if (rc) {
				dprintk(VIDC_ERR,
					"%s : session_set_buffers failed",
					__func__);
				goto fail_set_buffers;
			}
			mutex_lock(&inst->lock);
			list_add_tail(&binfo->list, &inst->outputbufs);
			mutex_unlock(&inst->lock);
		}
	}
	return rc;
fail_set_buffers:
	kfree(binfo);
fail_kzalloc:
	msm_smem_free(inst->mem_client, handle);
err_no_mem:
	return rc;
}

static int set_scratch_buffers(struct msm_vidc_inst *inst,
	enum hal_buffer buffer_type)
{
@@ -2232,7 +2441,8 @@ int msm_comm_qbuf(struct vb2_buffer *vb)
			frame_data.filled_len = 0;
			frame_data.offset = 0;
			frame_data.alloc_len = vb->v4l2_planes[0].length;
			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
			frame_data.buffer_type =
				msm_comm_get_hal_output_buffer(inst);
			extra_idx =
			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES) &&
@@ -2326,6 +2536,62 @@ exit:
	mutex_unlock(&inst->sync_lock);
	return rc;
}
int msm_comm_release_output_buffers(struct msm_vidc_inst *inst)
{
	struct msm_smem *handle;
	struct list_head *ptr, *next;
	struct internal_buf *buf;
	struct vidc_buffer_addr_info buffer_info;
	int rc = 0;
	struct msm_vidc_core *core;
	struct hfi_device *hdev;
	if (!inst) {
		dprintk(VIDC_ERR,
				"Invalid instance pointer = %p\n", inst);
		return -EINVAL;
	}
	core = inst->core;
	if (!core) {
		dprintk(VIDC_ERR,
				"Invalid core pointer = %p\n", core);
		return -EINVAL;
	}
	hdev = core->device;
	if (!hdev) {
		dprintk(VIDC_ERR, "Invalid device pointer = %p\n", hdev);
		return -EINVAL;
	}
	mutex_lock(&inst->lock);
	if (!list_empty(&inst->outputbufs)) {
		list_for_each_safe(ptr, next, &inst->outputbufs) {
			buf = list_entry(ptr, struct internal_buf,
					list);
			handle = buf->handle;
			buffer_info.buffer_size = handle->size;
			buffer_info.buffer_type = buf->buffer_type;
			buffer_info.num_buffers = 1;
			buffer_info.align_device_addr = handle->device_addr;
			if (inst->state != MSM_VIDC_CORE_INVALID &&
					core->state != VIDC_CORE_INVALID) {
				buffer_info.response_required = false;
				rc = call_hfi_op(hdev, session_release_buffers,
					(void *)inst->session, &buffer_info);
				if (rc)
					dprintk(VIDC_WARN,
						"Rel output buf fail:0x%x, %d",
						buffer_info.align_device_addr,
						buffer_info.buffer_size);
			}
			list_del(&buf->list);
			mutex_unlock(&inst->lock);
			msm_smem_free(inst->mem_client, buf->handle);
			kfree(buf);
			mutex_lock(&inst->lock);
		}
	}
	mutex_unlock(&inst->lock);
	return rc;
}

int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst)
{
@@ -2500,6 +2766,26 @@ exit:
	return rc;
}

int msm_comm_set_output_buffers(struct msm_vidc_inst *inst)
{
	int rc = 0;
	if (!inst || !inst->core || !inst->core->device) {
		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
		return -EINVAL;
	}

	if (msm_comm_release_output_buffers(inst))
		dprintk(VIDC_WARN, "Failed to release output buffers\n");

	rc = set_output_buffers(inst, HAL_BUFFER_OUTPUT);
	if (rc)
		goto error;
	return rc;
error:
	msm_comm_release_output_buffers(inst);
	return rc;
}

int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
{
	int rc = 0;
@@ -2710,6 +2996,11 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
		}
		rc = call_hfi_op(hdev, session_flush, inst->session,
				HAL_FLUSH_OUTPUT);
		if (!rc && (msm_comm_get_stream_output_mode(inst) ==
			HAL_VIDEO_DECODER_SECONDARY))
			rc = call_hfi_op(hdev, session_flush, inst->session,
				HAL_FLUSH_OUTPUT2);

	} else {
		if (!list_empty(&inst->pendingq)) {
			/*If flush is called after queueing buffers but before
Loading