Просмотр исходного кода

Merge "video: driver: restructure video state machine"

qctecmdr 2 лет назад
Родитель
Сommit
0884f5a04a

+ 7 - 7
driver/platform/common/src/msm_vidc_platform.c

@@ -168,13 +168,13 @@ static struct v4l2_ctrl_ops msm_v4l2_ctrl_ops = {
 };
 
 static struct vb2_ops msm_vb2_ops = {
-	.queue_setup                    = msm_vidc_queue_setup,
-	.start_streaming                = msm_vidc_start_streaming,
-	.buf_queue                      = msm_vidc_buf_queue,
-	.buf_cleanup                    = msm_vidc_buf_cleanup,
-	.stop_streaming                 = msm_vidc_stop_streaming,
-	.buf_out_validate               = msm_vidc_buf_out_validate,
-	.buf_request_complete           = msm_vidc_buf_request_complete,
+	.queue_setup                    = msm_vb2_queue_setup,
+	.start_streaming                = msm_vb2_start_streaming,
+	.buf_queue                      = msm_vb2_buf_queue,
+	.buf_cleanup                    = msm_vb2_buf_cleanup,
+	.stop_streaming                 = msm_vb2_stop_streaming,
+	.buf_out_validate               = msm_vb2_buf_out_validate,
+	.buf_request_complete           = msm_vb2_request_complete,
 };
 
 static struct vb2_mem_ops msm_vb2_mem_ops = {

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

@@ -28,7 +28,8 @@ int msm_vdec_inst_deinit(struct msm_vidc_inst *inst);
 int msm_vdec_init_input_subcr_params(struct msm_vidc_inst *inst);
 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_vdec_stop_cmd(struct msm_vidc_inst *inst);
+int msm_vdec_start_cmd(struct msm_vidc_inst *inst);
 int msm_vdec_handle_release_buffer(struct msm_vidc_inst *inst,
 	struct msm_vidc_buffer *buf);
 int msm_vdec_set_num_comv(struct msm_vidc_inst *inst);

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

@@ -15,7 +15,8 @@ int msm_venc_streamon_input(struct msm_vidc_inst *inst);
 int msm_venc_streamoff_output(struct msm_vidc_inst *inst);
 int msm_venc_streamon_output(struct msm_vidc_inst *inst);
 int msm_venc_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2);
-int msm_venc_process_cmd(struct msm_vidc_inst *inst, u32 cmd);
+int msm_venc_stop_cmd(struct msm_vidc_inst *inst);
+int msm_venc_start_cmd(struct msm_vidc_inst *inst);
 int msm_venc_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
 int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
 int msm_venc_s_fmt_output(struct msm_vidc_inst *inst, struct v4l2_format *f);

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

@@ -41,7 +41,8 @@ int msm_vidc_query_ctrl(void *instance, struct v4l2_queryctrl *ctrl);
 int msm_vidc_query_menu(void *instance, struct v4l2_querymenu *qmenu);
 int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
 int msm_vidc_try_cmd(void *instance, union msm_v4l2_cmd *cmd);
-int msm_vidc_cmd(void *instance, union msm_v4l2_cmd *cmd);
+int msm_vidc_start_cmd(void *instance);
+int msm_vidc_stop_cmd(void *instance);
 int msm_vidc_poll(void *instance, struct file *filp,
 		struct poll_table_struct *pt);
 int msm_vidc_subscribe_event(void *instance,

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

@@ -14,6 +14,7 @@ int msm_vidc_ctrl_init(struct msm_vidc_inst *inst);
 int msm_vidc_ctrl_deinit(struct msm_vidc_inst *inst);
 int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl);
 int msm_v4l2_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
+int msm_vidc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl);
 int msm_vidc_prepare_dependency_list(struct msm_vidc_inst *inst);
 int msm_vidc_adjust_set_v4l2_properties(struct msm_vidc_inst *inst);
 bool is_valid_cap_id(enum msm_vidc_inst_capability_type cap_id);

+ 5 - 6
driver/vidc/inc/msm_vidc_driver.h

@@ -404,8 +404,8 @@ const char *state_name(enum msm_vidc_state state);
 int msm_vidc_change_state(struct msm_vidc_inst *inst,
 	enum msm_vidc_state request_state, const char *func);
 int msm_vidc_change_sub_state(struct msm_vidc_inst *inst,
-	enum msm_vidc_sub_state clear_sub_states,
-	enum msm_vidc_sub_state set_sub_states, const char *func);
+	enum msm_vidc_sub_state clear_sub_state,
+	enum msm_vidc_sub_state set_sub_state, const char *func);
 int msm_vidc_create_internal_buffer(struct msm_vidc_inst *inst,
 	enum msm_vidc_buffer_type buffer_type, u32 index);
 int msm_vidc_get_internal_buffers(struct msm_vidc_inst *inst,
@@ -436,6 +436,8 @@ int msm_vidc_change_core_state(struct msm_vidc_core *core,
 int msm_vidc_change_core_sub_state(struct msm_vidc_core *core,
 	enum msm_vidc_core_sub_state clear_sub_states,
 	enum msm_vidc_core_sub_state set_sub_states, const char *func);
+int prepare_sub_state_name(enum msm_vidc_sub_state sub_state,
+	char *buf, u32 size);
 int msm_vidc_core_init(struct msm_vidc_core *core);
 int msm_vidc_core_init_wait(struct msm_vidc_core *core);
 int msm_vidc_core_deinit(struct msm_vidc_core *core, bool force);
@@ -482,6 +484,7 @@ int cancel_stats_work_sync(struct msm_vidc_inst *inst);
 void msm_vidc_print_stats(struct msm_vidc_inst *inst);
 enum msm_vidc_buffer_type v4l2_type_to_driver(u32 type,
 	const char *func);
+int msm_vidc_buf_queue(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf);
 int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst,
 	struct vb2_buffer *vb2);
 int msm_vidc_queue_deferred_buffers(struct msm_vidc_inst *inst,
@@ -501,8 +504,6 @@ struct msm_vidc_inst *get_inst(struct msm_vidc_core *core,
 		u32 session_id);
 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,
-	enum msm_vidc_inst_capability_type cap_id);
 bool msm_vidc_allow_metadata_delivery(struct msm_vidc_inst *inst,
 	u32 cap_id, u32 port);
 bool msm_vidc_allow_metadata_subscription(struct msm_vidc_inst *inst,
@@ -514,8 +515,6 @@ 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);
 bool msm_vidc_allow_streamon(struct msm_vidc_inst *inst, u32 type);
-enum msm_vidc_allow msm_vidc_allow_streamoff(struct msm_vidc_inst *inst, u32 type);
-enum msm_vidc_allow msm_vidc_allow_qbuf(struct msm_vidc_inst *inst, u32 type);
 enum msm_vidc_allow msm_vidc_allow_input_psc(struct msm_vidc_inst *inst);
 bool msm_vidc_allow_drain_last_flag(struct msm_vidc_inst *inst);
 bool msm_vidc_allow_psc_last_flag(struct msm_vidc_inst *inst);

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

@@ -9,12 +9,12 @@
 
 #include "msm_vidc_internal.h"
 #include "msm_vidc_memory.h"
+#include "msm_vidc_state.h"
 #include "hfi_property.h"
 
 struct msm_vidc_inst;
 
 #define FOREACH_STATE(STATE) {                    \
-	STATE(NONE)                               \
 	STATE(OPEN)                               \
 	STATE(INPUT_STREAMING)                    \
 	STATE(OUTPUT_STREAMING)                   \
@@ -97,6 +97,8 @@ struct msm_vidc_inst {
 	struct mutex                       request_lock;
 	struct mutex                       client_lock;
 	enum msm_vidc_state                state;
+	int                              (*event_handle)(struct msm_vidc_inst *inst,
+					   enum msm_vidc_event event, void *data);
 	enum msm_vidc_sub_state            sub_state;
 	char                               sub_state_name[MAX_NAME_LENGTH];
 	enum msm_vidc_domain_type          domain;

+ 1 - 1
driver/vidc/inc/msm_vidc_internal.h

@@ -377,7 +377,7 @@ enum msm_vidc_metadata_bits {
 	BUF_TYPE(INPUT_META)                      \
 	BUF_TYPE(OUTPUT_META)                     \
 	BUF_TYPE(READ_ONLY)                       \
-	BUF_TYPE(QUEUE)                           \
+	BUF_TYPE(INTERFACE_QUEUE)                 \
 	BUF_TYPE(BIN)                             \
 	BUF_TYPE(ARP)                             \
 	BUF_TYPE(COMV)                            \

+ 22 - 6
driver/vidc/inc/msm_vidc_state.h

@@ -10,6 +10,8 @@
 #include "msm_vidc_internal.h"
 
 struct msm_vidc_core;
+enum msm_vidc_state;
+enum msm_vidc_sub_state;
 
 #define FOREACH_CORE_STATE(CORE_STATE) {               \
 	CORE_STATE(CORE_DEINIT)                        \
@@ -18,6 +20,17 @@ struct msm_vidc_core;
 	CORE_STATE(CORE_ERROR)                         \
 }
 
+#define FOREACH_EVENT(EVENT) {                         \
+	EVENT(S_FMT)                                   \
+	EVENT(REQBUFS)                                 \
+	EVENT(S_CTRL)                                  \
+	EVENT(STREAMON)                                \
+	EVENT(STREAMOFF)                               \
+	EVENT(CMD_START)                               \
+	EVENT(CMD_STOP)                                \
+	EVENT(BUF_QUEUE)                               \
+}
+
 enum msm_vidc_core_state FOREACH_CORE_STATE(GENERATE_MSM_VIDC_ENUM);
 
 enum msm_vidc_core_sub_state {
@@ -37,13 +50,9 @@ enum msm_vidc_core_event_type {
 	CORE_EVENT_UPDATE_SUB_STATE          = BIT(1),
 };
 
-struct msm_vidc_core_state_handle {
-	enum msm_vidc_core_state   state;
-	int                      (*handle)(struct msm_vidc_core *core,
-				   enum msm_vidc_core_event_type type,
-				   struct msm_vidc_event_data *data);
-};
+enum msm_vidc_event FOREACH_EVENT(GENERATE_MSM_VIDC_ENUM);
 
+/* core statemachine functions */
 enum msm_vidc_allow msm_vidc_allow_core_state_change(
 	struct msm_vidc_core *core, enum msm_vidc_core_state req_state);
 int msm_vidc_update_core_state(struct msm_vidc_core *core,
@@ -55,4 +64,11 @@ bool is_core_sub_state(struct msm_vidc_core *core,
 const char *core_state_name(enum msm_vidc_core_state state);
 const char *core_sub_state_name(enum msm_vidc_core_sub_state sub_state);
 
+/* inst statemachine functions */
+int msm_vidc_update_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_state request_state, const char *func);
+enum msm_vidc_allow msm_vidc_allow_state_change(
+	struct msm_vidc_inst *inst,
+	enum msm_vidc_state req_state);
+
 #endif // _MSM_VIDC_STATE_H_

+ 9 - 8
driver/vidc/inc/msm_vidc_vb2.h

@@ -35,14 +35,15 @@ int msm_vb2_map_dmabuf(void *buf_priv);
 void msm_vb2_unmap_dmabuf(void *buf_priv);
 
 /* vb2_ops */
-int msm_vidc_queue_setup(struct vb2_queue *q,
+int msm_vb2_queue_setup(struct vb2_queue *q,
 		unsigned int *num_buffers, unsigned int *num_planes,
 		unsigned int sizes[], struct device *alloc_devs[]);
-int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count);
-void msm_vidc_stop_streaming(struct vb2_queue *q);
-void msm_vidc_buf_queue(struct vb2_buffer *vb2);
-void msm_vidc_buf_cleanup(struct vb2_buffer *vb);
-int msm_vidc_buf_out_validate(struct vb2_buffer *vb);
-void msm_vidc_buf_request_complete(struct vb2_buffer *vb);
-
+int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q);
+int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q);
+int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count);
+void msm_vb2_stop_streaming(struct vb2_queue *q);
+void msm_vb2_buf_queue(struct vb2_buffer *vb2);
+void msm_vb2_buf_cleanup(struct vb2_buffer *vb);
+int msm_vb2_buf_out_validate(struct vb2_buffer *vb);
+void msm_vb2_request_complete(struct vb2_buffer *vb);
 #endif // _MSM_VIDC_VB2_H_

+ 69 - 71
driver/vidc/src/msm_vdec.c

@@ -1898,11 +1898,8 @@ static int msm_vdec_qbuf_batch(struct msm_vidc_inst *inst,
 	if (!buf)
 		return -EINVAL;
 
-	allow = msm_vidc_allow_qbuf(inst, vb2->type);
-	if (allow == MSM_VIDC_DISALLOW) {
-		i_vpr_e(inst, "%s: qbuf not allowed\n", __func__);
-		return -EINVAL;
-	} else if (allow == MSM_VIDC_DEFER) {
+	if (is_state(inst, MSM_VIDC_OPEN) ||
+		is_state(inst, MSM_VIDC_INPUT_STREAMING)) {
 		print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
 		return 0;
 	}
@@ -2092,95 +2089,96 @@ static int msm_vdec_alloc_and_queue_additional_dpb_buffers(struct msm_vidc_inst
 	return 0;
 }
 
-int msm_vdec_process_cmd(struct msm_vidc_inst *inst, u32 cmd)
+int msm_vdec_stop_cmd(struct msm_vidc_inst *inst)
 {
-	int rc = 0;
 	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
+	int rc = 0;
+
+	i_vpr_h(inst, "received cmd: drain\n");
+	allow = msm_vidc_allow_stop(inst);
+	if (allow == MSM_VIDC_DISALLOW)
+		return -EBUSY;
+	else if (allow == MSM_VIDC_IGNORE)
+		return 0;
+	else if (allow != MSM_VIDC_ALLOW)
+		return -EINVAL;
+	rc = msm_vidc_process_drain(inst);
+	if (rc)
+		return rc;
+
+	return rc;
+}
+
+int msm_vdec_start_cmd(struct msm_vidc_inst *inst)
+{
 	struct msm_vidc_inst_capability *capability;
+	int rc = 0;
 
-	if (!inst || !inst->core || !inst->capabilities) {
+	if (!inst || !inst->capabilities) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
 	capability = inst->capabilities;
 
-	if (cmd == V4L2_DEC_CMD_STOP) {
-		i_vpr_h(inst, "received cmd: drain\n");
-		allow = msm_vidc_allow_stop(inst);
-		if (allow == MSM_VIDC_DISALLOW)
-			return -EBUSY;
-		else if (allow == MSM_VIDC_IGNORE)
-			return 0;
-		else if (allow != MSM_VIDC_ALLOW)
-			return -EINVAL;
-		rc = msm_vidc_process_drain(inst);
-		if (rc)
-			return rc;
-	} else if (cmd == V4L2_DEC_CMD_START) {
-		i_vpr_h(inst, "received cmd: resume\n");
-		vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q);
-		vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q);
-
-		if (capability->cap[CODED_FRAMES].value == CODED_FRAMES_INTERLACE &&
-			!is_ubwc_colorformat(capability->cap[PIX_FMTS].value)) {
-			i_vpr_e(inst,
-				"%s: interlace with non-ubwc color format is unsupported\n",
-				__func__);
-			return -EINVAL;
-		}
+	i_vpr_h(inst, "received cmd: resume\n");
+	vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q);
+	vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q);
 
-		if (!msm_vidc_allow_start(inst))
-			return -EBUSY;
-
-		/* tune power features */
-		inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst);
-		msm_vidc_allow_dcvs(inst);
-		msm_vidc_power_data_reset(inst);
-
-		/*
-		 * client is completing partial port reconfiguration,
-		 * hence reallocate input internal buffers before input port
-		 * is resumed.
-		 */
-		if (is_sub_state(inst, MSM_VIDC_DRC) &&
-			is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER) &&
-			is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) {
-			rc = msm_vidc_alloc_and_queue_input_internal_buffers(inst);
-			if (rc)
-				return rc;
+	if (capability->cap[CODED_FRAMES].value == CODED_FRAMES_INTERLACE &&
+		!is_ubwc_colorformat(capability->cap[PIX_FMTS].value)) {
+		i_vpr_e(inst,
+			"%s: interlace with non-ubwc color format is unsupported\n",
+			__func__);
+		return -EINVAL;
+	}
 
-			rc = msm_vidc_set_stage(inst, STAGE);
-			if (rc)
-				return rc;
+	if (!msm_vidc_allow_start(inst))
+		return -EBUSY;
 
-			rc = msm_vidc_set_pipe(inst, PIPE);
-			if (rc)
-				return rc;
-		}
+	/* tune power features */
+	inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst);
+	msm_vidc_allow_dcvs(inst);
+	msm_vidc_power_data_reset(inst);
 
-		/* allocate and queue extra dpb buffers */
-		rc = msm_vdec_alloc_and_queue_additional_dpb_buffers(inst);
+	/*
+	 * client is completing partial port reconfiguration,
+	 * hence reallocate input internal buffers before input port
+	 * is resumed.
+	 */
+	if (is_sub_state(inst, MSM_VIDC_DRC) &&
+		is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER) &&
+		is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) {
+		rc = msm_vidc_alloc_and_queue_input_internal_buffers(inst);
 		if (rc)
 			return rc;
 
-		/* queue pending deferred buffers */
-		rc = msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT);
+		rc = msm_vidc_set_stage(inst, STAGE);
 		if (rc)
 			return rc;
 
-		/* print final buffer counts & size details */
-		msm_vidc_print_buffer_info(inst);
-
-		rc = msm_vidc_process_resume(inst);
+		rc = msm_vidc_set_pipe(inst, PIPE);
 		if (rc)
 			return rc;
-
-	} else {
-		i_vpr_e(inst, "%s: unknown cmd %d\n", __func__, cmd);
-		return -EINVAL;
 	}
 
-	return 0;
+	/* allocate and queue extra dpb buffers */
+	rc = msm_vdec_alloc_and_queue_additional_dpb_buffers(inst);
+	if (rc)
+		return rc;
+
+	/* queue pending deferred buffers */
+	rc = msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT);
+	if (rc)
+		return rc;
+
+	/* print final buffer counts & size details */
+	msm_vidc_print_buffer_info(inst);
+
+	rc = msm_vidc_process_resume(inst);
+	if (rc)
+		return rc;
+
+	return rc;
 }
 
 int msm_vdec_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)

+ 34 - 36
driver/vidc/src/msm_venc.c

@@ -905,50 +905,48 @@ int msm_venc_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2)
 	return rc;
 }
 
-int msm_venc_process_cmd(struct msm_vidc_inst *inst, u32 cmd)
+int msm_venc_stop_cmd(struct msm_vidc_inst *inst)
 {
-	int rc = 0;
 	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
+	int rc = 0;
 
-	if (!inst || !inst->core) {
-		d_vpr_e("%s: invalid params\n", __func__);
+	i_vpr_h(inst, "received cmd: drain\n");
+	allow = msm_vidc_allow_stop(inst);
+	if (allow == MSM_VIDC_DISALLOW)
+		return -EBUSY;
+	else if (allow == MSM_VIDC_IGNORE)
+		return 0;
+	else if (allow != MSM_VIDC_ALLOW)
 		return -EINVAL;
-	}
+	rc = msm_vidc_process_drain(inst);
+	if (rc)
+		return rc;
 
-	if (cmd == V4L2_ENC_CMD_STOP) {
-		i_vpr_h(inst, "received cmd: drain\n");
-		allow = msm_vidc_allow_stop(inst);
-		if (allow == MSM_VIDC_DISALLOW)
-			return -EBUSY;
-		else if (allow == MSM_VIDC_IGNORE)
-			return 0;
-		else if (allow != MSM_VIDC_ALLOW)
-			return -EINVAL;
-		rc = msm_vidc_process_drain(inst);
-		if (rc)
-			return rc;
-	} else if (cmd == V4L2_ENC_CMD_START) {
-		i_vpr_h(inst, "received cmd: resume\n");
-		if (!msm_vidc_allow_start(inst))
-			return -EBUSY;
-		vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q);
-		vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q);
+	return rc;
+}
 
-		/* tune power features */
-		msm_vidc_allow_dcvs(inst);
-		msm_vidc_power_data_reset(inst);
+int msm_venc_start_cmd(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
 
-		/* print final buffer counts & size details */
-		msm_vidc_print_buffer_info(inst);
+	i_vpr_h(inst, "received cmd: resume\n");
+	if (!msm_vidc_allow_start(inst))
+		return -EBUSY;
+	vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q);
+	vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q);
 
-		rc = msm_vidc_process_resume(inst);
-		if (rc)
-			return rc;
-	} else {
-		i_vpr_e(inst, "%s: unknown cmd %d\n", __func__, cmd);
-		return -EINVAL;
-	}
-	return 0;
+	/* tune power features */
+	msm_vidc_allow_dcvs(inst);
+	msm_vidc_power_data_reset(inst);
+
+	/* print final buffer counts & size details */
+	msm_vidc_print_buffer_info(inst);
+
+	rc = msm_vidc_process_resume(inst);
+	if (rc)
+		return rc;
+
+	return rc;
 }
 
 int msm_venc_streamoff_output(struct msm_vidc_inst *inst)

+ 42 - 12
driver/vidc/src/msm_vidc.c

@@ -658,26 +658,53 @@ int msm_vidc_try_cmd(void *instance, union msm_v4l2_cmd *cmd)
 }
 EXPORT_SYMBOL(msm_vidc_try_cmd);
 
-int msm_vidc_cmd(void *instance, union msm_v4l2_cmd *cmd)
+int msm_vidc_start_cmd(void *instance)
 {
+	struct msm_vidc_inst *inst = instance;
 	int rc = 0;
+
+	if (!is_decode_session(inst) && !is_encode_session(inst)) {
+		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
+		return -EINVAL;
+	}
+
+	if (is_decode_session(inst)) {
+		rc = msm_vdec_start_cmd(inst);
+		if (rc)
+			return rc;
+	} else if (is_encode_session(inst)) {
+		rc = msm_venc_start_cmd(inst);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_start_cmd);
+
+int msm_vidc_stop_cmd(void *instance)
+{
 	struct msm_vidc_inst *inst = instance;
-	struct v4l2_decoder_cmd *dec = NULL;
-	struct v4l2_encoder_cmd *enc = NULL;
+	int rc = 0;
+
+	if (!is_decode_session(inst) && !is_encode_session(inst)) {
+		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
+		return -EINVAL;
+	}
 
 	if (is_decode_session(inst)) {
-		dec = (struct v4l2_decoder_cmd *)cmd;
-		rc = msm_vdec_process_cmd(inst, dec->cmd);
+		rc = msm_vdec_stop_cmd(inst);
+		if (rc)
+			return rc;
 	} else if (is_encode_session(inst)) {
-		enc = (struct v4l2_encoder_cmd *)cmd;
-		rc = msm_venc_process_cmd(inst, enc->cmd);
+		rc = msm_venc_stop_cmd(inst);
+		if (rc)
+			return rc;
 	}
-	if (rc)
-		return rc;
 
-	return 0;
+	return rc;
 }
-EXPORT_SYMBOL(msm_vidc_cmd);
+EXPORT_SYMBOL(msm_vidc_stop_cmd);
 
 int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize)
 {
@@ -894,7 +921,7 @@ void *msm_vidc_open(void *vidc_core, u32 session_type)
 	inst->core = core;
 	inst->domain = session_type;
 	inst->session_id = hash32_ptr(inst);
-	msm_vidc_change_state(inst, MSM_VIDC_OPEN, __func__);
+	msm_vidc_update_state(inst, MSM_VIDC_OPEN, __func__);
 	inst->sub_state = MSM_VIDC_SUB_STATE_NONE;
 	strlcpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name));
 	inst->active = true;
@@ -1041,6 +1068,9 @@ int msm_vidc_close(void *instance)
 	msm_vidc_event_queue_deinit(inst);
 	msm_vidc_vb2_queue_deinit(inst);
 	msm_vidc_remove_session(inst);
+	msm_vidc_change_state(inst, MSM_VIDC_CLOSE, __func__);
+	inst->sub_state = MSM_VIDC_SUB_STATE_NONE;
+	strscpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name));
 	inst_unlock(inst, __func__);
 	client_unlock(inst, __func__);
 	cancel_stability_work_sync(inst);

+ 35 - 28
driver/vidc/src/msm_vidc_control.c

@@ -841,29 +841,17 @@ static int msm_vidc_update_static_property(struct msm_vidc_inst *inst,
 	return rc;
 }
 
-int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl)
+int msm_vidc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
 {
-	int rc = 0;
-	struct msm_vidc_inst *inst;
 	enum msm_vidc_inst_capability_type cap_id;
 	struct msm_vidc_inst_capability *capability;
+	int rc = 0;
 	u32 port;
 
-	if (!ctrl) {
-		d_vpr_e("%s: invalid ctrl parameter\n", __func__);
-		return -EINVAL;
-	}
-
-	inst = container_of(ctrl->handler,
-		struct msm_vidc_inst, ctrl_handler);
-	inst = get_inst_ref(g_core, inst);
-	if (!inst || !inst->capabilities) {
-		d_vpr_e("%s: invalid parameters for inst\n", __func__);
+	if (!inst || !inst->capabilities || !ctrl) {
+		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
-
-	client_lock(inst, __func__);
-	inst_lock(inst, __func__);
 	capability = inst->capabilities;
 
 	i_vpr_h(inst, FMT_STRING_SET_CTRL,
@@ -871,15 +859,8 @@ int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	cap_id = msm_vidc_get_cap_id(inst, ctrl->id);
 	if (!is_valid_cap_id(cap_id)) {
-		i_vpr_e(inst, "%s: could not find cap_id for ctrl %s\n",
-			__func__, ctrl->name);
-		rc = -EINVAL;
-		goto unlock;
-	}
-
-	if (!msm_vidc_allow_s_ctrl(inst, cap_id)) {
-		rc = -EINVAL;
-		goto unlock;
+		i_vpr_e(inst, "%s: invalid cap_id for ctrl %s\n", __func__, ctrl->name);
+		return -EINVAL;
 	}
 
 	/* mark client set flag */
@@ -890,18 +871,44 @@ int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl)
 		/* static case */
 		rc = msm_vidc_update_static_property(inst, cap_id, ctrl);
 		if (rc)
-			goto unlock;
+			return rc;
 	} else {
 		/* dynamic case */
 		rc = msm_vidc_adjust_dynamic_property(inst, cap_id, ctrl);
 		if (rc)
-			goto unlock;
+			return rc;
 
 		rc = msm_vidc_set_dynamic_property(inst);
 		if (rc)
-			goto unlock;
+			return rc;
 	}
 
+	return rc;
+}
+
+int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	if (!ctrl) {
+		d_vpr_e("%s: invalid ctrl parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	inst = container_of(ctrl->handler, struct msm_vidc_inst, ctrl_handler);
+	inst = get_inst_ref(g_core, inst);
+	if (!inst) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	rc = inst->event_handle(inst, MSM_VIDC_S_CTRL, ctrl);
+	if (rc)
+		goto unlock;
+
 unlock:
 	inst_unlock(inst, __func__);
 	client_unlock(inst, __func__);

+ 71 - 175
driver/vidc/src/msm_vidc_driver.c

@@ -130,6 +130,28 @@ const char *sub_state_name(enum msm_vidc_sub_state sub_state)
 	return "SUB_STATE_NONE";
 }
 
+int prepare_sub_state_name(enum msm_vidc_sub_state sub_state,
+	char *buf, u32 size)
+{
+	int i = 0;
+
+	if (!buf || !size)
+		return -EINVAL;
+
+	strscpy(buf, "\0", size);
+	if (sub_state == MSM_VIDC_SUB_STATE_NONE) {
+		strscpy(buf, "SUB_STATE_NONE", size);
+		return 0;
+	}
+
+	for (i = 0; i < MSM_VIDC_MAX_SUB_STATES; i++) {
+		if (sub_state & BIT(i))
+			strlcat(buf, sub_state_name(BIT(i)), size);
+	}
+
+	return 0;
+}
+
 const char *v4l2_type_name(u32 port)
 {
 	switch (port) {
@@ -888,7 +910,7 @@ struct msm_vidc_buffers *msm_vidc_get_buffers(
 		return &inst->buffers.vpss;
 	case MSM_VIDC_BUF_PARTIAL_DATA:
 		return &inst->buffers.partial_data;
-	case MSM_VIDC_BUF_QUEUE:
+	case MSM_VIDC_BUF_INTERFACE_QUEUE:
 		return NULL;
 	default:
 		i_vpr_e(inst, "%s: invalid driver buffer type %d\n",
@@ -994,16 +1016,14 @@ int signal_session_msg_receipt(struct msm_vidc_inst *inst,
 int msm_vidc_change_state(struct msm_vidc_inst *inst,
 		enum msm_vidc_state request_state, const char *func)
 {
+	enum msm_vidc_allow allow;
+	int rc;
+
 	if (!inst) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
 
-	if (!request_state) {
-		i_vpr_e(inst, "%s: invalid request state\n", func);
-		return -EINVAL;
-	}
-
 	if (is_session_error(inst)) {
 		i_vpr_h(inst,
 			"%s: inst is in bad state, can not change state to %s\n",
@@ -1011,17 +1031,23 @@ int msm_vidc_change_state(struct msm_vidc_inst *inst,
 		return 0;
 	}
 
-	if (request_state == MSM_VIDC_ERROR)
-		i_vpr_e(inst, FMT_STRING_STATE_CHANGE,
-		   func, state_name(request_state), state_name(inst->state));
-	else
-		i_vpr_h(inst, FMT_STRING_STATE_CHANGE,
-		   func, state_name(request_state), state_name(inst->state));
+	/* current and requested state is same */
+	if (inst->state == request_state)
+		return 0;
 
-	trace_msm_vidc_common_state_change(inst, func, state_name(inst->state),
+	/* check if requested state movement is allowed */
+	allow = msm_vidc_allow_state_change(inst, request_state);
+	if (allow != MSM_VIDC_ALLOW) {
+		i_vpr_e(inst, "%s: %s state change %s -> %s\n", func,
+			allow_name(allow), state_name(inst->state),
 			state_name(request_state));
+		return (allow == MSM_VIDC_DISALLOW ? -EINVAL : 0);
+	}
 
-	inst->state = request_state;
+	/* go ahead and update inst state */
+	rc = msm_vidc_update_state(inst, request_state, func);
+	if (rc)
+		return rc;
 
 	return 0;
 }
@@ -1030,8 +1056,8 @@ int msm_vidc_change_sub_state(struct msm_vidc_inst *inst,
 		enum msm_vidc_sub_state clear_sub_state,
 		enum msm_vidc_sub_state set_sub_state, const char *func)
 {
-	int i = 0;
 	enum msm_vidc_sub_state prev_sub_state;
+	int rc = 0;
 
 	if (!inst) {
 		d_vpr_e("%s: invalid params\n", __func__);
@@ -1061,18 +1087,11 @@ int msm_vidc_change_sub_state(struct msm_vidc_inst *inst,
 
 	/* print substates only when there is a change */
 	if (inst->sub_state != prev_sub_state) {
-		strlcpy(inst->sub_state_name, "\0", sizeof(inst->sub_state_name));
-		for (i = 0; i < MSM_VIDC_MAX_SUB_STATES; i++) {
-			if (inst->sub_state == MSM_VIDC_SUB_STATE_NONE) {
-				strlcpy(inst->sub_state_name, "SUB_STATE_NONE",
-					sizeof(inst->sub_state_name));
-				break;
-			}
-			if (inst->sub_state & BIT(i))
-				strlcat(inst->sub_state_name, sub_state_name(BIT(i)),
-					sizeof(inst->sub_state_name));
-		}
-		i_vpr_h(inst, "%s: sub state changed to %s\n", func, inst->sub_state_name);
+		rc = prepare_sub_state_name(inst->sub_state, inst->sub_state_name,
+			sizeof(inst->sub_state_name));
+		if (!rc)
+			i_vpr_h(inst, "%s: state %s and sub state changed to %s\n",
+				func, state_name(inst->state), inst->sub_state_name);
 	}
 
 	return 0;
@@ -1110,55 +1129,6 @@ exit:
 	return allow;
 }
 
-bool msm_vidc_allow_s_ctrl(struct msm_vidc_inst *inst,
-	enum msm_vidc_inst_capability_type cap_id)
-{
-	bool allow = false;
-
-	if (!inst || !inst->capabilities) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return false;
-	}
-	if (is_state(inst, MSM_VIDC_OPEN)) {
-		allow = true;
-		goto exit;
-	}
-
-	if (!inst->capabilities->cap[cap_id].cap_id ||
-	    !inst->capabilities->cap[cap_id].v4l2_id) {
-		allow = false;
-		goto exit;
-	}
-
-	if (is_decode_session(inst)) {
-		if (!inst->bufq[INPUT_PORT].vb2q->streaming) {
-			allow = true;
-			goto exit;
-		}
-		if (inst->bufq[INPUT_PORT].vb2q->streaming) {
-			if (inst->capabilities->cap[cap_id].flags &
-			    CAP_FLAG_DYNAMIC_ALLOWED)
-				allow = true;
-		}
-	} else if (is_encode_session(inst)) {
-		if (!inst->bufq[OUTPUT_PORT].vb2q->streaming) {
-			allow = true;
-			goto exit;
-		}
-		if (inst->bufq[OUTPUT_PORT].vb2q->streaming) {
-			if (inst->capabilities->cap[cap_id].flags &
-			    CAP_FLAG_DYNAMIC_ALLOWED)
-				allow = true;
-		}
-	}
-
-exit:
-	if (!allow)
-		i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n",
-			__func__, cap_id, state_name(inst->state));
-	return allow;
-}
-
 bool msm_vidc_allow_metadata_delivery(struct msm_vidc_inst *inst, u32 cap_id,
 	u32 port)
 {
@@ -1387,79 +1357,6 @@ bool msm_vidc_allow_streamon(struct msm_vidc_inst *inst, u32 type)
 	return false;
 }
 
-enum msm_vidc_allow msm_vidc_allow_streamoff(struct msm_vidc_inst *inst, u32 type)
-{
-	enum msm_vidc_allow allow = MSM_VIDC_ALLOW;
-
-	if (!inst) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return MSM_VIDC_DISALLOW;
-	}
-	if (type == INPUT_MPLANE) {
-		if (!inst->bufq[INPUT_PORT].vb2q->streaming)
-			allow = MSM_VIDC_IGNORE;
-	} else if (type == INPUT_META_PLANE) {
-		if (inst->bufq[INPUT_PORT].vb2q->streaming)
-			allow = MSM_VIDC_DISALLOW;
-		else if (!inst->bufq[INPUT_META_PORT].vb2q->streaming)
-			allow = MSM_VIDC_IGNORE;
-	} else if (type == OUTPUT_MPLANE) {
-		if (!inst->bufq[OUTPUT_PORT].vb2q->streaming)
-			allow = MSM_VIDC_IGNORE;
-	} else if (type == OUTPUT_META_PLANE) {
-		if (inst->bufq[OUTPUT_PORT].vb2q->streaming)
-			allow = MSM_VIDC_DISALLOW;
-		else if (!inst->bufq[OUTPUT_META_PORT].vb2q->streaming)
-			allow = MSM_VIDC_IGNORE;
-	}
-	if (allow != MSM_VIDC_ALLOW)
-		i_vpr_e(inst, "%s: type %d is %s in state %s\n",
-				__func__, type, allow_name(allow),
-				state_name(inst->state));
-
-	return allow;
-}
-
-enum msm_vidc_allow msm_vidc_allow_qbuf(struct msm_vidc_inst *inst, u32 type)
-{
-	int port = 0;
-
-	if (!inst) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return MSM_VIDC_DISALLOW;
-	}
-
-	port = v4l2_type_to_driver_port(inst, type, __func__);
-	if (port < 0)
-		return MSM_VIDC_DISALLOW;
-
-	/* defer queuing if streamon not completed */
-	if (!inst->bufq[port].vb2q->streaming)
-		return MSM_VIDC_DEFER;
-
-	if (type == INPUT_META_PLANE || type == OUTPUT_META_PLANE)
-		return MSM_VIDC_DEFER;
-
-	if (type == INPUT_MPLANE) {
-		if (is_state(inst, MSM_VIDC_OPEN) ||
-			is_state(inst, MSM_VIDC_OUTPUT_STREAMING))
-			return MSM_VIDC_DEFER;
-		else
-			return MSM_VIDC_ALLOW;
-	} else if (type == OUTPUT_MPLANE) {
-		if (is_state(inst, MSM_VIDC_OPEN) ||
-			is_state(inst, MSM_VIDC_INPUT_STREAMING))
-			return MSM_VIDC_DEFER;
-		else
-			return MSM_VIDC_ALLOW;
-	} else {
-		i_vpr_e(inst, "%s: unknown buffer type %d\n", __func__, type);
-		return MSM_VIDC_DISALLOW;
-	}
-
-	return MSM_VIDC_DISALLOW;
-}
-
 enum msm_vidc_allow msm_vidc_allow_input_psc(struct msm_vidc_inst *inst)
 {
 	enum msm_vidc_allow allow = MSM_VIDC_ALLOW;
@@ -3339,12 +3236,29 @@ int msm_vidc_queue_deferred_buffers(struct msm_vidc_inst *inst, enum msm_vidc_bu
 	return 0;
 }
 
+int msm_vidc_buf_queue(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;
+	}
+
+	msm_vidc_scale_power(inst, is_input_buffer(buf->type));
+
+	rc = msm_vidc_queue_buffer(inst, buf);
+	if (rc)
+		return rc;
+
+	return rc;
+}
+
 int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer *vb2)
 {
 	int rc = 0;
 	struct msm_vidc_buffer *buf = NULL;
 	struct msm_vidc_fence *fence = NULL;
-	enum msm_vidc_allow allow;
 
 	if (!inst || !vb2 || !inst->capabilities) {
 		d_vpr_e("%s: invalid params\n", __func__);
@@ -3363,20 +3277,7 @@ int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer *
 		buf->fence_id = fence->dma_fence.seqno;
 	}
 
-	allow = msm_vidc_allow_qbuf(inst, vb2->type);
-	if (allow == MSM_VIDC_DISALLOW) {
-		i_vpr_e(inst, "%s: qbuf not allowed\n", __func__);
-		rc = -EINVAL;
-		goto exit;
-	} else if (allow == MSM_VIDC_DEFER) {
-		print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
-		rc = 0;
-		goto exit;
-	}
-
-	msm_vidc_scale_power(inst, is_input_buffer(buf->type));
-
-	rc = msm_vidc_queue_buffer(inst, buf);
+	rc = inst->event_handle(inst, MSM_VIDC_BUF_QUEUE, buf);
 	if (rc)
 		goto exit;
 
@@ -4198,10 +4099,6 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst,
 	if (rc)
 		goto error;
 
-	rc = msm_vidc_state_change_streamoff(inst, port);
-	if (rc)
-		goto error;
-
 	core = inst->core;
 	i_vpr_h(inst, "%s: wait on port: %d for time: %d ms\n",
 		__func__, port, core->capabilities[HW_RESPONSE_TIMEOUT].value);
@@ -4241,6 +4138,10 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst,
 		goto error;
 	}
 
+	rc = msm_vidc_state_change_streamoff(inst, port);
+	if (rc)
+		goto error;
+
 	/* flush deferred buffers */
 	msm_vidc_flush_buffers(inst, buffer_type);
 	msm_vidc_flush_read_only_buffers(inst, buffer_type);
@@ -4290,10 +4191,6 @@ int msm_vidc_session_close(struct msm_vidc_inst *inst)
 	}
 	inst_lock(inst, __func__);
 
-	msm_vidc_change_state(inst, MSM_VIDC_CLOSE, __func__);
-	inst->sub_state = MSM_VIDC_SUB_STATE_NONE;
-	strlcpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name));
-
 	return rc;
 }
 
@@ -5129,7 +5026,6 @@ void msm_vidc_fw_unload_handler(struct work_struct *work)
 void msm_vidc_batch_handler(struct work_struct *work)
 {
 	struct msm_vidc_inst *inst;
-	enum msm_vidc_allow allow;
 	struct msm_vidc_core *core;
 	int rc = 0;
 
@@ -5152,8 +5048,8 @@ void msm_vidc_batch_handler(struct work_struct *work)
 		goto exit;
 	}
 
-	allow = msm_vidc_allow_qbuf(inst, OUTPUT_MPLANE);
-	if (allow != MSM_VIDC_ALLOW) {
+	if (is_state(inst, MSM_VIDC_OPEN) ||
+		is_state(inst, MSM_VIDC_INPUT_STREAMING)) {
 		i_vpr_e(inst, "%s: not allowed in state: %s\n", __func__,
 			state_name(inst->state));
 		goto exit;

+ 736 - 2
driver/vidc/src/msm_vidc_state.c

@@ -4,10 +4,14 @@
  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
+#include "msm_vidc_control.h"
 #include "msm_vidc_driver.h"
 #include "msm_vidc_state.h"
-#include "msm_vidc_core.h"
 #include "msm_vidc_debug.h"
+#include "msm_vidc_core.h"
+#include "msm_vidc_vb2.h"
+#include "msm_vidc.h"
+#include "msm_vidc_events.h"
 
 bool core_in_valid_state(struct msm_vidc_core *core)
 {
@@ -36,6 +40,22 @@ exit:
 	return name;
 }
 
+static const char * const event_name_arr[] =
+	FOREACH_EVENT(GENERATE_STRING);
+
+static const char *event_name(enum msm_vidc_event event)
+{
+	const char *name = "UNKNOWN EVENT";
+
+	if (event >= ARRAY_SIZE(event_name_arr))
+		goto exit;
+
+	name = event_name_arr[event];
+
+exit:
+	return name;
+}
+
 static int __strict_check(struct msm_vidc_core *core, const char *function)
 {
 	bool fatal = !mutex_is_locked(&core->lock);
@@ -48,6 +68,18 @@ static int __strict_check(struct msm_vidc_core *core, const char *function)
 	return fatal ? -EINVAL : 0;
 }
 
+static int __strict_inst_check(struct msm_vidc_inst *inst, const char *function)
+{
+	bool fatal = !mutex_is_locked(&inst->lock);
+
+	WARN_ON(fatal);
+
+	if (fatal)
+		d_vpr_e("%s: strict check failed\n", function);
+
+	return fatal ? -EINVAL : 0;
+}
+
 static int msm_vidc_core_deinit_state(struct msm_vidc_core *core,
 	enum msm_vidc_core_event_type type,
 	struct msm_vidc_event_data *data)
@@ -181,7 +213,14 @@ static int msm_vidc_core_error_state(struct msm_vidc_core *core,
 	return rc;
 }
 
-struct msm_vidc_core_state_handle *msm_vidc_get_core_state_handle(
+struct msm_vidc_core_state_handle {
+	enum msm_vidc_core_state   state;
+	int                      (*handle)(struct msm_vidc_core *core,
+				   enum msm_vidc_core_event_type type,
+				   struct msm_vidc_event_data *data);
+};
+
+static struct msm_vidc_core_state_handle *msm_vidc_get_core_state_handle(
 	enum msm_vidc_core_state req_state)
 {
 	int cnt;
@@ -456,3 +495,698 @@ int msm_vidc_change_core_sub_state(struct msm_vidc_core *core,
 
 	return 0;
 }
+
+static int msm_vidc_open_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_S_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)data;
+
+		rc = msm_vidc_s_fmt(inst, f);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_S_CTRL:
+	{
+		struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data;
+
+		/* allow set_control request in open state */
+		rc = msm_vidc_s_ctrl(inst, ctrl);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data;
+
+		rc = msm_vidc_reqbufs(inst, b);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMON:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		rc = msm_vidc_start_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		/* ignore streamoff request in open state */
+		i_vpr_e(inst, "%s: type %d is %s in state %s\n",
+						__func__, q->type, allow_name(MSM_VIDC_IGNORE),
+						state_name(inst->state));
+		break;
+	}
+	case MSM_VIDC_CMD_START:
+	{
+		rc = msm_vidc_start_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_STOP:
+	{
+		rc = msm_vidc_stop_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* defer qbuf request in open state */
+		print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+		break;
+	}
+	default:
+	{
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_input_streaming_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_S_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)data;
+
+		rc = msm_vidc_s_fmt(inst, f);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_S_CTRL:
+	{
+		struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data;
+		u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id);
+
+		if (cap_id == INST_CAP_NONE) {
+			i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id);
+			return -EINVAL;
+		}
+
+		/* disallow */
+		if (is_decode_session(inst)) {
+			/* check dynamic allowed if master port is streaming */
+			if (!(inst->capabilities->cap[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) {
+				i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n",
+					__func__, cap_id, state_name(inst->state));
+				return -EINVAL;
+			}
+		}
+
+		rc = msm_vidc_s_ctrl(inst, ctrl);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data;
+
+		rc = msm_vidc_reqbufs(inst, b);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMON:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		rc = msm_vidc_start_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+		enum msm_vidc_allow allow = MSM_VIDC_ALLOW;
+
+		/* ignore */
+		if (q->type == OUTPUT_MPLANE || q->type == OUTPUT_META_PLANE)
+			allow = MSM_VIDC_IGNORE;
+		/* disallow */
+		else if (q->type == INPUT_META_PLANE)
+			allow = MSM_VIDC_DISALLOW;
+
+		if (allow != MSM_VIDC_ALLOW) {
+			i_vpr_e(inst, "%s: type %d is %s in state %s\n",
+				__func__, q->type, allow_name(allow),
+					state_name(inst->state));
+			return (allow == MSM_VIDC_DISALLOW ? -EINVAL : 0);
+		}
+
+		/* sanitize type field */
+		if (q->type != INPUT_MPLANE) {
+			i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_stop_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_START:
+	{
+		rc = msm_vidc_start_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_STOP:
+	{
+		rc = msm_vidc_stop_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* defer meta port */
+		if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		/* disallow */
+		if (buf->type != MSM_VIDC_BUF_INPUT && buf->type != MSM_VIDC_BUF_OUTPUT) {
+			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
+			return -EINVAL;
+		}
+
+		/* defer output port */
+		if (buf->type == MSM_VIDC_BUF_OUTPUT) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		rc = msm_vidc_buf_queue(inst, buf);
+		if (rc)
+			return rc;
+		break;
+	}
+	default:
+	{
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_output_streaming_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_S_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)data;
+
+		rc = msm_vidc_s_fmt(inst, f);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_S_CTRL:
+	{
+		struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data;
+		u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id);
+
+		if (cap_id == INST_CAP_NONE) {
+			i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id);
+			return -EINVAL;
+		}
+
+		/* disallow */
+		if (is_encode_session(inst)) {
+			/* check dynamic allowed if master port is streaming */
+			if (!(inst->capabilities->cap[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) {
+				i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n",
+					__func__, cap_id, state_name(inst->state));
+				return -EINVAL;
+			}
+		}
+
+		rc = msm_vidc_s_ctrl(inst, ctrl);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data;
+
+		rc = msm_vidc_reqbufs(inst, b);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMON:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		rc = msm_vidc_start_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+		enum msm_vidc_allow allow = MSM_VIDC_ALLOW;
+
+		/* ignore */
+		if (q->type == INPUT_MPLANE || q->type == INPUT_META_PLANE)
+			allow = MSM_VIDC_IGNORE;
+		/* disallow */
+		else if (q->type == OUTPUT_META_PLANE)
+			allow = MSM_VIDC_DISALLOW;
+
+		if (allow != MSM_VIDC_ALLOW) {
+			i_vpr_e(inst, "%s: type %d is %s in state %s\n",
+				__func__, q->type, allow_name(allow),
+					state_name(inst->state));
+			return (allow == MSM_VIDC_DISALLOW ? -EINVAL : 0);
+		}
+
+		/* sanitize type field */
+		if (q->type != OUTPUT_MPLANE) {
+			i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_stop_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_START:
+	{
+		rc = msm_vidc_start_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_STOP:
+	{
+		rc = msm_vidc_stop_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* defer meta port */
+		if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		/* disallow */
+		if (buf->type != MSM_VIDC_BUF_INPUT && buf->type != MSM_VIDC_BUF_OUTPUT) {
+			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
+			return -EINVAL;
+		}
+
+		/* defer input port */
+		if (buf->type == MSM_VIDC_BUF_INPUT) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		rc = msm_vidc_buf_queue(inst, buf);
+		if (rc)
+			return rc;
+		break;
+	}
+	default: {
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_streaming_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_S_CTRL:
+	{
+		struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data;
+		u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id);
+
+		if (cap_id == INST_CAP_NONE) {
+			i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id);
+			return -EINVAL;
+		}
+
+		/* disallow */
+		if (!(inst->capabilities->cap[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) {
+			i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n",
+				__func__, cap_id, state_name(inst->state));
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_s_ctrl(inst, ctrl);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		/* disallow */
+		if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) {
+			i_vpr_e(inst, "%s: type %d is %s in state %s\n",
+					__func__, q->type, allow_name(MSM_VIDC_DISALLOW),
+					state_name(inst->state));
+			return -EINVAL;
+		}
+
+		/* sanitize type field */
+		if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) {
+			i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_stop_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_START:
+	{
+		rc = msm_vidc_start_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_CMD_STOP:
+	{
+		rc = msm_vidc_stop_cmd(inst);
+		if (rc)
+			return rc;
+		break;
+	}
+	case MSM_VIDC_BUF_QUEUE:
+	{
+		struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data;
+
+		/* defer meta port */
+		if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) {
+			print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
+			return 0;
+		}
+
+		/* disallow */
+		if (buf->type != MSM_VIDC_BUF_INPUT && buf->type != MSM_VIDC_BUF_OUTPUT) {
+			i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type);
+			return -EINVAL;
+		}
+
+		rc = msm_vidc_buf_queue(inst, buf);
+		if (rc)
+			return rc;
+		break;
+	}
+	default: {
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+static int msm_vidc_close_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+
+	return -EINVAL;
+}
+
+static int msm_vidc_error_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_event event, void *data)
+{
+	int rc = 0;
+
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/* inst must be locked */
+	rc = __strict_inst_check(inst, __func__);
+	if (rc) {
+		i_vpr_e(inst, "%s(): inst was not locked\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case MSM_VIDC_STREAMOFF:
+	{
+		struct vb2_queue *q = (struct vb2_queue *)data;
+
+		rc = msm_vidc_stop_streaming(inst, q);
+		if (rc)
+			return rc;
+		break;
+	}
+	default: {
+		i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event));
+		return -EINVAL;
+	}
+	}
+
+	return rc;
+}
+
+struct msm_vidc_state_handle {
+	enum msm_vidc_state   state;
+	int                 (*handle)(struct msm_vidc_inst *inst,
+		enum msm_vidc_event event, void *data);
+};
+
+static struct msm_vidc_state_handle *msm_vidc_get_state_handle(
+	struct msm_vidc_inst *inst,
+	enum msm_vidc_state req_state)
+{
+	int cnt;
+	struct msm_vidc_state_handle *inst_state_handle = NULL;
+	static struct msm_vidc_state_handle state_handle[] = {
+		{MSM_VIDC_OPEN,             msm_vidc_open_state             },
+		{MSM_VIDC_INPUT_STREAMING,  msm_vidc_input_streaming_state  },
+		{MSM_VIDC_OUTPUT_STREAMING, msm_vidc_output_streaming_state },
+		{MSM_VIDC_STREAMING,        msm_vidc_streaming_state        },
+		{MSM_VIDC_CLOSE,            msm_vidc_close_state            },
+		{MSM_VIDC_ERROR,            msm_vidc_error_state            },
+	};
+
+	for (cnt = 0; cnt < ARRAY_SIZE(state_handle); cnt++) {
+		if (state_handle[cnt].state == req_state) {
+			inst_state_handle = &state_handle[cnt];
+			break;
+		}
+	}
+
+	/* check if req_state does not exist in the table */
+	if (cnt == ARRAY_SIZE(state_handle)) {
+		i_vpr_e(inst, "%s: invalid state %s\n", __func__, state_name(req_state));
+		return inst_state_handle;
+	}
+
+	return inst_state_handle;
+}
+
+int msm_vidc_update_state(struct msm_vidc_inst *inst,
+	enum msm_vidc_state request_state, const char *func)
+{
+	struct msm_vidc_state_handle *state_handle = NULL;
+	int rc = 0;
+
+	/* get inst state handler for requested state */
+	state_handle = msm_vidc_get_state_handle(inst, request_state);
+	if (!state_handle)
+		return -EINVAL;
+
+	if (request_state == MSM_VIDC_ERROR)
+		i_vpr_e(inst, FMT_STRING_STATE_CHANGE,
+		   func, state_name(request_state), state_name(inst->state));
+	else
+		i_vpr_h(inst, FMT_STRING_STATE_CHANGE,
+		   func, state_name(request_state), state_name(inst->state));
+
+	trace_msm_vidc_common_state_change(inst, func, state_name(inst->state),
+			state_name(request_state));
+
+	/* finally update inst state and handler */
+	inst->state = state_handle->state;
+	inst->event_handle = state_handle->handle;
+
+	return rc;
+}
+
+struct msm_vidc_state_allow {
+	enum msm_vidc_state        from;
+	enum msm_vidc_state        to;
+	enum msm_vidc_allow        allow;
+};
+
+enum msm_vidc_allow msm_vidc_allow_state_change(
+	struct msm_vidc_inst *inst,
+	enum msm_vidc_state req_state)
+{
+	int cnt;
+	enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
+	static struct msm_vidc_state_allow state[] = {
+		/* from, to, allow */
+		{MSM_VIDC_OPEN,             MSM_VIDC_OPEN,               MSM_VIDC_IGNORE    },
+		{MSM_VIDC_OPEN,             MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OPEN,             MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OPEN,             MSM_VIDC_STREAMING,          MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_OPEN,             MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OPEN,             MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_OPEN,               MSM_VIDC_ALLOW     },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_IGNORE    },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_STREAMING,          MSM_VIDC_ALLOW     },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_INPUT_STREAMING,  MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_OPEN,               MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_IGNORE    },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_STREAMING,          MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_STREAMING,        MSM_VIDC_OPEN,               MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_ALLOW     },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_ALLOW     },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_STREAMING,          MSM_VIDC_IGNORE    },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_STREAMING,        MSM_VIDC_ERROR,              MSM_VIDC_ALLOW     },
+
+		{MSM_VIDC_CLOSE,            MSM_VIDC_OPEN,               MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_STREAMING,          MSM_VIDC_DISALLOW  },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_CLOSE,              MSM_VIDC_IGNORE    },
+		{MSM_VIDC_CLOSE,            MSM_VIDC_ERROR,              MSM_VIDC_IGNORE    },
+
+		{MSM_VIDC_ERROR,            MSM_VIDC_OPEN,               MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_INPUT_STREAMING,    MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_OUTPUT_STREAMING,   MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_STREAMING,          MSM_VIDC_IGNORE    },
+		{MSM_VIDC_ERROR,            MSM_VIDC_CLOSE,              MSM_VIDC_ALLOW     },
+		{MSM_VIDC_ERROR,            MSM_VIDC_ERROR,              MSM_VIDC_IGNORE    },
+	};
+
+	for (cnt = 0; cnt < ARRAY_SIZE(state); cnt++) {
+		if (state[cnt].from == inst->state && state[cnt].to == req_state) {
+			allow = state[cnt].allow;
+			break;
+		}
+	}
+
+	return allow;
+}

+ 33 - 7
driver/vidc/src/msm_vidc_v4l2.c

@@ -166,7 +166,7 @@ int msm_v4l2_s_fmt(struct file *filp, void *fh,
 		rc = -EBUSY;
 		goto unlock;
 	}
-	rc = msm_vidc_s_fmt((void *)inst, f);
+	rc = inst->event_handle(inst, MSM_VIDC_S_FMT, f);
 	if (rc)
 		goto unlock;
 
@@ -332,7 +332,7 @@ int msm_v4l2_reqbufs(struct file *filp, void *fh,
 
 	client_lock(inst, __func__);
 	inst_lock(inst, __func__);
-	rc = msm_vidc_reqbufs((void *)inst, b);
+	rc = inst->event_handle(inst, MSM_VIDC_REQBUFS, b);
 	if (rc)
 		goto unlock;
 
@@ -437,11 +437,11 @@ int msm_v4l2_qbuf(struct file *filp, void *fh,
 	}
 
 	/*
-	 * do not acquire inst lock here. acquire it in msm_vidc_buf_queue.
-	 * for requests, msm_vidc_buf_queue() is not called from here.
+	 * do not acquire inst lock here. acquire it in msm_vb2_buf_queue.
+	 * for requests, msm_vb2_buf_queue() is not called from here.
 	 * instead it's called as part of msm_v4l2_request_queue().
 	 * hence acquire the inst lock in common function i.e
-	 * msm_vidc_buf_queue, to handle both requests and non-request
+	 * msm_vb2_buf_queue, to handle both requests and non-request
 	 * scenarios.
 	 */
 	rc = msm_vidc_qbuf(inst, vdev->v4l2_dev->mdev, b);
@@ -618,6 +618,7 @@ int msm_v4l2_decoder_cmd(struct file *filp, void *fh,
 				struct v4l2_decoder_cmd *dec)
 {
 	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	enum msm_vidc_event event;
 	int rc = 0;
 
 	inst = get_inst_ref(g_core, inst);
@@ -633,7 +634,19 @@ int msm_v4l2_decoder_cmd(struct file *filp, void *fh,
 		rc = -EBUSY;
 		goto unlock;
 	}
-	rc = msm_vidc_cmd((void *)inst, (union msm_v4l2_cmd *)dec);
+	if (!dec) {
+		i_vpr_e(inst, "%s: invalid params\n", __func__);
+		rc = -EINVAL;
+		goto unlock;
+	}
+	if (dec->cmd != V4L2_DEC_CMD_START &&
+		dec->cmd != V4L2_DEC_CMD_STOP) {
+		i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, dec->cmd);
+		rc = -EINVAL;
+		goto unlock;
+	}
+	event = (dec->cmd == V4L2_DEC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP);
+	rc = inst->event_handle(inst, event, NULL);
 	if (rc)
 		goto unlock;
 
@@ -680,6 +693,7 @@ int msm_v4l2_encoder_cmd(struct file *filp, void *fh,
 				struct v4l2_encoder_cmd *enc)
 {
 	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	enum msm_vidc_event event;
 	int rc = 0;
 
 	inst = get_inst_ref(g_core, inst);
@@ -695,7 +709,19 @@ int msm_v4l2_encoder_cmd(struct file *filp, void *fh,
 		rc = -EBUSY;
 		goto unlock;
 	}
-	rc = msm_vidc_cmd((void *)inst, (union msm_v4l2_cmd *)enc);
+	if (!enc) {
+		i_vpr_e(inst, "%s: invalid params\n", __func__);
+		rc = -EINVAL;
+		goto unlock;
+	}
+	if (enc->cmd != V4L2_ENC_CMD_START &&
+		enc->cmd != V4L2_ENC_CMD_STOP) {
+		i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, enc->cmd);
+		rc = -EINVAL;
+		goto unlock;
+	}
+	event = (enc->cmd == V4L2_ENC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP);
+	rc = inst->event_handle(inst, event, NULL);
 	if (rc)
 		goto unlock;
 

+ 84 - 79
driver/vidc/src/msm_vidc_vb2.c

@@ -239,7 +239,7 @@ exit:
 	return;
 }
 
-int msm_vidc_queue_setup(struct vb2_queue *q,
+int msm_vb2_queue_setup(struct vb2_queue *q,
 		unsigned int *num_buffers, unsigned int *num_planes,
 		unsigned int sizes[], struct device *alloc_devs[])
 {
@@ -366,11 +366,10 @@ int msm_vidc_queue_setup(struct vb2_queue *q,
 	return rc;
 }
 
-int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
+int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
 {
 	int rc = 0;
 	struct msm_vidc_inst *inst;
-	enum msm_vidc_buffer_type buf_type;
 
 	if (!q || !q->drv_priv) {
 		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
@@ -391,22 +390,46 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
 		goto unlock;
 	}
 
-	if (!msm_vidc_allow_streamon(inst, q->type)) {
-		rc = -EBUSY;
+	rc = inst->event_handle(inst, MSM_VIDC_STREAMON, q);
+	if (rc) {
+		i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type));
+		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
 		goto unlock;
 	}
 
+unlock:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
+int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q)
+{
+	enum msm_vidc_buffer_type buf_type;
+	int rc = 0;
+
+	if (!inst || !q) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!msm_vidc_allow_streamon(inst, q->type))
+		return -EBUSY;
+
 	if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) {
 		i_vpr_h(inst, "%s: nothing to start on %s\n",
 			__func__, v4l2_type_name(q->type));
-		rc = 0;
-		goto unlock;
+		return 0;
+	}
+	if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
+		return -EINVAL;
 	}
 	if (!is_decode_session(inst) && !is_encode_session(inst)) {
-		i_vpr_e(inst, "%s: invalid session %d\n",
-			__func__, inst->domain);
-		rc = -EINVAL;
-		goto unlock;
+		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
+		return -EINVAL;
 	}
 	i_vpr_h(inst, "Streamon: %s\n", v4l2_type_name(q->type));
 
@@ -414,30 +437,30 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
 		inst->once_per_session_set = true;
 		rc = msm_vidc_prepare_dependency_list(inst);
 		if (rc)
-			goto unlock;
+			return rc;
 
 		rc = msm_vidc_session_set_codec(inst);
 		if (rc)
-			goto unlock;
+			return rc;
 
 		rc = msm_vidc_session_set_secure_mode(inst);
 		if (rc)
-			goto unlock;
+			return rc;
 
 		if (is_encode_session(inst)) {
 			rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst,
 				MSM_VIDC_BUF_ARP);
 			if (rc)
-				goto unlock;
+				return rc;
 		} else if(is_decode_session(inst)) {
 			rc = msm_vidc_session_set_default_header(inst);
 			if (rc)
-				goto unlock;
+				return rc;
 
 			rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst,
 				MSM_VIDC_BUF_PERSIST);
 			if (rc)
-				goto unlock;
+				return rc;
 		}
 	}
 
@@ -452,33 +475,26 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
 			rc = msm_vdec_streamon_input(inst);
 		else if (is_encode_session(inst))
 			rc = msm_venc_streamon_input(inst);
-		else
-			goto unlock;
 	} else if (q->type == OUTPUT_MPLANE) {
 		if (is_decode_session(inst))
 			rc = msm_vdec_streamon_output(inst);
 		else if (is_encode_session(inst))
 			rc = msm_venc_streamon_output(inst);
-		else
-			goto unlock;
-	} else {
-		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
-		goto unlock;
 	}
 	if (rc)
-		goto unlock;
+		return rc;
 
 	/* print final buffer counts & size details */
 	msm_vidc_print_buffer_info(inst);
 
 	buf_type = v4l2_type_to_driver(q->type, __func__);
 	if (!buf_type)
-		goto unlock;
+		return -EINVAL;
 
 	/* queue pending buffers */
 	rc = msm_vidc_queue_deferred_buffers(inst, buf_type);
 	if (rc)
-		goto unlock;
+		return rc;
 
 	/* initialize statistics timer(one time) */
 	if (!inst->stats.time_ms)
@@ -487,71 +503,40 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
 	/* schedule to print buffer statistics */
 	rc = schedule_stats_work(inst);
 	if (rc)
-		goto unlock;
+		return rc;
 
 	if ((q->type == INPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming) ||
 		(q->type == OUTPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming)) {
 		rc = msm_vidc_get_properties(inst);
 		if (rc)
-			goto unlock;
+			return rc;
 	}
 
 	i_vpr_h(inst, "Streamon: %s successful\n", v4l2_type_name(q->type));
-
-unlock:
-	if (rc) {
-		i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type));
-		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
-	}
-	inst_unlock(inst, __func__);
-	client_unlock(inst, __func__);
-	put_inst(inst);
 	return rc;
 }
 
-void msm_vidc_stop_streaming(struct vb2_queue *q)
+int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q)
 {
 	int rc = 0;
-	struct msm_vidc_inst *inst;
-	enum msm_vidc_allow allow;
 
-	if (!q || !q->drv_priv) {
-		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
-		return;
-	}
-	inst = q->drv_priv;
-	inst = get_inst_ref(g_core, inst);
-	if (!inst || !inst->core) {
+	if (!inst || !q) {
 		d_vpr_e("%s: invalid params\n", __func__);
-		return;
+		return -EINVAL;
 	}
 
-	client_lock(inst, __func__);
-	inst_lock(inst, __func__);
 	if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) {
 		i_vpr_h(inst, "%s: nothing to stop on %s\n",
 			__func__, v4l2_type_name(q->type));
-		rc = 0;
-		goto unlock;
+		return 0;
 	}
-
-	allow = msm_vidc_allow_streamoff(inst, q->type);
-	if (allow == MSM_VIDC_DISALLOW) {
-		rc = -EBUSY;
-		goto unlock;
-	} else if (allow == MSM_VIDC_IGNORE) {
-		rc = 0;
-		goto unlock;
-	} else if (allow != MSM_VIDC_ALLOW) {
-		rc = -EINVAL;
-		goto unlock;
+	if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) {
+		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
+		return -EINVAL;
 	}
-
 	if (!is_decode_session(inst) && !is_encode_session(inst)) {
-		i_vpr_e(inst, "%s: invalid session %d\n",
-			__func__, inst->domain);
-		rc = -EINVAL;
-		goto unlock;
+		i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain);
+		return -EINVAL;
 	}
 	i_vpr_h(inst, "Streamoff: %s\n", v4l2_type_name(q->type));
 
@@ -565,13 +550,9 @@ void msm_vidc_stop_streaming(struct vb2_queue *q)
 			rc = msm_vdec_streamoff_output(inst);
 		else if (is_encode_session(inst))
 			rc = msm_venc_streamoff_output(inst);
-	} else {
-		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
-		rc = -EINVAL;
-		goto unlock;
 	}
 	if (rc)
-		goto unlock;
+		return rc;
 
 	/* Input port streamoff */
 	if (q->type == INPUT_MPLANE) {
@@ -583,19 +564,43 @@ void msm_vidc_stop_streaming(struct vb2_queue *q)
 	}
 
 	i_vpr_h(inst, "Streamoff: %s successful\n", v4l2_type_name(q->type));
+	return rc;
+}
 
-unlock:
+void msm_vb2_stop_streaming(struct vb2_queue *q)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	if (!q || !q->drv_priv) {
+		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
+		return;
+	}
+	inst = q->drv_priv;
+	inst = get_inst_ref(g_core, inst);
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
+	rc = inst->event_handle(inst, MSM_VIDC_STREAMOFF, q);
 	if (rc) {
 		i_vpr_e(inst, "Streamoff: %s failed\n", v4l2_type_name(q->type));
 		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
+		goto unlock;
 	}
+
+unlock:
 	inst_unlock(inst, __func__);
 	client_unlock(inst, __func__);
 	put_inst(inst);
+
 	return;
 }
 
-void msm_vidc_buf_queue(struct vb2_buffer *vb2)
+void msm_vb2_buf_queue(struct vb2_buffer *vb2)
 {
 	int rc = 0;
 	struct msm_vidc_inst *inst;
@@ -700,11 +705,11 @@ unlock:
 	put_inst(inst);
 }
 
-void msm_vidc_buf_cleanup(struct vb2_buffer *vb)
+void msm_vb2_buf_cleanup(struct vb2_buffer *vb)
 {
 }
 
-int msm_vidc_buf_out_validate(struct vb2_buffer *vb)
+int msm_vb2_buf_out_validate(struct vb2_buffer *vb)
 {
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 
@@ -712,7 +717,7 @@ int msm_vidc_buf_out_validate(struct vb2_buffer *vb)
 	return 0;
 }
 
-void msm_vidc_buf_request_complete(struct vb2_buffer *vb)
+void msm_vb2_request_complete(struct vb2_buffer *vb)
 {
 	struct msm_vidc_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
 

+ 3 - 3
driver/vidc/src/venus_hfi_queue.c

@@ -509,7 +509,7 @@ int venus_hfi_queue_init(struct msm_vidc_core *core)
 	}
 
 	memset(&mem, 0, sizeof(mem));
-	mem.type = MSM_VIDC_BUF_QUEUE;
+	mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE;
 	mem.region = MSM_VIDC_NON_SECURE;
 	mem.size = TOTAL_QSIZE;
 	mem.secure = false;
@@ -570,7 +570,7 @@ int venus_hfi_queue_init(struct msm_vidc_core *core)
 
 	/* sfr buffer */
 	memset(&mem, 0, sizeof(mem));
-	mem.type = MSM_VIDC_BUF_QUEUE;
+	mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE;
 	mem.region = MSM_VIDC_NON_SECURE;
 	mem.size = ALIGNED_SFR_SIZE;
 	mem.secure = false;
@@ -610,7 +610,7 @@ int venus_hfi_queue_init(struct msm_vidc_core *core)
 
 	/* allocate 4k buffer for HFI_MMAP_ADDR */
 	memset(&mem, 0, sizeof(mem));
-	mem.type = MSM_VIDC_BUF_QUEUE;
+	mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE;
 	mem.region = MSM_VIDC_NON_SECURE;
 	mem.size = ALIGNED_MMAP_BUF_SIZE;
 	mem.secure = false;