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

Commit de63f1de authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: VPU: Add Dual Output Support"

parents 39ec2349 7c4ada9d
Loading
Loading
Loading
Loading
+35 −23
Original line number Diff line number Diff line
@@ -983,7 +983,7 @@ void vpu_hw_session_close(u32 sid)
 * sid must be valid
 */
static int ipc_cmd_set_session_prop(u32 sid, u32 prop_id,
				void *extra, u32 extra_size)
		u32 port_id, void *extra, u32 extra_size)
{
	struct vpu_ipc_cmd_session_set_property_packet packet;
	int cid = SID2CID(sid);
@@ -995,6 +995,7 @@ static int ipc_cmd_set_session_prop(u32 sid, u32 prop_id,
	packet.hdr.flags = 0; /* no ack */
	packet.hdr.trans_id = 0; /* no sync */
	packet.hdr.sid = sid;
	packet.hdr.port_id = port_id;

	packet.prop_id = prop_id;
	packet.data_offset = sizeof(packet);
@@ -1021,7 +1022,7 @@ static int ipc_cmd_set_session_prop(u32 sid, u32 prop_id,
 * Return: 0 on success, -ve on failure
 */
static int ipc_cmd_sync_get_session_prop(u32 sid, u32 prop_id,
		u8 *rxd, u32 rxd_size)
		u32 port_id, u8 *rxd, u32 rxd_size)
{
	struct vpu_ipc_cmd_session_get_property_packet packet;
	struct vpu_sync_transact *ptrans;
@@ -1032,6 +1033,7 @@ static int ipc_cmd_sync_get_session_prop(u32 sid, u32 prop_id,
	packet.hdr.size = sizeof(packet);
	packet.hdr.cmd_id = VPU_IPC_CMD_SESSION_GET_PROPERTY;
	packet.hdr.sid = sid;
	packet.hdr.port_id = port_id;

	packet.prop_id = prop_id;
	packet.data_offset = 0;
@@ -1195,7 +1197,7 @@ int vpu_hw_session_resume(u32 sid)
	return rc;
}

int vpu_hw_session_flush(u32 sid, enum flush_buf_type type)
int vpu_hw_session_flush(u32 sid, u32 port_id, enum flush_buf_type type)
{
	int rc;
	struct vpu_ipc_cmd_session_flush_packet packet;
@@ -1210,6 +1212,7 @@ int vpu_hw_session_flush(u32 sid, enum flush_buf_type type)
	packet.hdr.size = sizeof(packet);
	packet.hdr.cmd_id = VPU_IPC_CMD_SESSION_FLUSH;
	packet.hdr.sid = sid;
	packet.hdr.port_id = port_id;

	packet.flush_type = type;

@@ -1219,7 +1222,8 @@ int vpu_hw_session_flush(u32 sid, enum flush_buf_type type)
	return rc;
}

int vpu_hw_session_release_buffers(u32 sid, enum release_buf_type release_type)
int vpu_hw_session_release_buffers(u32 sid, u32 port_id,
		enum release_buf_type release_type)
{
	int rc;
	struct vpu_ipc_cmd_session_release_buffers_packet packet;
@@ -1235,6 +1239,7 @@ int vpu_hw_session_release_buffers(u32 sid, enum release_buf_type release_type)
	packet.hdr.size = sizeof(packet);
	packet.hdr.cmd_id = VPU_IPC_CMD_SESSION_RELEASE_BUFFERS;
	packet.hdr.sid = sid;
	packet.hdr.port_id = port_id;

	switch (release_type) {
	case CH_RELEASE_IN_BUF:
@@ -1370,7 +1375,7 @@ static void vpu_buf_to_ipc_buf_info(struct vpu_buffer *vb, bool input,
		*pktflag = flag;
}

int vpu_hw_session_register_buffers(u32 sid, bool input,
int vpu_hw_session_register_buffers(u32 sid, u32 port_id,
		struct vpu_buffer *vb, u32 num)
{
	int rc;
@@ -1380,6 +1385,7 @@ int vpu_hw_session_register_buffers(u32 sid, bool input,
	u8 extra_info[MAX_BUFFER_NUM * sizeof(struct _ipc_buffer_info_ext)];
	struct _ipc_buffer_info_ext *pbuf_info_ext;
	int cid = SID2CID(sid);
	bool input = (port_id == VPU_IPC_PORT_INPUT) ? true : false;

	if (unlikely(!vb)) {
		pr_err("Null pointer vb\n");
@@ -1413,6 +1419,7 @@ int vpu_hw_session_register_buffers(u32 sid, bool input,
	buffer_packet.hdr.flags = 0; /* no ack */
	buffer_packet.hdr.trans_id = 0; /* no sync */
	buffer_packet.hdr.sid = sid;
	buffer_packet.hdr.port_id = port_id;

	if (input) {
		buffer_packet.num_in_buf = num;
@@ -1456,7 +1463,7 @@ int vpu_hw_session_register_buffers(u32 sid, bool input,
 * vpu_hw_session_fill_buffer
 * to queue an empty output buffer
 */
int vpu_hw_session_fill_buffer(u32 sid, struct vpu_buffer *vb)
int vpu_hw_session_fill_buffer(u32 sid, u32 port_id, struct vpu_buffer *vb)
{
	int rc;
	struct vpu_ipc_cmd_session_buffers_packet buffer_packet;
@@ -1486,6 +1493,7 @@ int vpu_hw_session_fill_buffer(u32 sid, struct vpu_buffer *vb)
	buffer_packet.hdr.flags = 0; /* no ack */
	buffer_packet.hdr.trans_id = 0; /* no sync */
	buffer_packet.hdr.sid = sid;
	buffer_packet.hdr.port_id = port_id;

	buffer_packet.num_out_buf = 1;
	buffer_packet.num_in_buf = 0;
@@ -1509,7 +1517,7 @@ int vpu_hw_session_fill_buffer(u32 sid, struct vpu_buffer *vb)
	return rc;
}

int vpu_hw_session_empty_buffer(u32 sid, struct vpu_buffer *vb)
int vpu_hw_session_empty_buffer(u32 sid, u32 port_id, struct vpu_buffer *vb)
{
	int rc;
	struct vpu_ipc_cmd_session_buffers_packet buffer_packet;
@@ -1539,6 +1547,7 @@ int vpu_hw_session_empty_buffer(u32 sid, struct vpu_buffer *vb)
	buffer_packet.hdr.flags = 0; /* no ack */
	buffer_packet.hdr.trans_id = 0; /* no sync */
	buffer_packet.hdr.sid = sid;
	buffer_packet.hdr.port_id = port_id;

	buffer_packet.num_out_buf = 0;
	buffer_packet.num_in_buf = 1;
@@ -1600,7 +1609,7 @@ int vpu_hw_session_commit(u32 sid, enum commit_type ct,
	return rc;
}

int vpu_hw_session_s_input_params(u32 sid,
int vpu_hw_session_s_input_params(u32 sid, u32 port_id,
		const struct vpu_prop_session_input *inparam)
{
	int cid = SID2CID(sid);
@@ -1610,11 +1619,11 @@ int vpu_hw_session_s_input_params(u32 sid,
		return -EINVAL;
	}

	return ipc_cmd_set_session_prop(sid, VPU_PROP_SESSION_INPUT,
	return ipc_cmd_set_session_prop(sid, VPU_PROP_SESSION_INPUT, port_id,
				(void *)inparam, sizeof(*inparam));
}

int vpu_hw_session_s_output_params(u32 sid,
int vpu_hw_session_s_output_params(u32 sid, u32 port_id,
		const struct vpu_prop_session_output *outparam)
{
	int cid = SID2CID(sid);
@@ -1624,11 +1633,12 @@ int vpu_hw_session_s_output_params(u32 sid,
		return -EINVAL;
	}

	return ipc_cmd_set_session_prop(sid, VPU_PROP_SESSION_OUTPUT,
	return ipc_cmd_set_session_prop(sid, VPU_PROP_SESSION_OUTPUT, port_id,
				(void *)outparam, sizeof(*outparam));
}

int vpu_hw_session_g_input_params(u32 sid, struct vpu_prop_session_input *inp)
int vpu_hw_session_g_input_params(u32 sid, u32 port_id,
		struct vpu_prop_session_input *inp)
{
	int rc;
	int cid = SID2CID(sid);
@@ -1640,7 +1650,7 @@ int vpu_hw_session_g_input_params(u32 sid, struct vpu_prop_session_input *inp)

	/* send the synchronous command (blocking call) */
	rc = ipc_cmd_sync_get_session_prop(sid, VPU_PROP_SESSION_INPUT,
			(u8 *)inp, sizeof(*inp));
			port_id, (u8 *)inp, sizeof(*inp));
	if (unlikely(rc))
		pr_err("Error while getting input param property\n");

@@ -1648,7 +1658,7 @@ int vpu_hw_session_g_input_params(u32 sid, struct vpu_prop_session_input *inp)
	return rc;
}

int vpu_hw_session_g_output_params(u32 sid,
int vpu_hw_session_g_output_params(u32 sid, u32 port_id,
		struct vpu_prop_session_output *outp)
{
	int rc;
@@ -1661,7 +1671,7 @@ int vpu_hw_session_g_output_params(u32 sid,

	/* send the synchronous command (blocking call) */
	rc = ipc_cmd_sync_get_session_prop(sid, VPU_PROP_SESSION_OUTPUT,
			(u8 *)outp, sizeof(*outp));
			port_id, (u8 *)outp, sizeof(*outp));
	if (unlikely(rc))
		pr_err("Error while getting output param property\n");

@@ -1685,7 +1695,7 @@ int vpu_hw_session_nr_buffer_config(u32 sid, u32 in_addr, u32 out_addr)
	nr_conf_pkt.release_flag = false;

	return ipc_cmd_set_session_prop(sid,
			VPU_PROP_SESSION_NOISE_REDUCTION_CONFIG,
		VPU_PROP_SESSION_NOISE_REDUCTION_CONFIG, VPU_IPC_PORT_UNUSED,
		(void *)&nr_conf_pkt, sizeof(nr_conf_pkt));
}

@@ -1705,7 +1715,7 @@ int vpu_hw_session_nr_buffer_release(u32 sid)
	nr_conf_pkt.release_flag = true;

	return ipc_cmd_set_session_prop(sid,
			VPU_PROP_SESSION_NOISE_REDUCTION_CONFIG,
		VPU_PROP_SESSION_NOISE_REDUCTION_CONFIG, VPU_IPC_PORT_UNUSED,
		(void *)&nr_conf_pkt, sizeof(nr_conf_pkt));
}

@@ -1720,7 +1730,8 @@ int vpu_hw_session_s_property(u32 sid, u32 prop_id, void *data, u32 data_size)
	}

	/* Send the command for the current property, asynchronously */
	return ipc_cmd_set_session_prop(sid, prop_id, data, data_size);
	return ipc_cmd_set_session_prop(sid, prop_id, VPU_IPC_PORT_UNUSED,
			data, data_size);
}

int vpu_hw_session_g_property(u32 sid, u32 prop_id, void *data, u32 data_size)
@@ -1733,7 +1744,8 @@ int vpu_hw_session_g_property(u32 sid, u32 prop_id, void *data, u32 data_size)
		return -EINVAL;
	}

	return ipc_cmd_sync_get_session_prop(sid, prop_id, data, data_size);
	return ipc_cmd_sync_get_session_prop(sid, prop_id, VPU_IPC_PORT_UNUSED,
			data, data_size);
}

int vpu_hw_session_s_property_ext(u32 sid,
+10 −10
Original line number Diff line number Diff line
@@ -205,9 +205,9 @@ int vpu_hw_session_resume(u32 sid);
 * Set input/output port configuration. Channel *does not* commit new settings.
 * return 0 on success, -ve value on failure
 */
int vpu_hw_session_s_input_params(u32 sid,
int vpu_hw_session_s_input_params(u32 sid, u32 port_id,
		const struct vpu_prop_session_input *inp);
int vpu_hw_session_s_output_params(u32 sid,
int vpu_hw_session_s_output_params(u32 sid, u32 port_id,
		const struct vpu_prop_session_output *outp);

/*
@@ -215,9 +215,9 @@ int vpu_hw_session_s_output_params(u32 sid,
 * Channel copies current hardware configuration into *param.
 * return 0 on success, -ve value on failure
 */
int vpu_hw_session_g_input_params(u32 sid,
int vpu_hw_session_g_input_params(u32 sid, u32 port_id,
		struct vpu_prop_session_input *inp);
int vpu_hw_session_g_output_params(u32 sid,
int vpu_hw_session_g_output_params(u32 sid, u32 port_id,
		struct vpu_prop_session_output *outp);

/**
@@ -291,7 +291,7 @@ int vpu_hw_session_commit(u32 sid, enum commit_type type, u32 load,
/* register session buffers
 * pass a list of buffers to session for use in tunnel case
 */
int vpu_hw_session_register_buffers(u32 sid, bool input,
int vpu_hw_session_register_buffers(u32 sid, u32 port_id,
		struct vpu_buffer *vb, u32 num);

/*
@@ -305,19 +305,19 @@ enum release_buf_type {
	CH_RELEASE_OUT_BUF,
	CH_RELEASE_NR_BUF
};
int vpu_hw_session_release_buffers(u32 sid, enum release_buf_type);
int vpu_hw_session_release_buffers(u32 sid, u32 port_id, enum release_buf_type);

/*
 * fill an output buffer
 * pass an empty output buffer to the session
 */
int vpu_hw_session_fill_buffer(u32 sid, struct vpu_buffer*);
int vpu_hw_session_fill_buffer(u32 sid, u32 port_id, struct vpu_buffer*);

/*
 * empty an input buffer
 * pass a filled input buffer to the session to process
 */
int vpu_hw_session_empty_buffer(u32 sid, struct vpu_buffer*);
int vpu_hw_session_empty_buffer(u32 sid, u32 port_id, struct vpu_buffer*);

/*
 * session flush
@@ -330,7 +330,7 @@ enum flush_buf_type {
	CH_FLUSH_OUT_BUF,
	CH_FLUSH_ALL_BUF
};
int vpu_hw_session_flush(u32 sid, enum flush_buf_type);
int vpu_hw_session_flush(u32 sid, u32 port_id, enum flush_buf_type);


#ifdef CONFIG_DEBUG_FS
+19 −11
Original line number Diff line number Diff line
@@ -1277,7 +1277,8 @@ static int __configure_input_port(struct vpu_dev_session *session)

	translate_input_format_to_hfi(&session->port_info[INPUT_PORT],
			&in_param);
	ret = vpu_hw_session_s_input_params(session->id, &in_param);
	ret = vpu_hw_session_s_input_params(session->id,
			translate_port_id(INPUT_PORT), &in_param);
	if (ret) {
		pr_err("Failed to set input port config\n");
		return ret;
@@ -1301,31 +1302,32 @@ static int __configure_input_port(struct vpu_dev_session *session)
	return 0;
}

static int __configure_output_port(struct vpu_dev_session *session)
static int __configure_output_port(struct vpu_dev_session *session, int port)
{
	struct vpu_prop_session_output out_param;
	int ret = 0;

	translate_output_format_to_hfi(&session->port_info[OUTPUT_PORT],
	translate_output_format_to_hfi(&session->port_info[port],
			&out_param);
	ret = vpu_hw_session_s_output_params(session->id, &out_param);
	ret = vpu_hw_session_s_output_params(session->id,
			translate_port_id(port), &out_param);
	if (ret) {
		pr_err("Failed to set output port config\n");
		pr_err("Failed to set output port %d config\n", port);
		return ret;
	}

	if (session->port_info[OUTPUT_PORT].destination
	if (session->port_info[port].destination
					!= VPU_OUTPUT_TYPE_HOST) {
		struct vpu_data_pkt out_dest_ch;
		memset(&out_dest_ch, 0, sizeof(out_dest_ch));
		out_dest_ch.payload[0] = translate_output_destination_ch(
				session->port_info[OUTPUT_PORT].destination);
				session->port_info[port].destination);
		out_dest_ch.size = sizeof(out_dest_ch);
		ret = vpu_hw_session_s_property(session->id,
				VPU_PROP_SESSION_SINK_CONFIG,
				&out_dest_ch, sizeof(out_dest_ch));
		if (ret) {
			pr_err("Failed to set port 1 dest ch\n");
			pr_err("Failed to set port %d dest ch\n", port);
			return ret;
		}
	}
@@ -1362,10 +1364,16 @@ int commit_initial_config(struct vpu_dev_session *session)
	if (ret)
		return ret;

	ret = __configure_output_port(session);
	ret = __configure_output_port(session, OUTPUT_PORT);
	if (ret)
		return ret;

	if (session->dual_output) {
		ret = __configure_output_port(session, OUTPUT_PORT2);
		if (ret)
			return ret;
	}

	ret = __do_commit(session, CH_COMMIT_AT_ONCE, 1);
	if (ret)
		return ret;
@@ -1389,8 +1397,8 @@ int commit_port_config(struct vpu_dev_session *session, int port, int new_load)
		if (ret)
			return ret;

	} else if (port == OUTPUT_PORT) {
		ret = __configure_output_port(session);
	} else if (port == OUTPUT_PORT || port == OUTPUT_PORT2) {
		ret = __configure_output_port(session, port);
		if (ret)
			return ret;
	} else {
+6 −3
Original line number Diff line number Diff line
@@ -373,7 +373,8 @@ static int vcap2vpu_set_src_buffer(void *sink_ctx,
	} else if (i_port_hnd->start_req) {
		pr_debug("Last buffer received, streamon requested, start\n");

		ret = vpu_hw_session_register_buffers(session->id, true,
		ret = vpu_hw_session_register_buffers(session->id,
				translate_port_id(INPUT_PORT),
				i_port_hnd->buf_array, i_port_hnd->buf_num);
		if (ret) {
			pr_err("Register buffer failed (error %d)\n", ret);
@@ -421,7 +422,8 @@ static void vpu_in_vcap_streamoff(struct vpu_dev_session *session,
	BUG_ON(session != i_port_hnd->session);
	BUG_ON(session->streaming_state == ALL_STREAMING);

	if (vpu_hw_session_release_buffers(session->id, CH_RELEASE_IN_BUF))
	if (vpu_hw_session_release_buffers(session->id,
			translate_port_id(INPUT_PORT), CH_RELEASE_IN_BUF))
		pr_err("Release buffer failed\n");

	/* notify VCAP*/
@@ -488,7 +490,8 @@ static int vpu_in_vcap_streamon(struct vpu_dev_session *session,
	}

	pr_debug("Set tunnel buffers to VPU on port %d\n", port);
	ret = vpu_hw_session_register_buffers(session->id, true,
	ret = vpu_hw_session_register_buffers(session->id,
			translate_port_id(INPUT_PORT),
			i_port_hnd->buf_array, i_port_hnd->buf_num);
	if (unlikely(ret))
		pr_err("Register buffer failed (error %d)\n", ret);
+109 −53
Original line number Diff line number Diff line
@@ -147,7 +147,7 @@ static void __sys_buffer_callback_handler(u32 sid, struct vpu_buffer *pbuf,
		return;
	}

	port = get_port_number(pbuf->vb.vb2_queue->type);
	port = get_queue_port_number(pbuf->vb.vb2_queue);
	session = vb2_get_drv_priv(pbuf->vb.vb2_queue);

	if (data) {
@@ -206,7 +206,7 @@ static int __vpu_hw_switch(struct vpu_dev_core *core, int on)
	return ret;
}

static void __vpu_streamoff_port(struct vpu_dev_session *session, int port)
static void __vpu_streamoff_port(struct vpu_dev_session *session, int port_type)
{
	/* Stop end-to-end session streaming on first streamoff */
	if (session->streaming_state == ALL_STREAMING) {
@@ -215,7 +215,7 @@ static void __vpu_streamoff_port(struct vpu_dev_session *session, int port)
		pr_debug("Session streaming stopped\n");
		session->commit_state = 0;
	}
	session->streaming_state &= ~(0x1 << port);
	session->streaming_state &= ~(0x1 << port_type);
}

static struct vpu_client *__create_client(struct vpu_dev_core *core,
@@ -404,21 +404,22 @@ void vpu_detach_client(struct vpu_client *client)
		/* close hw session on last detach */
		vpu_hw_session_close(session->id);

		/* ports cleanup */
		for (port = 0; port < NUM_VPU_PORTS; ++port) {
			/* detach tunneling ports */
		for (port = 0; port < NUM_VPU_PORTS; ++port)
			call_port_op(session, port, detach);

			memset(&session->port_info[port], 0,
					sizeof(session->port_info[port]));
		}

		/* reset session state and configuration data */
		deinit_vpu_controller(session->controller);
		session->controller = NULL;

		memset(&session->port_info[INPUT_PORT], 0,
				sizeof(session->port_info[INPUT_PORT]));
		memset(&session->port_info[OUTPUT_PORT], 0,
				sizeof(session->port_info[OUTPUT_PORT]));

		session->streaming_state = 0;
		session->commit_state = 0;
		session->dual_output = false;
	}

	list_del_init(&client->clients_entry); /* remove from attached list */
@@ -435,8 +436,8 @@ void vpu_detach_client(struct vpu_client *client)
int vpu_enum_fmt(struct v4l2_fmtdesc *f)
{
	const struct vpu_format_desc *fmt;
	int port = get_port_number(f->type);
	if (port < 0)
	int port_type = get_port_type(f->type);
	if (port_type < 0)
		return -EINVAL;

	fmt = query_supported_formats(f->index);
@@ -460,21 +461,23 @@ int vpu_get_fmt(struct vpu_client *client, struct v4l2_format *f)
	if (!session)
		return -EPERM;

	port = get_port_number(f->type);
	port = get_port_number(client, f->type);
	if (port < 0)
		return -EINVAL;

	if (port == INPUT_PORT) {
		ret = vpu_hw_session_g_input_params(session->id, &in_param);
		ret = vpu_hw_session_g_input_params(session->id,
				translate_port_id(port), &in_param);
		translate_input_format_to_api(&in_param, f);
		f->fmt.pix_mp.colorspace =
			session->port_info[INPUT_PORT].format.colorspace;
			session->port_info[port].format.colorspace;

	} else {
		ret = vpu_hw_session_g_output_params(session->id, &out_param);
		ret = vpu_hw_session_g_output_params(session->id,
				translate_port_id(port), &out_param);
		translate_output_format_to_api(&out_param, f);
		f->fmt.pix_mp.colorspace =
			session->port_info[OUTPUT_PORT].format.colorspace;
			session->port_info[port].format.colorspace;
	}

	return ret;
@@ -530,9 +533,9 @@ int vpu_set_fmt(struct vpu_client *client, struct v4l2_format *f)
		pr_err("invalid session\n");
		return -EPERM;
	}
	port = get_port_number(f->type);
	port = get_port_number(client, f->type);
	if (port < 0) {
		pr_err("invalid port (%d)\n", port);
		pr_err("invalid buffer type (%d)\n", f->type);
		return -EINVAL;
	}

@@ -575,10 +578,12 @@ static int __vpu_get_framerate(struct vpu_client *client, u32 *framerate,
	int ret = 0;

	if (port == INPUT_PORT) {
		ret = vpu_hw_session_g_input_params(session->id, &in_param);
		ret = vpu_hw_session_g_input_params(session->id,
				translate_port_id(port), &in_param);
		*framerate = in_param.frame_rate;
	} else {
		ret = vpu_hw_session_g_output_params(session->id, &out_param);
		ret = vpu_hw_session_g_output_params(session->id,
				translate_port_id(port), &out_param);
		*framerate = out_param.frame_rate;
	}

@@ -610,16 +615,18 @@ int vpu_get_region_of_intereset(struct vpu_client *client,
	if (!session)
		return -EPERM;

	port = get_port_number(crop->type);
	port = get_port_number(client, crop->type);
	if (port < 0)
		return -EINVAL;

	if (port == INPUT_PORT) {
		ret = vpu_hw_session_g_input_params(session->id, &in_param);
		ret = vpu_hw_session_g_input_params(session->id,
				translate_port_id(port), &in_param);
		translate_roi_rect_to_api(&in_param.region_interest,
				&crop->c);
	} else {
		ret = vpu_hw_session_g_output_params(session->id, &out_param);
		ret = vpu_hw_session_g_output_params(session->id,
				translate_port_id(port), &out_param);
		translate_roi_rect_to_api(&out_param.dest_rect,
				&crop->c);
	}
@@ -631,7 +638,9 @@ int vpu_set_region_of_intereset(struct vpu_client *client,
		const struct v4l2_crop *crop)
{
	struct vpu_dev_session *session = client ? client->session : 0;
	int ret = 0, port = get_port_number(crop->type);
	int ret = 0, port;

	port = get_port_number(client, crop->type);

	if (!session)
		return -EPERM;
@@ -665,7 +674,7 @@ int vpu_set_input(struct vpu_client *client, unsigned int i)

	/* Changing input/output only allowed if port is not streaming */
	mutex_lock(&session->lock);
	if (session->streaming_state & (0x1 << INPUT_PORT)) {
	if (session->streaming_state & (0x1 << PORT_TYPE_INPUT)) {
		ret = -EBUSY;
		goto exit_s_input;
	}
@@ -697,44 +706,50 @@ exit_s_input:

int vpu_get_output(struct vpu_client *client, unsigned int *i)
{
	int port;
	if (!client || !client->session)
		return -EPERM;
	*i = client->session->port_info[OUTPUT_PORT].destination;

	port = client->uses_output2 ? OUTPUT_PORT2 : OUTPUT_PORT;

	*i = client->session->port_info[port].destination;

	return 0;
}

int vpu_set_output(struct vpu_client *client, unsigned int i)
{
	int ret = 0;
	int ret = 0, port;
	struct vpu_dev_session *session = client ? client->session : 0;
	if (!session)
		return -EPERM;

	port = client->uses_output2 ? OUTPUT_PORT2 : OUTPUT_PORT;

	mutex_lock(&session->lock);
	if (session->streaming_state & (0x1 << OUTPUT_PORT)) {
	if (session->streaming_state & (0x1 << PORT_TYPE_OUTPUT)) {
		ret = -EBUSY;
		goto exit_s_output;
	}

	session->port_info[OUTPUT_PORT].destination = i;
	session->port_info[port].destination = i;

	/* detach previous output tunnel port, if existing */
	call_port_op(session, OUTPUT_PORT, detach);
	call_port_op(session, port, detach);

	/* initiate and attach input tunnel port, if needed */
	if (i != VPU_OUTPUT_TYPE_HOST) {
		ret = vpu_init_port_mdss(session,
					&session->port_info[OUTPUT_PORT]);
					&session->port_info[port]);
		if (ret)
			goto exit_s_output;

		ret = call_port_op(session, OUTPUT_PORT, attach);
		ret = call_port_op(session, port, attach);
		if (ret)
			goto exit_s_output;
	}

	ret = commit_port_config(session, OUTPUT_PORT, 1);
	ret = commit_port_config(session, port, 1);

exit_s_output:
	mutex_unlock(&session->lock);
@@ -781,9 +796,12 @@ int vpu_get_control_port(struct vpu_client *client,

	if (!session)
		return -EPERM;
	if (port < 0 || port > NUM_VPU_PORTS)
	if (port < 0 || port >= NUM_VPU_PORT_TYPES)
		return -EINVAL;

	if (port == PORT_TYPE_OUTPUT && client->uses_output2)
		port = OUTPUT_PORT2;

	if (control->control_id == VPU_CTRL_FPS)
		return __vpu_get_framerate(client,
				&control->data.framerate, port);
@@ -799,9 +817,12 @@ int vpu_set_control_port(struct vpu_client *client,

	if (!session)
		return -EPERM;
	if (port < 0 || port > NUM_VPU_PORTS)
	if (port < 0 || port >= NUM_VPU_PORT_TYPES)
		return -EINVAL;

	if (port == PORT_TYPE_OUTPUT && client->uses_output2)
		port = OUTPUT_PORT2;

	if (control->control_id == VPU_CTRL_FPS)
		return __vpu_set_framerate(client,
				control->data.framerate, port);
@@ -823,6 +844,26 @@ int vpu_commit_configuration(struct vpu_client *client)
	return ret;
}

int vpu_dual_output(struct vpu_client *client)
{
	int ret = 0;
	struct vpu_dev_session *session = client ? client->session : 0;
	if (!session)
		return -EPERM;

	mutex_lock(&session->lock);
	if (session->io_client[OUTPUT_PORT] == client) {
		pr_err("Client using output port 1\n");
		ret = -EINVAL;
	} else {
		session->dual_output = true;
		client->uses_output2 = true;
	}
	mutex_unlock(&session->lock);

	return ret;
}

/*
 * Streaming I/O operations
 */
@@ -840,13 +881,13 @@ int vpu_reqbufs(struct vpu_client *client, struct v4l2_requestbuffers *req)
	if (!session)
		return -EPERM;

	port = get_port_number(req->type);
	port = get_port_number(client, req->type);
	if (port < 0) {
		pr_err("Invalid buffer type %d\n", req->type);
		return -EINVAL;
	}

	pr_debug("count = %d\n", req->count);
	pr_debug("port %d count = %d\n", port, req->count);

	mutex_lock(&session->que_lock[port]);
	if (session->io_client[port] != client && session->io_client[port]) {
@@ -921,7 +962,7 @@ int vpu_qbuf(struct vpu_client *client, struct v4l2_buffer *b)
	if (!session)
		return -EPERM;

	port = get_port_number(b->type);
	port = get_port_number(client, b->type);
	if (port < 0) {
		pr_err("Invalid type %d\n", b->type);
		return -EINVAL;
@@ -956,7 +997,7 @@ int vpu_dqbuf(struct vpu_client *client, struct v4l2_buffer *b,
	if (!session)
		return -EPERM;

	port = get_port_number(b->type);
	port = get_port_number(client, b->type);
	if (port < 0) {
		pr_err("Invalid type %d\n", b->type);
		return -EINVAL;
@@ -1001,10 +1042,10 @@ static int __queue_pending_buffers(struct vpu_dev_session *session)
		{
			if (port == INPUT_PORT)
				ret = vpu_hw_session_empty_buffer(session->id,
						buff);
						translate_port_id(port), buff);
			else
				ret = vpu_hw_session_fill_buffer(session->id,
						buff);
						translate_port_id(port), buff);

			if (ret) {
				pr_err("returning buffer\n");
@@ -1021,11 +1062,13 @@ static int __queue_pending_buffers(struct vpu_dev_session *session)
int vpu_flush_bufs(struct vpu_client *client, enum v4l2_buf_type type)
{
	struct vpu_dev_session *session = client ? client->session : 0;
	int ret = 0, port;
	int ret = 0, port, port_type;
	if (!session)
		return -EPERM;

	port = get_port_number(type);
	port_type = get_port_type(type);

	port = get_port_number(client, type);
	if (port < 0) {
		pr_err("Invalid type %d\n", type);
		return -EINVAL;
@@ -1038,7 +1081,7 @@ int vpu_flush_bufs(struct vpu_client *client, enum v4l2_buf_type type)
		ret = -EINVAL;
		goto exit_flush;
	} else {
		if (!(session->streaming_state & (0x1 << port))) {
		if (!(session->streaming_state & (0x1 << port_type))) {
			/* Can't flush if port is not streaming */
			ret = -EINVAL;
			goto exit_flush;
@@ -1072,6 +1115,15 @@ int vpu_trigger_stream(struct vpu_dev_session *session)
		return ret;
	}

	if (session->dual_output) {
		ret = vb2_streamon(&session->vbqueue[OUTPUT_PORT2],
				session->vbqueue[OUTPUT_PORT2].type);
		if (ret) {
			pr_err("Failed to vb2_streamon output port 2\n");
			return ret;
		}
	}

	session->streaming_state = ALL_STREAMING;
	__queue_pending_buffers(session);

@@ -1081,16 +1133,19 @@ int vpu_trigger_stream(struct vpu_dev_session *session)
int vpu_streamon(struct vpu_client *client, enum v4l2_buf_type type)
{
	struct vpu_dev_session *session = client ? client->session : 0;
	int ret = 0, port;
	int ret = 0, port, port_type;
	u32 temp_streaming = 0;
	if (!session)
		return -EPERM;

	port = get_port_number(type);
	port_type = get_port_type(type);
	port = get_port_number(client, type);
	if (port < 0) {
		pr_err("Invalid type %d\n", type);
		return -EINVAL;
	}
	if (port == OUTPUT_PORT2)
		return 0; /* do nothing for second output port */

	mutex_lock(&session->lock); /* needed to sync streamon from two ports */

@@ -1107,10 +1162,10 @@ int vpu_streamon(struct vpu_client *client, enum v4l2_buf_type type)
	if (ret)
		goto early_exit_streamon;

	if (temp_streaming & (0x1 << port)) {
	if (temp_streaming & (0x1 << port_type)) {
		goto early_exit_streamon; /* This port already streaming */
	} else {
		temp_streaming |= (0x1 << port);
		temp_streaming |= (0x1 << port_type);
		/* lock port if tunneling */
		if (__is_tunneling(session, port))
			session->io_client[port] = client;
@@ -1144,12 +1199,11 @@ int vpu_streamon(struct vpu_client *client, enum v4l2_buf_type type)

	/* Start end-to-end session streaming */
	ret = vpu_trigger_stream(session);

	if (!ret)
		pr_debug("Session streaming started successfully\n");

late_exit_streamon:
	if (ret) {
		/* TODO: How do we notify the streamed on sessions? */
		if (__is_tunneling(session, port))
			session->io_client[port] = NULL;
	}
@@ -1173,11 +1227,13 @@ int vpu_streamoff(struct vpu_client *client, enum v4l2_buf_type type)
	if (!session)
		return -EPERM;

	port = get_port_number(type);
	port = get_port_number(client, type);
	if (port < 0) {
		pr_err("Invalid type %d\n", type);
		return -EINVAL;
	}
	if (port == OUTPUT_PORT2)
		return 0; /* do nothing for second output port */

	/* session lock needed to protect actions inside vb2_stream_off */
	mutex_lock(&session->lock);
Loading