From 10794c2968a2d6d91575702087245afb72d16f28 Mon Sep 17 00:00:00 2001 From: Darshana Patil Date: Thu, 2 Jun 2022 10:42:56 -0700 Subject: [PATCH] video: driver: initial state machine changes - hierarchical state model which comprises of top level states and sub states - top level states include OPEN, CLOSE, ERROR, INPUT_STREAMING, OUTPUT_STREAMING, STREAMING. - sub states include DRAIN, DRC, DRAIN_LAST_BUFFER, DRC_LAST_BUFFER, INPUT_PAUSE, OUTPUT_PAUSE. - follows deterministic approach for key sequences like DRC, DRAIN and last flag handling i.e none of these events are ignored or discarded. - removal of auto start of firmware input port as part of ipsc handling. - introduction of hfi commands for host controlled PAUSE and RESUME of firmware ports. - introduction of information last flag packets for DRC and DRAIN when FW has insufficient output buffers. Change-Id: Ie8c8f44af464d06f5a7bb76822f749c9874f869a Signed-off-by: Darshana Patil --- driver/platform/kalama/src/msm_vidc_kalama.c | 5 + driver/vidc/inc/hfi_command.h | 8 +- driver/vidc/inc/hfi_property.h | 4 + driver/vidc/inc/msm_media_info.h | 2 +- driver/vidc/inc/msm_vidc_driver.h | 40 +- driver/vidc/inc/msm_vidc_inst.h | 43 +- driver/vidc/inc/msm_vidc_internal.h | 14 +- driver/vidc/inc/venus_hfi.h | 4 + driver/vidc/inc/venus_hfi_response.h | 5 - driver/vidc/src/msm_vdec.c | 79 +- driver/vidc/src/msm_venc.c | 29 +- driver/vidc/src/msm_vidc.c | 11 +- driver/vidc/src/msm_vidc_driver.c | 877 ++++++++++-------- driver/vidc/src/msm_vidc_vb2.c | 16 +- driver/vidc/src/venus_hfi.c | 131 +++ driver/vidc/src/venus_hfi_response.c | 420 ++++----- .../uapi/vidc/media/v4l2_vidc_extensions.h | 16 + 17 files changed, 966 insertions(+), 738 deletions(-) diff --git a/driver/platform/kalama/src/msm_vidc_kalama.c b/driver/platform/kalama/src/msm_vidc_kalama.c index 693b0be4c2..c4dbd9d5d3 100644 --- a/driver/platform/kalama/src/msm_vidc_kalama.c +++ b/driver/platform/kalama/src/msm_vidc_kalama.c @@ -1455,6 +1455,11 @@ static struct msm_platform_inst_capability instance_cap_data_kalama[] = { HFI_PROP_AV1_DRAP_CONFIG, CAP_FLAG_INPUT_PORT}, + {LAST_FLAG_EVENT_ENABLE, DEC, CODECS_ALL, + V4L2_MPEG_MSM_VIDC_DISABLE, V4L2_MPEG_MSM_VIDC_ENABLE, + 1, V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDC_LAST_FLAG_EVENT_ENABLE}, + {META_BITSTREAM_RESOLUTION, DEC, AV1, V4L2_MPEG_VIDC_META_DISABLE, V4L2_MPEG_VIDC_META_ENABLE | V4L2_MPEG_VIDC_META_RX_INPUT | diff --git a/driver/vidc/inc/hfi_command.h b/driver/vidc/inc/hfi_command.h index c037e34595..33f9eb391e 100644 --- a/driver/vidc/inc/hfi_command.h +++ b/driver/vidc/inc/hfi_command.h @@ -116,6 +116,7 @@ enum hfi_buffer_firmware_flags { HFI_BUF_FW_FLAG_READONLY = 0x00000010, HFI_BUF_FW_FLAG_CODEC_CONFIG = 0x00000100, HFI_BUF_FW_FLAG_LAST = 0x10000000, + HFI_BUF_FW_FLAG_PSC_LAST = 0x20000000, }; enum hfi_metapayload_header_flags { @@ -165,22 +166,23 @@ enum hfi_reserve_type { #define HFI_CMD_DELIVERY_MODE 0x0100000A #define HFI_CMD_SUBSCRIBE_MODE 0x0100000B #define HFI_CMD_SETTINGS_CHANGE 0x0100000C -#define HFI_CMD_RESERVE 0x0100000F #define HFI_SSR_TYPE_SW_ERR_FATAL 0x1 #define HFI_SSR_TYPE_SW_DIV_BY_ZERO 0x2 #define HFI_SSR_TYPE_CPU_WDOG_IRQ 0x3 #define HFI_SSR_TYPE_NOC_ERROR 0x4 - #define HFI_BITMASK_HW_CLIENT_ID 0x000000f0 #define HFI_BITMASK_SSR_TYPE 0x0000000f #define HFI_CMD_SSR 0x0100000D #define HFI_STABILITY_TYPE_VCODEC_HUNG 0x1 #define HFI_STABILITY_TYPE_ENC_BUFFER_FULL 0x2 -#define HFI_BITMASK_STABILITY_TYPE 0x0000000f +#define HFI_BITMASK_STABILITY_TYPE 0x0000000f #define HFI_CMD_STABILITY 0x0100000E +#define HFI_CMD_RESERVE 0x0100000F +#define HFI_CMD_FLUSH 0x01000010 +#define HFI_CMD_PAUSE 0x01000011 #define HFI_CMD_END 0x01FFFFFF #endif //__H_HFI_COMMAND_H__ diff --git a/driver/vidc/inc/hfi_property.h b/driver/vidc/inc/hfi_property.h index 0899ecf799..2661837ff4 100644 --- a/driver/vidc/inc/hfi_property.h +++ b/driver/vidc/inc/hfi_property.h @@ -607,6 +607,10 @@ enum hfi_saliency_type { #define HFI_INFO_VCODEC_RESET 0x06000005 +#define HFI_INFO_HFI_FLAG_DRAIN_LAST 0x06000006 + +#define HFI_INFO_HFI_FLAG_PSC_LAST 0x06000007 + #define HFI_INFORMATION_END 0x06FFFFFF #endif //__H_HFI_PROPERTY_H__ diff --git a/driver/vidc/inc/msm_media_info.h b/driver/vidc/inc/msm_media_info.h index 3443c8aa89..a1b1c95e9b 100644 --- a/driver/vidc/inc/msm_media_info.h +++ b/driver/vidc/inc/msm_media_info.h @@ -520,7 +520,6 @@ static inline unsigned int VIDEO_RAW_BUFFER_SIZE(unsigned int v4l2_fmt, uv_meta_scanlines, 4096); size = (y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane); - size = MSM_MEDIA_ALIGN(size, 4096); } else { if (pix_width <= INTERLACE_WIDTH_MAX && pix_height <= INTERLACE_HEIGHT_MAX && @@ -597,6 +596,7 @@ static inline unsigned int VIDEO_RAW_BUFFER_SIZE(unsigned int v4l2_fmt, } invalid_input: + size = MSM_MEDIA_ALIGN(size, 4096); return size; } diff --git a/driver/vidc/inc/msm_vidc_driver.h b/driver/vidc/inc/msm_vidc_driver.h index 998b390ad2..1edf31fc43 100644 --- a/driver/vidc/inc/msm_vidc_driver.h +++ b/driver/vidc/inc/msm_vidc_driver.h @@ -352,6 +352,17 @@ static inline bool is_enc_slice_delivery_mode(struct msm_vidc_inst *inst) V4L2_MPEG_VIDC_HEVC_ENCODE_DELIVERY_MODE_SLICE_BASED))); } +static inline bool is_state(struct msm_vidc_inst *inst, enum msm_vidc_state state) +{ + return inst->state == state; +} + +static inline bool is_sub_state(struct msm_vidc_inst *inst, + enum msm_vidc_sub_state sub_state) +{ + return (inst->sub_state & sub_state); +} + const char *cap_name(enum msm_vidc_inst_capability_type cap_id); const char *v4l2_pixelfmt_name(u32 pixelfmt); const char *v4l2_type_name(u32 port); @@ -382,10 +393,13 @@ u32 v4l2_matrix_coeff_from_driver(struct msm_vidc_inst *inst, int v4l2_type_to_driver_port(struct msm_vidc_inst *inst, u32 type, const char *func); const char *allow_name(enum msm_vidc_allow allow); -const char *state_name(enum msm_vidc_inst_state state); +const char *state_name(enum msm_vidc_state state); const char *core_state_name(enum msm_vidc_core_state state); -int msm_vidc_change_inst_state(struct msm_vidc_inst *inst, - enum msm_vidc_inst_state request_state, const char *func); +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); 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, @@ -406,8 +420,6 @@ int msm_vidc_session_open(struct msm_vidc_inst *inst); int msm_vidc_session_set_codec(struct msm_vidc_inst *inst); int msm_vidc_session_set_secure_mode(struct msm_vidc_inst *inst); int msm_vidc_session_set_default_header(struct msm_vidc_inst *inst); -int msm_vidc_session_streamon(struct msm_vidc_inst *inst, - enum msm_vidc_port_type port); int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); int msm_vidc_session_close(struct msm_vidc_inst *inst); @@ -502,13 +514,21 @@ 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_last_flag(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); int msm_vidc_state_change_streamon(struct msm_vidc_inst *inst, u32 type); int msm_vidc_state_change_streamoff(struct msm_vidc_inst *inst, u32 type); -int msm_vidc_state_change_stop(struct msm_vidc_inst *inst); -int msm_vidc_state_change_start(struct msm_vidc_inst *inst); int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst); -int msm_vidc_state_change_last_flag(struct msm_vidc_inst *inst); +int msm_vidc_state_change_drain_last_flag(struct msm_vidc_inst *inst); +int msm_vidc_state_change_psc_last_flag(struct msm_vidc_inst *inst); +int msm_vidc_process_drain(struct msm_vidc_inst *inst); +int msm_vidc_process_resume(struct msm_vidc_inst *inst); +int msm_vidc_process_streamon(struct msm_vidc_inst *inst, u32 type); +int msm_vidc_process_stop_done(struct msm_vidc_inst *inst, + enum signal_session_response signal_type); +int msm_vidc_process_drain_done(struct msm_vidc_inst *inst); +int msm_vidc_process_drain_last_flag(struct msm_vidc_inst *inst); +int msm_vidc_process_psc_last_flag(struct msm_vidc_inst *inst); int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst); u32 msm_vidc_get_max_bitrate(struct msm_vidc_inst* inst); int msm_vidc_get_fps(struct msm_vidc_inst *inst); @@ -557,6 +577,8 @@ bool res_is_less_than(u32 width, u32 height, u32 ref_width, u32 ref_height); bool res_is_less_than_or_equal_to(u32 width, u32 height, u32 ref_width, u32 ref_height); +int signal_session_msg_receipt(struct msm_vidc_inst *inst, + enum signal_session_response cmd); int msm_vidc_get_properties(struct msm_vidc_inst *inst); int msm_vidc_create_input_metadata_buffer(struct msm_vidc_inst *inst, int buf_fd); int msm_vidc_update_input_meta_buffer_index(struct msm_vidc_inst *inst, struct vb2_buffer *vb2); diff --git a/driver/vidc/inc/msm_vidc_inst.h b/driver/vidc/inc/msm_vidc_inst.h index cac6126da0..954e519762 100644 --- a/driver/vidc/inc/msm_vidc_inst.h +++ b/driver/vidc/inc/msm_vidc_inst.h @@ -75,19 +75,30 @@ struct msm_vidc_buffers_info { struct msm_vidc_buffers partial_data; }; -enum msm_vidc_inst_state { +enum msm_vidc_state { MSM_VIDC_OPEN = 1, - MSM_VIDC_START_INPUT = 2, - MSM_VIDC_START_OUTPUT = 3, - MSM_VIDC_START = 4, - MSM_VIDC_DRC = 5, - MSM_VIDC_DRC_LAST_FLAG = 6, - MSM_VIDC_DRAIN = 7, - MSM_VIDC_DRAIN_LAST_FLAG = 8, - MSM_VIDC_DRC_DRAIN = 9, - MSM_VIDC_DRC_DRAIN_LAST_FLAG = 10, - MSM_VIDC_DRAIN_START_INPUT = 11, - MSM_VIDC_ERROR = 12, + MSM_VIDC_INPUT_STREAMING = 2, + MSM_VIDC_OUTPUT_STREAMING = 3, + MSM_VIDC_STREAMING = 4, + MSM_VIDC_CLOSE = 5, + MSM_VIDC_ERROR = 6, +}; + +#define MSM_VIDC_SUB_STATE_NONE 0 +#define MSM_VIDC_MAX_SUB_STATES 6 +/* + * max value of inst->sub_state if all + * the 6 valid bits are set i.e 111111==>63 + */ +#define MSM_VIDC_MAX_SUB_STATE_VALUE ((1 << MSM_VIDC_MAX_SUB_STATES) - 1) + +enum msm_vidc_sub_state { + MSM_VIDC_DRAIN = BIT(0), + MSM_VIDC_DRC = BIT(1), + MSM_VIDC_DRAIN_LAST_BUFFER = BIT(2), + MSM_VIDC_DRC_LAST_BUFFER = BIT(3), + MSM_VIDC_INPUT_PAUSE = BIT(4), + MSM_VIDC_OUTPUT_PAUSE = BIT(5), }; struct buf_queue { @@ -99,7 +110,9 @@ struct msm_vidc_inst { struct mutex lock; struct mutex request_lock; struct mutex client_lock; - enum msm_vidc_inst_state state; + enum msm_vidc_state state; + enum msm_vidc_sub_state sub_state; + char sub_state_name[MAX_NAME_LENGTH]; enum msm_vidc_domain_type domain; enum msm_vidc_codec_type codec; void *core; @@ -138,12 +151,10 @@ struct msm_vidc_inst { struct msm_vidc_decode_batch decode_batch; struct msm_vidc_decode_vpp_delay decode_vpp_delay; struct msm_vidc_session_idle session_idle; - struct delayed_work response_work; struct delayed_work stats_work; struct work_struct stability_work; struct msm_vidc_stability stability; - struct workqueue_struct *response_workq; - struct list_head response_works; /* list of struct response_work */ + struct workqueue_struct *workq; struct list_head enc_input_crs; struct list_head dmabuf_tracker; /* list of struct msm_memory_dmabuf */ struct list_head input_timer_list; /* list of struct msm_vidc_input_timer */ diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index 4eacba6c0d..54843ba6f0 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -500,6 +500,7 @@ enum msm_vidc_inst_capability_type { CAVLC_MAX_BITRATE, ALLINTRA_MAX_BITRATE, LOWLATENCY_MAX_BITRATE, + LAST_FLAG_EVENT_ENABLE, /* place all root(no parent) enums before this line */ PROFILE, @@ -940,19 +941,6 @@ enum msm_vidc_allow { MSM_VIDC_IGNORE, }; -enum response_work_type { - RESP_WORK_INPUT_PSC = 1, - RESP_WORK_OUTPUT_PSC, - RESP_WORK_LAST_FLAG, -}; - -struct response_work { - struct list_head list; - enum response_work_type type; - void *data; - u32 data_size; -}; - struct msm_vidc_ssr { bool trigger; enum msm_vidc_ssr_trigger_type ssr_type; diff --git a/driver/vidc/inc/venus_hfi.h b/driver/vidc/inc/venus_hfi.h index ba41ad24dc..7c60d9235b 100644 --- a/driver/vidc/inc/venus_hfi.h +++ b/driver/vidc/inc/venus_hfi.h @@ -49,6 +49,10 @@ int venus_hfi_start(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); int venus_hfi_stop(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); int venus_hfi_session_close(struct msm_vidc_inst *inst); int venus_hfi_session_open(struct msm_vidc_inst *inst); +int venus_hfi_session_pause(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); +int venus_hfi_session_resume(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port, u32 payload); +int venus_hfi_session_drain(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); int venus_hfi_session_set_codec(struct msm_vidc_inst *inst); int venus_hfi_session_set_secure_mode(struct msm_vidc_inst *inst); int venus_hfi_core_init(struct msm_vidc_core *core); diff --git a/driver/vidc/inc/venus_hfi_response.h b/driver/vidc/inc/venus_hfi_response.h index 83e05dd9a9..ebd19e9d68 100644 --- a/driver/vidc/inc/venus_hfi_response.h +++ b/driver/vidc/inc/venus_hfi_response.h @@ -16,11 +16,6 @@ bool is_valid_port(struct msm_vidc_inst *inst, u32 port, const char *func); bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst, u32 buffer_type, const char *func); -void handle_session_response_work_handler(struct work_struct *work); -int handle_session_response_work(struct msm_vidc_inst *inst, - struct response_work *work); -int cancel_response_work(struct msm_vidc_inst *inst); -int cancel_response_work_sync(struct msm_vidc_inst *inst); int handle_system_error(struct msm_vidc_core *core, struct hfi_packet *pkt); void fw_coredump(struct msm_vidc_core *core); diff --git a/driver/vidc/src/msm_vdec.c b/driver/vidc/src/msm_vdec.c index 4663b9bee0..ca781c754c 100644 --- a/driver/vidc/src/msm_vdec.c +++ b/driver/vidc/src/msm_vdec.c @@ -1160,24 +1160,6 @@ static int msm_vdec_set_delivery_mode_property(struct msm_vidc_inst *inst, return rc; } -static int msm_vdec_session_resume(struct msm_vidc_inst *inst, - enum msm_vidc_port_type port) -{ - int rc = 0; - - i_vpr_h(inst, "%s()\n", __func__); - rc = venus_hfi_session_command(inst, - HFI_CMD_RESUME, - port, - HFI_PAYLOAD_NONE, - NULL, - 0); - if (rc) - return rc; - - return rc; -} - int msm_vdec_init_input_subcr_params(struct msm_vidc_inst *inst) { struct msm_vidc_subscription_params *subsc_params; @@ -1330,7 +1312,7 @@ static int msm_vdec_read_input_subcr_params(struct msm_vidc_inst *inst) if (inst->buffers.output.min_count != 1) { i_vpr_e(inst, "%s: invalid min count %d in thumbnail case\n", __func__, inst->buffers.output.min_count); - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); } } inst->crop.top = subsc_params.crop_offsets[0] & 0xFFFF; @@ -1413,16 +1395,11 @@ int msm_vdec_input_port_settings_change(struct msm_vidc_inst *inst) if (rc) return rc; - rc = msm_vdec_session_resume(inst, INPUT_PORT); - if (rc) - return rc; - return rc; } int msm_vdec_output_port_settings_change(struct msm_vidc_inst *inst) { - //todo return 0; } @@ -1496,23 +1473,23 @@ int msm_vdec_streamon_input(struct msm_vidc_inst *inst) rc = msm_vdec_subscribe_input_port_settings_change( inst, INPUT_PORT); if (rc) - return rc; + goto error; inst->ipsc_properties_set = true; } rc = msm_vdec_subscribe_property(inst, INPUT_PORT); if (rc) - return rc; + goto error; rc = msm_vdec_subscribe_metadata(inst, INPUT_PORT); if (rc) - return rc; + goto error; rc = msm_vdec_set_delivery_mode_metadata(inst, INPUT_PORT); if (rc) - return rc; + goto error; - rc = msm_vidc_session_streamon(inst, INPUT_PORT); + rc = msm_vidc_process_streamon(inst, INPUT_PORT); if (rc) goto error; @@ -1788,11 +1765,11 @@ int msm_vdec_streamon_output(struct msm_vidc_inst *inst) rc = msm_vidc_check_session_supported(inst); if (rc) - return rc; + goto error; rc = msm_vdec_update_max_map_output_count(inst); if (rc) - return rc; + goto error; rc = msm_vdec_set_output_properties(inst); if (rc) @@ -1800,8 +1777,8 @@ int msm_vdec_streamon_output(struct msm_vidc_inst *inst) if (!inst->opsc_properties_set) { memcpy(&inst->subcr_params[OUTPUT_PORT], - &inst->subcr_params[INPUT_PORT], - sizeof(inst->subcr_params[INPUT_PORT])); + &inst->subcr_params[INPUT_PORT], + sizeof(inst->subcr_params[INPUT_PORT])); rc = msm_vdec_subscribe_output_port_settings_change(inst, OUTPUT_PORT); if (rc) goto error; @@ -1810,7 +1787,7 @@ int msm_vdec_streamon_output(struct msm_vidc_inst *inst) rc = msm_vdec_subscribe_property(inst, OUTPUT_PORT); if (rc) - return rc; + goto error; rc = msm_vdec_subscribe_metadata(inst, OUTPUT_PORT); if (rc) @@ -1818,11 +1795,11 @@ int msm_vdec_streamon_output(struct msm_vidc_inst *inst) rc = msm_vdec_set_delivery_mode_property(inst, OUTPUT_PORT); if (rc) - return rc; + goto error; rc = msm_vdec_set_delivery_mode_metadata(inst, OUTPUT_PORT); if (rc) - return rc; + goto error; rc = msm_vdec_get_output_internal_buffers(inst); if (rc) @@ -1832,7 +1809,7 @@ int msm_vdec_streamon_output(struct msm_vidc_inst *inst) if (rc) goto error; - rc = msm_vidc_session_streamon(inst, OUTPUT_PORT); + rc = msm_vidc_process_streamon(inst, OUTPUT_PORT); if (rc) goto error; @@ -1862,10 +1839,6 @@ static inline enum msm_vidc_allow msm_vdec_allow_queue_deferred_buffers( if (inst->power.buffer_counter <= SKIP_BATCH_WINDOW) return MSM_VIDC_ALLOW; - /* do not defer, if client waiting for last flag FBD */ - if (inst->state != MSM_VIDC_START) - return MSM_VIDC_ALLOW; - /* defer qbuf, if pending buffers count less than batch size */ count = msm_vidc_num_buffers(inst, MSM_VIDC_BUF_OUTPUT, MSM_VIDC_ATTR_DEFERRED); if (count < inst->decode_batch.size) @@ -2192,7 +2165,6 @@ int msm_vdec_process_cmd(struct msm_vidc_inst *inst, u32 cmd) { int rc = 0; enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; - enum msm_vidc_port_type port; struct msm_vidc_inst_capability *capability; if (!inst || !inst->core || !inst->capabilities) { @@ -2210,15 +2182,7 @@ int msm_vdec_process_cmd(struct msm_vidc_inst *inst, u32 cmd) return 0; else if (allow != MSM_VIDC_ALLOW) return -EINVAL; - rc = venus_hfi_session_command(inst, - HFI_CMD_DRAIN, - INPUT_PORT, - HFI_PAYLOAD_NONE, - NULL, - 0); - if (rc) - return rc; - rc = msm_vidc_state_change_stop(inst); + rc = msm_vidc_process_drain(inst); if (rc) return rc; } else if (cmd == V4L2_DEC_CMD_START) { @@ -2236,11 +2200,6 @@ int msm_vdec_process_cmd(struct msm_vidc_inst *inst, u32 cmd) if (!msm_vidc_allow_start(inst)) return -EBUSY; - port = (inst->state == MSM_VIDC_DRAIN_LAST_FLAG) ? INPUT_PORT : OUTPUT_PORT; - - rc = msm_vidc_state_change_start(inst); - if (rc) - return rc; /* tune power features */ inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst); @@ -2252,10 +2211,15 @@ int msm_vdec_process_cmd(struct msm_vidc_inst *inst, u32 cmd) 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_vdec_session_resume(inst, port); + rc = msm_vidc_process_resume(inst); if (rc) return rc; @@ -2592,6 +2556,7 @@ int msm_vdec_subscribe_event(struct msm_vidc_inst *inst, switch (sub->type) { case V4L2_EVENT_EOS: case V4L2_EVENT_VIDC_METADATA: + case V4L2_EVENT_VIDC_LAST_FLAG: rc = v4l2_event_subscribe(&inst->event_handler, sub, MAX_EVENTS, NULL); break; case V4L2_EVENT_SOURCE_CHANGE: diff --git a/driver/vidc/src/msm_venc.c b/driver/vidc/src/msm_venc.c index 5eea5f42e3..9976a86c2f 100644 --- a/driver/vidc/src/msm_venc.c +++ b/driver/vidc/src/msm_venc.c @@ -857,13 +857,13 @@ int msm_venc_streamon_input(struct msm_vidc_inst *inst) rc = msm_venc_property_subscription(inst, INPUT_PORT); if (rc) - return rc; + goto error; rc = msm_venc_metadata_delivery(inst, INPUT_PORT); if (rc) - return rc; + goto error; - rc = msm_vidc_session_streamon(inst, INPUT_PORT); + rc = msm_vidc_process_streamon(inst, INPUT_PORT); if (rc) goto error; @@ -910,15 +910,7 @@ int msm_venc_process_cmd(struct msm_vidc_inst *inst, u32 cmd) return 0; else if (allow != MSM_VIDC_ALLOW) return -EINVAL; - rc = venus_hfi_session_command(inst, - HFI_CMD_DRAIN, - INPUT_PORT, - HFI_PAYLOAD_NONE, - NULL, - 0); - if (rc) - return rc; - rc = msm_vidc_state_change_stop(inst); + rc = msm_vidc_process_drain(inst); if (rc) return rc; } else if (cmd == V4L2_ENC_CMD_START) { @@ -928,10 +920,6 @@ int msm_venc_process_cmd(struct msm_vidc_inst *inst, u32 cmd) vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q); vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q); - rc = msm_vidc_state_change_start(inst); - if (rc) - return rc; - /* tune power features */ msm_vidc_allow_dcvs(inst); msm_vidc_power_data_reset(inst); @@ -939,12 +927,7 @@ int msm_venc_process_cmd(struct msm_vidc_inst *inst, u32 cmd) /* print final buffer counts & size details */ msm_vidc_print_buffer_info(inst); - rc = venus_hfi_session_command(inst, - HFI_CMD_RESUME, - INPUT_PORT, - HFI_PAYLOAD_NONE, - NULL, - 0); + rc = msm_vidc_process_resume(inst); if (rc) return rc; } else { @@ -1030,7 +1013,7 @@ int msm_venc_streamon_output(struct msm_vidc_inst *inst) if (rc) goto error; - rc = msm_vidc_session_streamon(inst, OUTPUT_PORT); + rc = msm_vidc_process_streamon(inst, OUTPUT_PORT); if (rc) goto error; diff --git a/driver/vidc/src/msm_vidc.c b/driver/vidc/src/msm_vidc.c index 76c6836bcf..b61803b89b 100644 --- a/driver/vidc/src/msm_vidc.c +++ b/driver/vidc/src/msm_vidc.c @@ -889,6 +889,8 @@ void *msm_vidc_open(void *vidc_core, u32 session_type) inst->domain = session_type; inst->session_id = hash32_ptr(inst); inst->state = MSM_VIDC_OPEN; + inst->sub_state = MSM_VIDC_SUB_STATE_NONE; + strlcpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name)); inst->active = true; inst->request = false; inst->ipsc_properties_set = false; @@ -908,7 +910,6 @@ void *msm_vidc_open(void *vidc_core, u32 session_type) msm_vidc_vmem_free((void **)&inst); return NULL; } - INIT_LIST_HEAD(&inst->response_works); INIT_LIST_HEAD(&inst->caps_list); INIT_LIST_HEAD(&inst->timestamps.list); INIT_LIST_HEAD(&inst->ts_reorder.list); @@ -959,13 +960,12 @@ void *msm_vidc_open(void *vidc_core, u32 session_type) for (i = 0; i < MAX_SIGNAL; i++) init_completion(&inst->completions[i]); - inst->response_workq = create_singlethread_workqueue("response_workq"); - if (!inst->response_workq) { - i_vpr_e(inst, "%s: create input_psc_workq failed\n", __func__); + inst->workq = create_singlethread_workqueue("workq"); + if (!inst->workq) { + i_vpr_e(inst, "%s: create workq failed\n", __func__); goto error; } - INIT_DELAYED_WORK(&inst->response_work, handle_session_response_work_handler); INIT_DELAYED_WORK(&inst->stats_work, msm_vidc_stats_handler); INIT_WORK(&inst->stability_work, msm_vidc_stability_handler); @@ -1042,7 +1042,6 @@ int msm_vidc_close(void *instance) msm_vidc_destroy_buffers(inst); inst_unlock(inst, __func__); client_unlock(inst, __func__); - cancel_response_work_sync(inst); cancel_stability_work_sync(inst); cancel_stats_work_sync(inst); msm_vidc_show_stats(inst); diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index df9dbd3a5c..f8ae6134af 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -195,6 +195,7 @@ static const struct msm_vidc_cap_name cap_name_arr[] = { {CAVLC_MAX_BITRATE, "CAVLC_MAX_BITRATE" }, {ALLINTRA_MAX_BITRATE, "ALLINTRA_MAX_BITRATE" }, {LOWLATENCY_MAX_BITRATE, "LOWLATENCY_MAX_BITRATE" }, + {LAST_FLAG_EVENT_ENABLE, "LAST_FLAG_EVENT_ENABLE" }, {PROFILE, "PROFILE" }, {ENH_LAYER_COUNT, "ENH_LAYER_COUNT" }, {BIT_RATE, "BIT_RATE" }, @@ -314,43 +315,51 @@ exit: return name; } -struct msm_vidc_inst_state_name { - enum msm_vidc_inst_state state; +struct msm_vidc_state_name { + enum msm_vidc_state state; char *name; }; /* do not modify the state names as it is used in test scripts */ -static const struct msm_vidc_inst_state_name inst_state_name_arr[] = { - {MSM_VIDC_OPEN, "OPEN" }, - {MSM_VIDC_START_INPUT, "START_INPUT" }, - {MSM_VIDC_START_OUTPUT, "START_OUTPUT" }, - {MSM_VIDC_START, "START" }, - {MSM_VIDC_DRC, "DRC" }, - {MSM_VIDC_DRC_LAST_FLAG, "DRC_LAST_FLAG" }, - {MSM_VIDC_DRAIN, "DRAIN" }, - {MSM_VIDC_DRAIN_LAST_FLAG, "DRAIN_LAST_FLAG" }, - {MSM_VIDC_DRC_DRAIN, "DRC_DRAIN" }, - {MSM_VIDC_DRC_DRAIN_LAST_FLAG, "DRC_DRAIN_LAST_FLAG" }, - {MSM_VIDC_DRAIN_START_INPUT, "DRAIN_START_INPUT" }, - {MSM_VIDC_ERROR, "ERROR" }, +static const struct msm_vidc_state_name state_name_arr[] = { + {MSM_VIDC_OPEN, "OPEN" }, + {MSM_VIDC_INPUT_STREAMING, "INPUT_STREAMING" }, + {MSM_VIDC_OUTPUT_STREAMING, "OUTPUT_STREAMING" }, + {MSM_VIDC_STREAMING, "STREAMING" }, + {MSM_VIDC_CLOSE, "CLOSE" }, + {MSM_VIDC_ERROR, "ERROR" }, }; -const char *state_name(enum msm_vidc_inst_state state) +const char *state_name(enum msm_vidc_state state) { const char *name = "UNKNOWN STATE"; - if (!state || state > ARRAY_SIZE(inst_state_name_arr)) + if (!state || state > ARRAY_SIZE(state_name_arr)) goto exit; - if (inst_state_name_arr[state - 1].state != state) + if (state_name_arr[state - 1].state != state) goto exit; - name = inst_state_name_arr[state - 1].name; + name = state_name_arr[state - 1].name; exit: return name; } +const char *sub_state_name(enum msm_vidc_sub_state sub_state) +{ + switch (sub_state) { + case MSM_VIDC_DRAIN: return "DRAIN "; + case MSM_VIDC_DRC: return "DRC "; + case MSM_VIDC_DRAIN_LAST_BUFFER: return "DRAIN_LAST_BUFFER "; + case MSM_VIDC_DRC_LAST_BUFFER: return "DRC_LAST_BUFFER "; + case MSM_VIDC_INPUT_PAUSE: return "INPUT_PAUSE "; + case MSM_VIDC_OUTPUT_PAUSE: return "OUTPUT_PAUSE "; + } + + return "SUB_STATE_NONE"; +} + struct msm_vidc_core_state_name { enum msm_vidc_core_state state; char *name; @@ -1228,6 +1237,14 @@ bool res_is_less_than_or_equal_to(u32 width, u32 height, return false; } +int signal_session_msg_receipt(struct msm_vidc_inst *inst, + enum signal_session_response cmd) +{ + if (cmd < MAX_SIGNAL) + complete(&inst->completions[cmd]); + return 0; +} + int msm_vidc_change_core_state(struct msm_vidc_core *core, enum msm_vidc_core_state request_state, const char *func) { @@ -1243,8 +1260,8 @@ int msm_vidc_change_core_state(struct msm_vidc_core *core, return 0; } -int msm_vidc_change_inst_state(struct msm_vidc_inst *inst, - enum msm_vidc_inst_state request_state, const char *func) +int msm_vidc_change_state(struct msm_vidc_inst *inst, + enum msm_vidc_state request_state, const char *func) { if (!inst) { d_vpr_e("%s: invalid params\n", __func__); @@ -1278,6 +1295,58 @@ int msm_vidc_change_inst_state(struct msm_vidc_inst *inst, return 0; } +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; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (is_session_error(inst)) { + i_vpr_h(inst, + "%s: inst is in bad state, can not change sub state\n", func); + return 0; + } + + if (!clear_sub_state && !set_sub_state) + return 0; + + if ((clear_sub_state & set_sub_state) || + (set_sub_state > MSM_VIDC_MAX_SUB_STATE_VALUE) || + (clear_sub_state > MSM_VIDC_MAX_SUB_STATE_VALUE)) { + i_vpr_e(inst, "%s: invalid sub states to clear %#x or set %#x\n", + func, clear_sub_state, set_sub_state); + return -EINVAL; + } + + prev_sub_state = inst->sub_state; + inst->sub_state |= set_sub_state; + inst->sub_state &= ~clear_sub_state; + + /* 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); + } + + return 0; +} + bool msm_vidc_allow_s_fmt(struct msm_vidc_inst *inst, u32 type) { bool allow = false; @@ -1286,19 +1355,18 @@ bool msm_vidc_allow_s_fmt(struct msm_vidc_inst *inst, u32 type) d_vpr_e("%s: invalid params\n", __func__); return false; } - if (inst->state == MSM_VIDC_OPEN) { + if (is_state(inst, MSM_VIDC_OPEN)) { allow = true; goto exit; } if (type == OUTPUT_MPLANE || type == OUTPUT_META_PLANE) { - if (inst->state == MSM_VIDC_START_INPUT || - inst->state == MSM_VIDC_DRAIN_START_INPUT) { + if (is_state(inst, MSM_VIDC_INPUT_STREAMING)) { allow = true; goto exit; } } if (type == INPUT_MPLANE || type == INPUT_META_PLANE) { - if (inst->state == MSM_VIDC_START_OUTPUT) { + if (is_state(inst, MSM_VIDC_OUTPUT_STREAMING)) { allow = true; goto exit; } @@ -1319,7 +1387,7 @@ bool msm_vidc_allow_s_ctrl(struct msm_vidc_inst *inst, u32 id) d_vpr_e("%s: invalid params\n", __func__); return false; } - if (inst->state == MSM_VIDC_OPEN) { + if (is_state(inst, MSM_VIDC_OPEN)) { allow = true; goto exit; } @@ -1535,19 +1603,18 @@ bool msm_vidc_allow_reqbufs(struct msm_vidc_inst *inst, u32 type) d_vpr_e("%s: invalid params\n", __func__); return false; } - if (inst->state == MSM_VIDC_OPEN) { + if (is_state(inst, MSM_VIDC_OPEN)) { allow = true; goto exit; } if (type == OUTPUT_MPLANE || type == OUTPUT_META_PLANE) { - if (inst->state == MSM_VIDC_START_INPUT || - inst->state == MSM_VIDC_DRAIN_START_INPUT) { + if (is_state(inst, MSM_VIDC_INPUT_STREAMING)) { allow = true; goto exit; } } if (type == INPUT_MPLANE || type == INPUT_META_PLANE) { - if (inst->state == MSM_VIDC_START_OUTPUT) { + if (is_state(inst, MSM_VIDC_OUTPUT_STREAMING)) { allow = true; goto exit; } @@ -1568,19 +1635,20 @@ enum msm_vidc_allow msm_vidc_allow_stop(struct msm_vidc_inst *inst) d_vpr_e("%s: invalid params\n", __func__); return allow; } - if (inst->state == MSM_VIDC_START || - inst->state == MSM_VIDC_DRC || - inst->state == MSM_VIDC_DRC_LAST_FLAG || - inst->state == MSM_VIDC_DRC_DRAIN) { - allow = MSM_VIDC_ALLOW; - } else if (inst->state == MSM_VIDC_START_INPUT || - inst->state == MSM_VIDC_OPEN) { + + /* allow stop (drain) if input port is streaming */ + if (is_state(inst, MSM_VIDC_INPUT_STREAMING) || + is_state(inst, MSM_VIDC_STREAMING)) { + /* do not allow back to back drain */ + if (!(is_sub_state(inst, MSM_VIDC_DRAIN))) + allow = MSM_VIDC_ALLOW; + } else if (is_state(inst, MSM_VIDC_OPEN)) { allow = MSM_VIDC_IGNORE; - i_vpr_e(inst, "%s: stop ignored in state %s\n", - __func__, state_name(inst->state)); + i_vpr_e(inst, "%s: ignored in state %s, sub state %s\n", + __func__, state_name(inst->state), inst->sub_state_name); } else { - i_vpr_e(inst, "%s: stop not allowed in state %s\n", - __func__, state_name(inst->state)); + i_vpr_e(inst, "%s: not allowed in state %s, sub state %s\n", + __func__, state_name(inst->state), inst->sub_state_name); } return allow; @@ -1588,18 +1656,24 @@ enum msm_vidc_allow msm_vidc_allow_stop(struct msm_vidc_inst *inst) bool msm_vidc_allow_start(struct msm_vidc_inst *inst) { + bool allow = false; + if (!inst) { d_vpr_e("%s: invalid params\n", __func__); - return false; + return allow; } - if (inst->state == MSM_VIDC_DRAIN_LAST_FLAG || - inst->state == MSM_VIDC_DRC_LAST_FLAG || - inst->state == MSM_VIDC_DRC_DRAIN_LAST_FLAG) - return true; - i_vpr_e(inst, "%s: not allowed in state %s\n", - __func__, state_name(inst->state)); - return false; + /* client would call start (resume) to complete DRC/drain sequence */ + if ((is_sub_state(inst, MSM_VIDC_DRC) && + is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) || + (is_sub_state(inst, MSM_VIDC_DRAIN) && + is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER))) + allow = true; + + if (!allow) + i_vpr_e(inst, "%s: not allowed in state %s, sub state %s\n", + __func__, state_name(inst->state), inst->sub_state_name); + return allow; } bool msm_vidc_allow_streamon(struct msm_vidc_inst *inst, u32 type) @@ -1609,13 +1683,12 @@ bool msm_vidc_allow_streamon(struct msm_vidc_inst *inst, u32 type) return false; } if (type == INPUT_MPLANE || type == INPUT_META_PLANE) { - if (inst->state == MSM_VIDC_OPEN || - inst->state == MSM_VIDC_START_OUTPUT) + if (is_state(inst, MSM_VIDC_OPEN) || + is_state(inst, MSM_VIDC_OUTPUT_STREAMING)) return true; } else if (type == OUTPUT_MPLANE || type == OUTPUT_META_PLANE) { - if (inst->state == MSM_VIDC_OPEN || - inst->state == MSM_VIDC_START_INPUT || - inst->state == MSM_VIDC_DRAIN_START_INPUT) + if (is_state(inst, MSM_VIDC_OPEN) || + is_state(inst, MSM_VIDC_INPUT_STREAMING)) return true; } @@ -1678,15 +1751,14 @@ enum msm_vidc_allow msm_vidc_allow_qbuf(struct msm_vidc_inst *inst, u32 type) return MSM_VIDC_DEFER; if (type == INPUT_MPLANE) { - if (inst->state == MSM_VIDC_OPEN || - inst->state == MSM_VIDC_START_OUTPUT) + 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 (inst->state == MSM_VIDC_OPEN || - inst->state == MSM_VIDC_START_INPUT || - inst->state == MSM_VIDC_DRAIN_START_INPUT) + if (is_state(inst, MSM_VIDC_OPEN) || + is_state(inst, MSM_VIDC_INPUT_STREAMING)) return MSM_VIDC_DEFER; else return MSM_VIDC_ALLOW; @@ -1700,269 +1772,130 @@ 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) { - enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; + enum msm_vidc_allow allow = MSM_VIDC_ALLOW; if (!inst) { d_vpr_e("%s: invalid params\n", __func__); return MSM_VIDC_DISALLOW; } - if (inst->state == MSM_VIDC_START || - inst->state == MSM_VIDC_START_INPUT || - inst->state == MSM_VIDC_DRAIN) { - allow = MSM_VIDC_ALLOW; - } else if (inst->state == MSM_VIDC_DRC || - inst->state == MSM_VIDC_DRC_LAST_FLAG || - inst->state == MSM_VIDC_DRC_DRAIN || - inst->state == MSM_VIDC_DRC_DRAIN_LAST_FLAG || - inst->state == MSM_VIDC_DRAIN_START_INPUT) { - i_vpr_h(inst, "%s: defer input psc, inst state %s\n", - __func__, state_name(inst->state)); - allow = MSM_VIDC_DEFER; - } else if (inst->state == MSM_VIDC_OPEN || - inst->state == MSM_VIDC_START_OUTPUT) { - i_vpr_h(inst, "%s: discard input psc, inst state %s\n", - __func__, state_name(inst->state)); - allow = MSM_VIDC_DISCARD; - } else { - i_vpr_e(inst, "%s: input psc in wrong state %s\n", - __func__, state_name(inst->state)); - allow = MSM_VIDC_DISALLOW; + + /* + * if drc sequence is not completed by client, fw is not + * expected to raise another ipsc + */ + if (is_sub_state(inst, MSM_VIDC_DRC)) { + i_vpr_e(inst, "%s: not allowed in sub state %s\n", + __func__, inst->sub_state_name); + return MSM_VIDC_DISALLOW; } return allow; } -bool msm_vidc_allow_last_flag(struct msm_vidc_inst *inst) +bool msm_vidc_allow_drain_last_flag(struct msm_vidc_inst *inst) { if (!inst) { d_vpr_e("%s: invalid params\n", __func__); return false; } - if (inst->state == MSM_VIDC_DRC || - inst->state == MSM_VIDC_DRAIN || - inst->state == MSM_VIDC_DRC_DRAIN) + + /* + * drain last flag is expected only when DRAIN, INPUT_PAUSE + * is set and DRAIN_LAST_BUFFER is not set + */ + if (is_sub_state(inst, MSM_VIDC_DRAIN) && + is_sub_state(inst, MSM_VIDC_INPUT_PAUSE) && + !is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER)) return true; - i_vpr_e(inst, "%s: not allowed in state %s\n", - __func__, state_name(inst->state)); + i_vpr_e(inst, "%s: not allowed in sub state %s\n", + __func__, inst->sub_state_name); return false; } -static int msm_vidc_flush_pending_last_flag(struct msm_vidc_inst *inst) +bool msm_vidc_allow_psc_last_flag(struct msm_vidc_inst *inst) { - int rc = 0; - struct response_work *resp_work, *dummy = NULL; - if (!inst) { d_vpr_e("%s: invalid params\n", __func__); - return -EINVAL; + return false; } - if (list_empty(&inst->response_works)) - return 0; + /* + * drc last flag is expected only when DRC, INPUT_PAUSE + * is set and DRC_LAST_BUFFER is not set + */ + if (is_sub_state(inst, MSM_VIDC_DRC) && + is_sub_state(inst, MSM_VIDC_INPUT_PAUSE) && + !is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) + return true; - /* flush pending last flag buffers if any */ - list_for_each_entry_safe(resp_work, dummy, - &inst->response_works, list) { - if (resp_work->type == RESP_WORK_LAST_FLAG) { - i_vpr_h(inst, "%s: flush pending last flag buffer\n", - __func__); - rc = handle_session_response_work(inst, resp_work); - if (rc) { - msm_vidc_change_inst_state(inst, - MSM_VIDC_ERROR, __func__); - return rc; - } - list_del(&resp_work->list); - msm_vidc_vmem_free((void **)&resp_work->data); - msm_vidc_vmem_free((void **)&resp_work); - } - } + i_vpr_e(inst, "%s: not allowed in sub state %s\n", + __func__, inst->sub_state_name); - return 0; + return false; } -static int msm_vidc_discard_pending_opsc(struct msm_vidc_inst *inst) -{ - struct response_work *resp_work, *dummy = NULL; - - if (!inst) { - d_vpr_e("%s: invalid params\n", __func__); - return -EINVAL; - } - - if (list_empty(&inst->response_works)) - return 0; - - /* discard pending port settings change if any */ - list_for_each_entry_safe(resp_work, dummy, - &inst->response_works, list) { - if (resp_work->type == RESP_WORK_OUTPUT_PSC) { - i_vpr_h(inst, - "%s: discard pending output psc\n", __func__); - list_del(&resp_work->list); - msm_vidc_vmem_free((void **)&resp_work->data); - msm_vidc_vmem_free((void **)&resp_work); - } - } - - return 0; -} - -static int msm_vidc_discard_pending_ipsc(struct msm_vidc_inst *inst) -{ - struct response_work *resp_work, *dummy = NULL; - - if (!inst) { - d_vpr_e("%s: invalid params\n", __func__); - return -EINVAL; - } - - if (list_empty(&inst->response_works)) - return 0; - - /* discard pending port settings change if any */ - list_for_each_entry_safe(resp_work, dummy, - &inst->response_works, list) { - if (resp_work->type == RESP_WORK_INPUT_PSC) { - i_vpr_h(inst, - "%s: discard pending input psc\n", __func__); - - /* override the psc properties again if ipsc discarded */ - inst->ipsc_properties_set = false; - - list_del(&resp_work->list); - msm_vidc_vmem_free((void **)&resp_work->data); - msm_vidc_vmem_free((void **)&resp_work); - } - } - - return 0; -} - -static int msm_vidc_process_pending_ipsc(struct msm_vidc_inst *inst, - enum msm_vidc_inst_state *new_state) -{ - struct response_work *resp_work, *dummy = NULL; - int rc = 0; - - if (!inst || !new_state) { - d_vpr_e("%s: invalid params\n", __func__); - return -EINVAL; - } - - if (list_empty(&inst->response_works)) - return 0; - - i_vpr_h(inst, "%s: state %s, ipsc pending\n", __func__, state_name(inst->state)); - list_for_each_entry_safe(resp_work, dummy, &inst->response_works, list) { - if (resp_work->type == RESP_WORK_INPUT_PSC) { - rc = handle_session_response_work(inst, resp_work); - if (rc) { - i_vpr_e(inst, "%s: handle ipsc failed\n", __func__); - *new_state = MSM_VIDC_ERROR; - } else { - if (inst->state == MSM_VIDC_DRC_DRAIN_LAST_FLAG || - inst->state == MSM_VIDC_DRAIN_START_INPUT) { - *new_state = MSM_VIDC_DRC_DRAIN; - } else if (inst->state == MSM_VIDC_DRC_LAST_FLAG) { - *new_state = MSM_VIDC_DRC; - } - } - list_del(&resp_work->list); - msm_vidc_vmem_free((void **)&resp_work->data); - msm_vidc_vmem_free((void **)&resp_work); - /* list contains max only one ipsc at anytime */ - break; - } - } - - return rc; -} - -int msm_vidc_state_change_streamon(struct msm_vidc_inst *inst, u32 type) +int msm_vidc_state_change_streamon(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) { int rc = 0; - enum msm_vidc_inst_state new_state = MSM_VIDC_ERROR; + enum msm_vidc_state new_state = MSM_VIDC_ERROR; if (!inst || !inst->core) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } - if (type == INPUT_META_PLANE || type == OUTPUT_META_PLANE) + if (port == INPUT_META_PORT || port == OUTPUT_META_PORT) return 0; - if (type == INPUT_MPLANE) { - if (inst->state == MSM_VIDC_OPEN) - new_state = MSM_VIDC_START_INPUT; - else if (inst->state == MSM_VIDC_START_OUTPUT) - new_state = MSM_VIDC_START; - } else if (type == OUTPUT_MPLANE) { - if (inst->state == MSM_VIDC_OPEN) { - new_state = MSM_VIDC_START_OUTPUT; - } else if (inst->state == MSM_VIDC_START_INPUT) { - new_state = MSM_VIDC_START; - } else if (inst->state == MSM_VIDC_DRAIN_START_INPUT) { - i_vpr_h(inst, "%s: streamon(output) in %s state\n", - __func__, state_name(inst->state)); - new_state = MSM_VIDC_DRAIN; - rc = msm_vidc_process_pending_ipsc(inst, &new_state); - if (rc) { - i_vpr_e(inst, "%s: process pending ipsc failed\n", __func__); - goto state_change; - } - } + if (port == INPUT_PORT) { + if (is_state(inst, MSM_VIDC_OPEN)) + new_state = MSM_VIDC_INPUT_STREAMING; + else if (is_state(inst, MSM_VIDC_OUTPUT_STREAMING)) + new_state = MSM_VIDC_STREAMING; + } else if (port == OUTPUT_PORT) { + if (is_state(inst, MSM_VIDC_OPEN)) + new_state = MSM_VIDC_OUTPUT_STREAMING; + else if (is_state(inst, MSM_VIDC_INPUT_STREAMING)) + new_state = MSM_VIDC_STREAMING; } -state_change: - msm_vidc_change_inst_state(inst, new_state, __func__); + rc = msm_vidc_change_state(inst, new_state, __func__); + if (rc) + return rc; return rc; } -int msm_vidc_state_change_streamoff(struct msm_vidc_inst *inst, u32 type) +int msm_vidc_state_change_streamoff(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) { int rc = 0; - enum msm_vidc_inst_state new_state = MSM_VIDC_ERROR; + enum msm_vidc_state new_state = MSM_VIDC_ERROR; if (!inst || !inst->core) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } - if (type == INPUT_META_PLANE || type == OUTPUT_META_PLANE) + if (port == INPUT_META_PORT || port == OUTPUT_META_PORT) return 0; - if (type == INPUT_MPLANE) { - if (inst->state == MSM_VIDC_START_INPUT) { + if (port == INPUT_PORT) { + if (is_state(inst, MSM_VIDC_INPUT_STREAMING)) { new_state = MSM_VIDC_OPEN; - } else if (inst->state == MSM_VIDC_START) { - new_state = MSM_VIDC_START_OUTPUT; - } else if (inst->state == MSM_VIDC_DRC || - inst->state == MSM_VIDC_DRC_LAST_FLAG || - inst->state == MSM_VIDC_DRAIN || - inst->state == MSM_VIDC_DRAIN_LAST_FLAG || - inst->state == MSM_VIDC_DRC_DRAIN || - inst->state == MSM_VIDC_DRC_DRAIN_LAST_FLAG || - inst->state == MSM_VIDC_DRAIN_START_INPUT) { - new_state = MSM_VIDC_START_OUTPUT; + } else if (is_state(inst, MSM_VIDC_STREAMING)) { + new_state = MSM_VIDC_OUTPUT_STREAMING; } - } else if (type == OUTPUT_MPLANE) { - if (inst->state == MSM_VIDC_START_OUTPUT) { + } else if (port == OUTPUT_PORT) { + if (is_state(inst, MSM_VIDC_OUTPUT_STREAMING)) { new_state = MSM_VIDC_OPEN; - } else if (inst->state == MSM_VIDC_START || - inst->state == MSM_VIDC_DRAIN || - inst->state == MSM_VIDC_DRAIN_LAST_FLAG || - inst->state == MSM_VIDC_DRC || - inst->state == MSM_VIDC_DRC_LAST_FLAG || - inst->state == MSM_VIDC_DRC_DRAIN) { - new_state = MSM_VIDC_START_INPUT; - } else if (inst->state == MSM_VIDC_DRC_DRAIN_LAST_FLAG) { - new_state = MSM_VIDC_DRAIN_START_INPUT; + } else if (is_state(inst, MSM_VIDC_STREAMING)) { + new_state = MSM_VIDC_INPUT_STREAMING; } } - rc = msm_vidc_change_inst_state(inst, new_state, __func__); + rc = msm_vidc_change_state(inst, new_state, __func__); if (rc) goto exit; @@ -1970,70 +1903,291 @@ exit: return rc; } -int msm_vidc_state_change_stop(struct msm_vidc_inst *inst) +int msm_vidc_process_drain(struct msm_vidc_inst *inst) { int rc = 0; - enum msm_vidc_inst_state new_state = MSM_VIDC_ERROR; - if (!inst || !inst->core) { + if (!inst) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } - if (inst->state == MSM_VIDC_START) { - new_state = MSM_VIDC_DRAIN; - } else if (inst->state == MSM_VIDC_DRC) { - new_state = MSM_VIDC_DRC_DRAIN; - } else if (inst->state == MSM_VIDC_DRC_DRAIN || - inst->state == MSM_VIDC_DRC_LAST_FLAG) { - new_state = MSM_VIDC_DRC_DRAIN_LAST_FLAG; - } else { - i_vpr_e(inst, "%s: wrong state %s\n", - __func__, state_name(inst->state)); - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); - return -EINVAL; - } - rc = msm_vidc_change_inst_state(inst, new_state, __func__); + rc = venus_hfi_session_drain(inst, INPUT_PORT); + if (rc) + return rc; + rc = msm_vidc_change_sub_state(inst, 0, MSM_VIDC_DRAIN, __func__); if (rc) return rc; return rc; } -int msm_vidc_state_change_start(struct msm_vidc_inst *inst) +int msm_vidc_process_resume(struct msm_vidc_inst *inst) { int rc = 0; - enum msm_vidc_inst_state new_state = MSM_VIDC_ERROR; + enum msm_vidc_sub_state clear_sub_state = MSM_VIDC_SUB_STATE_NONE; + bool drain_pending = false; - if (!inst || !inst->core) { + if (!inst) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } - if (inst->state == MSM_VIDC_DRAIN_LAST_FLAG || - inst->state == MSM_VIDC_DRC_LAST_FLAG) { - new_state = MSM_VIDC_START; - rc = msm_vidc_process_pending_ipsc(inst, &new_state); - if (rc) { - i_vpr_e(inst, "%s: process pending ipsc failed\n", __func__); - goto state_change; + /* first check DRC pending else check drain pending */ + if (is_sub_state(inst, MSM_VIDC_DRC) && + is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) { + clear_sub_state = MSM_VIDC_DRC | MSM_VIDC_DRC_LAST_BUFFER; + /* + * if drain sequence is not completed then do not resume here. + * client will eventually complete drain sequence in which ports + * will be resumed. + */ + drain_pending = is_sub_state(inst, MSM_VIDC_DRAIN) && + is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER); + if (!drain_pending) { + if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = venus_hfi_session_resume(inst, INPUT_PORT, + HFI_CMD_SETTINGS_CHANGE); + if (rc) + return rc; + clear_sub_state |= MSM_VIDC_INPUT_PAUSE; + } + if (is_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE)) { + rc = venus_hfi_session_resume(inst, OUTPUT_PORT, + HFI_CMD_SETTINGS_CHANGE); + if (rc) + return rc; + clear_sub_state |= MSM_VIDC_OUTPUT_PAUSE; + } } - } else if (inst->state == MSM_VIDC_DRC_DRAIN_LAST_FLAG) { - new_state = MSM_VIDC_DRAIN; - rc = msm_vidc_process_pending_ipsc(inst, &new_state); - if (rc) { - i_vpr_e(inst, "%s: process pending ipsc failed\n", __func__); - goto state_change; + } else if (is_sub_state(inst, MSM_VIDC_DRAIN) && + is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER)) { + clear_sub_state = MSM_VIDC_DRAIN | MSM_VIDC_DRAIN_LAST_BUFFER; + if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = venus_hfi_session_resume(inst, INPUT_PORT, HFI_CMD_DRAIN); + if (rc) + return rc; + clear_sub_state |= MSM_VIDC_INPUT_PAUSE; + } + if (is_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE)) { + rc = venus_hfi_session_resume(inst, OUTPUT_PORT, HFI_CMD_DRAIN); + if (rc) + return rc; + clear_sub_state |= MSM_VIDC_OUTPUT_PAUSE; } - } else { - i_vpr_e(inst, "%s: wrong state %s\n", __func__, state_name(inst->state)); - new_state = MSM_VIDC_ERROR; - rc = -EINVAL; - goto state_change; } -state_change: - msm_vidc_change_inst_state(inst, new_state, __func__); + rc = msm_vidc_change_sub_state(inst, clear_sub_state, 0, __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_process_streamon(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + enum msm_vidc_sub_state clear_sub_state = MSM_VIDC_SUB_STATE_NONE; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; + bool drain_pending = false; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (port == INPUT_META_PORT || port == OUTPUT_META_PORT) + return 0; + + msm_vidc_scale_power(inst, true); + + rc = venus_hfi_start(inst, port); + if (rc) + return rc; + + /* clear input/output pause substate immediately */ + if (port == INPUT_PORT && is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = msm_vidc_change_sub_state(inst, MSM_VIDC_INPUT_PAUSE, 0, __func__); + if (rc) + return rc; + } else if (port == OUTPUT_PORT && is_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE)) { + rc = msm_vidc_change_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE, 0, __func__); + if (rc) + return rc; + } + + if (port == INPUT_PORT) { + /* + * if DRC sequence is not completed by the client then PAUSE + * firmware input port to avoid firmware raising IPSC again. + * When client completes DRC or DRAIN sequences, firmware + * input port will be resumed. + */ + if (is_sub_state(inst, MSM_VIDC_DRC) || + is_sub_state(inst, MSM_VIDC_DRAIN)) { + if (!is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = venus_hfi_session_pause(inst, INPUT_PORT); + if (rc) + return rc; + set_sub_state = MSM_VIDC_INPUT_PAUSE; + } + } + } else if (port == OUTPUT_PORT) { + /* + * client completed drc sequence, reset DRC and + * MSM_VIDC_DRC_LAST_BUFFER substates + */ + if (is_sub_state(inst, MSM_VIDC_DRC) && + is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) { + clear_sub_state = MSM_VIDC_DRC | MSM_VIDC_DRC_LAST_BUFFER; + } + /* + * fw input port is paused due to ipsc. now that client + * completed drc sequence, resume fw input port provided + * drain is not pending and input port is streaming. + */ + drain_pending = is_sub_state(inst, MSM_VIDC_DRAIN) && + is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER); + if (!drain_pending && is_state(inst, MSM_VIDC_INPUT_STREAMING)) { + if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = venus_hfi_session_resume(inst, INPUT_PORT, + HFI_CMD_SETTINGS_CHANGE); + if (rc) + return rc; + clear_sub_state |= MSM_VIDC_INPUT_PAUSE; + } + } + } + + rc = msm_vidc_state_change_streamon(inst, port); + if (rc) + return rc; + + rc = msm_vidc_change_sub_state(inst, clear_sub_state, set_sub_state, __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_process_stop_done(struct msm_vidc_inst *inst, + enum signal_session_response signal_type) +{ + int rc = 0; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (signal_type == SIGNAL_CMD_STOP_INPUT) { + set_sub_state = MSM_VIDC_INPUT_PAUSE; + /* + * FW is expected to return DRC LAST flag before input + * stop done if DRC sequence is pending + */ + if (is_sub_state(inst, MSM_VIDC_DRC) && + !is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) { + i_vpr_e(inst, "%s: drc last flag pkt not received\n", __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + /* + * FW is expected to return DRAIN LAST flag before input + * stop done if DRAIN sequence is pending + */ + if (is_sub_state(inst, MSM_VIDC_DRAIN) && + !is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER)) { + i_vpr_e(inst, "%s: drain last flag pkt not received\n", __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + } else if (signal_type == SIGNAL_CMD_STOP_OUTPUT) { + set_sub_state = MSM_VIDC_OUTPUT_PAUSE; + } + + rc = msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__); + if (rc) + return rc; + + signal_session_msg_receipt(inst, signal_type); + return rc; +} + +int msm_vidc_process_drain_done(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (is_sub_state(inst, MSM_VIDC_DRAIN)) { + rc = msm_vidc_change_sub_state(inst, 0, MSM_VIDC_INPUT_PAUSE, __func__); + if (rc) + return rc; + } else { + i_vpr_e(inst, "%s: unexpected drain done\n", __func__); + } + + return rc; +} + +int msm_vidc_process_drain_last_flag(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct v4l2_event event = {0}; + struct v4l2_event_vidc_last_flag *event_data = NULL; + + if (!inst || !inst->capabilities) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_state_change_drain_last_flag(inst); + if (rc) + return rc; + + if (is_decode_session(inst) && + !inst->capabilities->cap[LAST_FLAG_EVENT_ENABLE].value) { + i_vpr_h(inst, "%s: last flag event not enabled\n", __func__); + return 0; + } + + event.type = V4L2_EVENT_VIDC_LAST_FLAG; + event_data = (struct v4l2_event_vidc_last_flag *)event.u.data; + event_data->flag_type = LAST_FLAG_DRAIN; + v4l2_event_queue_fh(&inst->event_handler, &event); + + return rc; +} + +int msm_vidc_process_psc_last_flag(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct v4l2_event event = {0}; + struct v4l2_event_vidc_last_flag *event_data = NULL; + + if (!inst || !inst->capabilities) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_state_change_psc_last_flag(inst); + if (rc) + return rc; + + if (is_decode_session(inst) && + !inst->capabilities->cap[LAST_FLAG_EVENT_ENABLE].value) { + i_vpr_h(inst, "%s: last flag event not enabled\n", __func__); + return 0; + } + + event.type = V4L2_EVENT_VIDC_LAST_FLAG; + event_data = (struct v4l2_event_vidc_last_flag *)event.u.data; + event_data->flag_type = LAST_FLAG_DRC; + v4l2_event_queue_fh(&inst->event_handler, &event); return rc; } @@ -2041,55 +2195,61 @@ state_change: int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst) { int rc = 0; - enum msm_vidc_inst_state new_state = MSM_VIDC_ERROR; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; if (!inst || !inst->core) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } - /* don't change state as output port is not started yet */ - if (inst->state == MSM_VIDC_START_INPUT) - return 0; - if (inst->state == MSM_VIDC_START) { - new_state = MSM_VIDC_DRC; - } else if (inst->state == MSM_VIDC_DRAIN) { - new_state = MSM_VIDC_DRC_DRAIN; - } else { - i_vpr_e(inst, "%s: wrong state %s\n", - __func__, state_name(inst->state)); - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); - return -EINVAL; - } - rc = msm_vidc_change_inst_state(inst, new_state, __func__); + /* + * if output port is not streaming, then do not set DRC substate + * because DRC_LAST_FLAG is not going to be received. Update + * INPUT_PAUSE substate only + */ + if (is_state(inst, MSM_VIDC_INPUT_STREAMING) || + is_state(inst, MSM_VIDC_OPEN)) + set_sub_state = MSM_VIDC_INPUT_PAUSE; + else + set_sub_state = MSM_VIDC_DRC | MSM_VIDC_INPUT_PAUSE; + + rc = msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__); if (rc) return rc; return rc; } -int msm_vidc_state_change_last_flag(struct msm_vidc_inst *inst) +int msm_vidc_state_change_drain_last_flag(struct msm_vidc_inst *inst) { int rc = 0; - enum msm_vidc_inst_state new_state = MSM_VIDC_ERROR; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; if (!inst || !inst->core) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } - if (inst->state == MSM_VIDC_DRC) { - new_state = MSM_VIDC_DRC_LAST_FLAG; - } else if (inst->state == MSM_VIDC_DRAIN) { - new_state = MSM_VIDC_DRAIN_LAST_FLAG; - } else if (inst->state == MSM_VIDC_DRC_DRAIN) { - new_state = MSM_VIDC_DRC_DRAIN_LAST_FLAG; - } else { - i_vpr_e(inst, "%s: wrong state %s\n", - __func__, state_name(inst->state)); - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + + set_sub_state = MSM_VIDC_DRAIN_LAST_BUFFER | MSM_VIDC_OUTPUT_PAUSE; + rc = msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_state_change_psc_last_flag(struct msm_vidc_inst *inst) +{ + int rc = 0; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } - rc = msm_vidc_change_inst_state(inst, new_state, __func__); + + set_sub_state = MSM_VIDC_DRC_LAST_BUFFER | MSM_VIDC_OUTPUT_PAUSE; + rc = msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__); if (rc) return rc; @@ -3317,7 +3477,7 @@ int schedule_stats_work(struct msm_vidc_inst *inst) return 0; } core = inst->core; - mod_delayed_work(inst->response_workq, &inst->stats_work, + mod_delayed_work(inst->workq, &inst->stats_work, msecs_to_jiffies(core->capabilities[STATS_TIMEOUT_MS].value)); return 0; @@ -4357,25 +4517,6 @@ int msm_vidc_session_set_default_header(struct msm_vidc_inst *inst) return rc; } -int msm_vidc_session_streamon(struct msm_vidc_inst *inst, - enum msm_vidc_port_type port) -{ - int rc = 0; - - if (!inst || !inst->core) { - d_vpr_e("%s: invalid params\n", __func__); - return -EINVAL; - } - - msm_vidc_scale_power(inst, true); - - rc = venus_hfi_start(inst, port); - if (rc) - return rc; - - return rc; -} - int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) { @@ -4405,6 +4546,10 @@ 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); @@ -4427,20 +4572,10 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, goto error; if (port == INPUT_PORT) { - /* discard pending input port settings change if any */ - msm_vidc_discard_pending_ipsc(inst); - /* flush input timer list */ msm_vidc_flush_input_timer(inst); } - if (port == OUTPUT_PORT) { - /* discard pending opsc if any*/ - msm_vidc_discard_pending_opsc(inst); - /* flush out pending last flag buffers if any */ - msm_vidc_flush_pending_last_flag(inst); - } - /* no more queued buffers after streamoff */ count = msm_vidc_num_buffers(inst, buffer_type, MSM_VIDC_ATTR_QUEUED); if (!count) { @@ -4502,6 +4637,9 @@ int msm_vidc_session_close(struct msm_vidc_inst *inst) } inst_lock(inst, __func__); + inst->state = MSM_VIDC_CLOSE; + inst->sub_state = MSM_VIDC_SUB_STATE_NONE; + strlcpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name)); msm_vidc_remove_session(inst); return rc; @@ -4520,7 +4658,7 @@ int msm_vidc_kill_session(struct msm_vidc_inst *inst) i_vpr_e(inst, "%s: killing session\n", __func__); msm_vidc_session_close(inst); - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); return 0; } @@ -4820,7 +4958,7 @@ int msm_vidc_core_deinit_locked(struct msm_vidc_core *core, bool force) /* unlink all sessions from core, if any */ list_for_each_entry_safe(inst, dummy, &core->instances, list) { - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); list_del_init(&inst->list); list_add_tail(&inst->list, &core->dangling_instances); } @@ -5326,7 +5464,7 @@ void msm_vidc_batch_handler(struct work_struct *work) rc = msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT); if (rc) { i_vpr_e(inst, "%s: batch qbufs failed\n", __func__); - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); } exit: @@ -5434,7 +5572,7 @@ int msm_vidc_flush_delayed_unmap_buffers(struct msm_vidc_inst *inst, i_vpr_e(inst, "%s: unexpected map refcount: %u device addr %#x\n", __func__, map->refcount, map->device_addr); - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); } msm_vidc_memory_unmap_completely(inst, map); } @@ -5451,7 +5589,6 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) struct msm_vidc_timestamp *ts, *dummy_ts; struct msm_memory_dmabuf *dbuf, *dummy_dbuf; struct msm_vidc_input_timer *timer, *dummy_timer; - struct response_work *work, *dummy_work = NULL; struct msm_vidc_inst_cap_entry *entry, *dummy_entry; struct msm_vidc_fence *fence, *dummy_fence; @@ -5547,12 +5684,6 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) msm_vidc_memory_put_dmabuf_completely(inst, dbuf); } - list_for_each_entry_safe(work, dummy_work, &inst->response_works, list) { - list_del(&work->list); - msm_vidc_vmem_free((void **)&work->data); - msm_vidc_vmem_free((void **)&work); - } - list_for_each_entry_safe(entry, dummy_entry, &inst->firmware_list, list) { i_vpr_e(inst, "%s: fw list: %s\n", __func__, cap_name(entry->cap_id)); list_del(&entry->list); @@ -5594,8 +5725,8 @@ static void msm_vidc_close_helper(struct kref *kref) else if (is_encode_session(inst)) msm_venc_inst_deinit(inst); msm_vidc_free_input_cr_list(inst); - if (inst->response_workq) - destroy_workqueue(inst->response_workq); + if (inst->workq) + destroy_workqueue(inst->workq); msm_vidc_remove_dangling_session(inst); mutex_destroy(&inst->client_lock); mutex_destroy(&inst->request_lock); diff --git a/driver/vidc/src/msm_vidc_vb2.c b/driver/vidc/src/msm_vidc_vb2.c index 740c3b7db1..4b3378fe5d 100644 --- a/driver/vidc/src/msm_vidc_vb2.c +++ b/driver/vidc/src/msm_vidc_vb2.c @@ -112,7 +112,7 @@ int msm_vidc_queue_setup(struct vb2_queue *q, return -EINVAL; } - if (inst->state == MSM_VIDC_START) { + if (is_state(inst, MSM_VIDC_STREAMING)) { i_vpr_e(inst, "%s: invalid state %d\n", __func__, inst->state); return -EINVAL; } @@ -217,10 +217,6 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count) goto unlock; } - rc = msm_vidc_state_change_streamon(inst, q->type); - if (rc) - goto unlock; - if (q->type == INPUT_META_PLANE && inst->capabilities->cap[INPUT_META_VIA_REQUEST].value) { i_vpr_e(inst, @@ -335,7 +331,7 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count) unlock: if (rc) { i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type)); - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); } inst_unlock(inst, __func__); client_unlock(inst, __func__); @@ -381,10 +377,6 @@ void msm_vidc_stop_streaming(struct vb2_queue *q) goto unlock; } - rc = msm_vidc_state_change_streamoff(inst, q->type); - if (rc) - goto unlock; - if (!is_decode_session(inst) && !is_encode_session(inst)) { i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); @@ -420,7 +412,7 @@ void msm_vidc_stop_streaming(struct vb2_queue *q) unlock: if (rc) { i_vpr_e(inst, "Streamoff: %s failed\n", v4l2_type_name(q->type)); - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); } inst_unlock(inst, __func__); client_unlock(inst, __func__); @@ -531,7 +523,7 @@ void msm_vidc_buf_queue(struct vb2_buffer *vb2) unlock: if (rc) { - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); vb2_buffer_done(vb2, VB2_BUF_STATE_ERROR); } inst_unlock(inst, __func__); diff --git a/driver/vidc/src/venus_hfi.c b/driver/vidc/src/venus_hfi.c index e3f1f2b4ae..b1905e1c21 100644 --- a/driver/vidc/src/venus_hfi.c +++ b/driver/vidc/src/venus_hfi.c @@ -3308,6 +3308,137 @@ unlock: return rc; } +int venus_hfi_session_pause(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) +{ + int rc = 0; + struct msm_vidc_core* core; + + if (!inst || !inst->core || !inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + goto unlock; + } + + rc = hfi_packet_session_command(inst, + HFI_CMD_PAUSE, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED), + get_hfi_port(inst, port), + inst->session_id, + HFI_PAYLOAD_NONE, + NULL, + 0); + if (rc) + goto unlock; + + rc = __iface_cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_session_resume(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port, u32 payload) +{ + int rc = 0; + struct msm_vidc_core* core; + + if (!inst || !inst->core || !inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + goto unlock; + } + + rc = hfi_packet_session_command(inst, + HFI_CMD_RESUME, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED), + get_hfi_port(inst, port), + inst->session_id, + HFI_PAYLOAD_U32, + &payload, + sizeof(u32)); + if (rc) + goto unlock; + + rc = __iface_cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_session_drain(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) +{ + int rc = 0; + struct msm_vidc_core* core; + + if (!inst || !inst->core || !inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + if (port != INPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + goto unlock; + } + + rc = hfi_packet_session_command(inst, + HFI_CMD_DRAIN, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED | + HFI_HOST_FLAGS_NON_DISCARDABLE), + get_hfi_port(inst, port), + inst->session_id, + HFI_PAYLOAD_NONE, + NULL, + 0); + if (rc) + goto unlock; + + rc = __iface_cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + int venus_hfi_session_command(struct msm_vidc_inst *inst, u32 cmd, enum msm_vidc_port_type port, u32 payload_type, void *payload, u32 payload_size) diff --git a/driver/vidc/src/venus_hfi_response.c b/driver/vidc/src/venus_hfi_response.c index 4434815e7b..db18a5dfc9 100644 --- a/driver/vidc/src/venus_hfi_response.c +++ b/driver/vidc/src/venus_hfi_response.c @@ -178,14 +178,6 @@ bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst, return true; } -static int signal_session_msg_receipt(struct msm_vidc_inst *inst, - enum signal_session_response cmd) -{ - if (cmd < MAX_SIGNAL) - complete(&inst->completions[cmd]); - return 0; -} - int validate_packet(u8 *response_pkt, u8 *core_resp_pkt, u32 core_resp_pkt_size, const char *func) { @@ -304,29 +296,35 @@ static bool check_for_packet_payload(struct msm_vidc_inst *inst, return true; } -static bool check_last_flag(struct msm_vidc_inst *inst, - struct hfi_packet *pkt) +static int handle_session_last_flag_info(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) { - struct hfi_buffer *buffer; + int rc = 0; - if (!inst || !pkt) { - d_vpr_e("%s: invalid params\n", __func__); - return false; + if (pkt->type == HFI_INFO_HFI_FLAG_PSC_LAST) { + if (msm_vidc_allow_psc_last_flag(inst)) + rc = msm_vidc_process_psc_last_flag(inst); + else + rc = -EINVAL; + } else if (pkt->type == HFI_INFO_HFI_FLAG_DRAIN_LAST) { + if (msm_vidc_allow_drain_last_flag(inst)) + rc = msm_vidc_process_drain_last_flag(inst); + else + rc = -EINVAL; + } else { + i_vpr_e(inst, "%s: invalid packet type %#x\n", __func__, + pkt->type); } - buffer = (struct hfi_buffer *)((u8 *)pkt + sizeof(struct hfi_packet)); - if (buffer->flags & HFI_BUF_FW_FLAG_LAST) { - i_vpr_h(inst, "%s: received last flag on FBD, index: %d\n", - __func__, buffer->index); - return true; - } - return false; + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + + return rc; } static int handle_session_info(struct msm_vidc_inst *inst, struct hfi_packet *pkt) { - int rc = 0; char *info; @@ -342,12 +340,20 @@ static int handle_session_info(struct msm_vidc_inst *inst, info = "buffer overflow"; inst->hfi_frame_info.overflow = 1; break; + case HFI_INFO_HFI_FLAG_DRAIN_LAST: + info = "drain last flag"; + rc = handle_session_last_flag_info(inst, pkt); + break; + case HFI_INFO_HFI_FLAG_PSC_LAST: + info = "drc last flag"; + rc = handle_session_last_flag_info(inst, pkt); + break; default: info = "unknown"; break; } - i_vpr_e(inst, "session info (%#x): %s\n", pkt->type, info); + i_vpr_h(inst, "session info (%#x): %s\n", pkt->type, info); return rc; } @@ -385,7 +391,7 @@ static int handle_session_error(struct msm_vidc_inst *inst, i_vpr_e(inst, "%s: session error received %#x: %s\n", __func__, pkt->type, error); - rc = msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + rc = msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); return rc; } @@ -537,7 +543,8 @@ static int handle_session_start(struct msm_vidc_inst *inst, static int handle_session_stop(struct msm_vidc_inst *inst, struct hfi_packet *pkt) { - int signal_type = -1; + int rc = 0; + enum signal_session_response signal_type = -1; if (pkt->flags & HFI_FW_FLAGS_SUCCESS) i_vpr_h(inst, "%s: successful for port %d\n", @@ -568,17 +575,28 @@ static int handle_session_stop(struct msm_vidc_inst *inst, return -EINVAL; } - if (signal_type != -1) - signal_session_msg_receipt(inst, signal_type); + if (signal_type != -1) { + rc = msm_vidc_process_stop_done(inst, signal_type); + if (rc) + return rc; + } + return 0; } static int handle_session_drain(struct msm_vidc_inst *inst, struct hfi_packet *pkt) { + int rc = 0; + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) i_vpr_h(inst, "%s: successful\n", __func__); - return 0; + + rc = msm_vidc_process_drain_done(inst); + if (rc) + return rc; + + return rc; } static int get_driver_buffer_flags(struct msm_vidc_inst *inst, u32 hfi_flags) @@ -618,7 +636,18 @@ static int get_driver_buffer_flags(struct msm_vidc_inst *inst, u32 hfi_flags) if (hfi_flags & HFI_BUF_FW_FLAG_CODEC_CONFIG) driver_flags |= MSM_VIDC_BUF_FLAG_CODECCONFIG; - if (hfi_flags & HFI_BUF_FW_FLAG_LAST) + /* + * attach last flag to the buffer for encode session. + * For decode session attach only if control(LAST_FLAG_EVENT_ENABLE) + * is not set by client. If this control is enabled, last flag + * info will be sent via event(V4L2_EVENT_VIDC_LAST_FLAG) to client. + */ + if ((is_encode_session(inst) && + (hfi_flags & HFI_BUF_FW_FLAG_LAST)) || + (is_decode_session(inst) && + !inst->capabilities->cap[LAST_FLAG_EVENT_ENABLE].value && + ((hfi_flags & HFI_BUF_FW_FLAG_LAST) || + (hfi_flags & HFI_BUF_FW_FLAG_PSC_LAST)))) driver_flags |= MSM_VIDC_BUF_FLAG_LAST; return driver_flags; @@ -714,6 +743,48 @@ static int handle_non_read_only_buffer(struct msm_vidc_inst *inst, return 0; } +static int handle_psc_last_flag_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + int rc = 0; + + if (!(buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST)) + return 0; + + if (!msm_vidc_allow_psc_last_flag(inst)) + return -EINVAL; + + rc = msm_vidc_process_psc_last_flag(inst); + if (rc) + return rc; + + return rc; +} + +static int handle_drain_last_flag_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + int rc = 0; + + if (!(buffer->flags & HFI_BUF_FW_FLAG_LAST)) + return 0; + + if (!msm_vidc_allow_drain_last_flag(inst)) + return -EINVAL; + + if (is_decode_session(inst)) { + rc = msm_vidc_process_drain_last_flag(inst); + if (rc) + return rc; + } else if (is_encode_session(inst)) { + rc = msm_vidc_state_change_drain_last_flag(inst); + if (rc) + return rc; + } + + return rc; +} + static int handle_input_buffer(struct msm_vidc_inst *inst, struct hfi_buffer *buffer) { @@ -801,11 +872,25 @@ static int handle_output_buffer(struct msm_vidc_inst *inst, return -EINVAL; } + /* handle drain last flag buffer */ + if (buffer->flags & HFI_BUF_FW_FLAG_LAST) { + rc = handle_drain_last_flag_buffer(inst, buffer); + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + if (is_decode_session(inst)) { + /* handle psc last flag buffer */ + if (buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST) { + rc = handle_psc_last_flag_buffer(inst, buffer); + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + /* handle non-read only buffer */ if (!(buffer->flags & HFI_BUF_FW_FLAG_READONLY)) { rc = handle_non_read_only_buffer(inst, buffer); if (rc) - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); } } @@ -861,14 +946,15 @@ static int handle_output_buffer(struct msm_vidc_inst *inst, } } if (fatal) - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); } /* * reset data size to zero for last flag buffer. * reset RO flag for last flag buffer. */ - if (buffer->flags & HFI_BUF_FW_FLAG_LAST) { + if ((buffer->flags & HFI_BUF_FW_FLAG_LAST) || + (buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST)) { if (buffer->data_size) { i_vpr_e(inst, "%s: reset data size to zero for last flag buffer\n", __func__); @@ -894,7 +980,7 @@ static int handle_output_buffer(struct msm_vidc_inst *inst, buf->attr |= MSM_VIDC_ATTR_READ_ONLY; rc = handle_read_only_buffer(inst, buf); if (rc) - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); } else { buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY; } @@ -993,7 +1079,12 @@ static int handle_input_metadata_buffer(struct msm_vidc_inst *inst, buf->attr &= ~MSM_VIDC_ATTR_QUEUED; buf->attr |= MSM_VIDC_ATTR_DEQUEUED; buf->flags = 0; - if (buffer->flags & HFI_BUF_FW_FLAG_LAST) + if ((is_encode_session(inst) && + (buffer->flags & HFI_BUF_FW_FLAG_LAST)) || + (is_decode_session(inst) && + !inst->capabilities->cap[LAST_FLAG_EVENT_ENABLE].value && + ((buffer->flags & HFI_BUF_FW_FLAG_LAST) || + (buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST)))) buf->flags |= MSM_VIDC_BUF_FLAG_LAST; print_vidc_buffer(VIDC_LOW, "low ", "dqbuf", inst, buf); @@ -1008,6 +1099,11 @@ static int handle_output_metadata_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf; bool found; + if (!inst || !inst->capabilities) { + d_vpr_e("%s: Invalid params\n", __func__); + return -EINVAL; + } + buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_OUTPUT_META, __func__); if (!buffers) return -EINVAL; @@ -1035,7 +1131,12 @@ static int handle_output_metadata_buffer(struct msm_vidc_inst *inst, buf->attr &= ~MSM_VIDC_ATTR_QUEUED; buf->attr |= MSM_VIDC_ATTR_DEQUEUED; buf->flags = 0; - if (buffer->flags & HFI_BUF_FW_FLAG_LAST) + if ((is_encode_session(inst) && + (buffer->flags & HFI_BUF_FW_FLAG_LAST)) || + (is_decode_session(inst) && + !inst->capabilities->cap[LAST_FLAG_EVENT_ENABLE].value && + ((buffer->flags & HFI_BUF_FW_FLAG_LAST) || + (buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST)))) buf->flags |= MSM_VIDC_BUF_FLAG_LAST; print_vidc_buffer(VIDC_LOW, "low ", "dqbuf", inst, buf); @@ -1267,18 +1368,18 @@ static int handle_session_buffer(struct msm_vidc_inst *inst, } if (!check_for_packet_payload(inst, pkt, __func__)) { - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); return 0; } buffer = (struct hfi_buffer *)((u8 *)pkt + sizeof(struct hfi_packet)); if (!is_valid_hfi_buffer_type(inst, buffer->type, __func__)) { - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); return 0; } if (!is_valid_hfi_port(inst, pkt->port, buffer->type, __func__)) { - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); return 0; } if (is_decode_session(inst) && buffer->type == HFI_BUFFER_RAW && @@ -1329,6 +1430,39 @@ static int handle_session_buffer(struct msm_vidc_inst *inst, return rc; } +static int handle_input_port_settings_change(struct msm_vidc_inst *inst) +{ + int rc = 0; + enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; + + allow = msm_vidc_allow_input_psc(inst); + if (allow == MSM_VIDC_DISALLOW) { + return -EINVAL; + } else if (allow == MSM_VIDC_ALLOW) { + rc = msm_vidc_state_change_input_psc(inst); + if (rc) + return rc; + print_psc_properties("INPUT_PSC", inst, inst->subcr_params[INPUT_PORT]); + rc = msm_vdec_input_port_settings_change(inst); + if (rc) + return rc; + } + + return rc; +} + +static int handle_output_port_settings_change(struct msm_vidc_inst *inst) +{ + int rc = 0; + + print_psc_properties("OUTPUT_PSC", inst, inst->subcr_params[OUTPUT_PORT]); + rc = msm_vdec_output_port_settings_change(inst); + if (rc) + return rc; + + return rc; +} + static int handle_port_settings_change(struct msm_vidc_inst *inst, struct hfi_packet *pkt) { @@ -1338,17 +1472,23 @@ static int handle_port_settings_change(struct msm_vidc_inst *inst, __func__, pkt->port); if (pkt->port == HFI_PORT_RAW) { - print_psc_properties("OUTPUT_PSC", inst, inst->subcr_params[OUTPUT_PORT]); - rc = msm_vdec_output_port_settings_change(inst); + rc = handle_output_port_settings_change(inst); + if (rc) + goto exit; } else if (pkt->port == HFI_PORT_BITSTREAM) { - print_psc_properties("INPUT_PSC", inst, inst->subcr_params[INPUT_PORT]); - rc = msm_vdec_input_port_settings_change(inst); + rc = handle_input_port_settings_change(inst); + if (rc) + goto exit; } else { i_vpr_e(inst, "%s: invalid port type: %#x\n", __func__, pkt->port); rc = -EINVAL; + goto exit; } +exit: + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); return rc; } @@ -1368,6 +1508,14 @@ static int handle_session_delivery_mode(struct msm_vidc_inst *inst, return 0; } +static int handle_session_pause(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful\n", __func__); + return 0; +} + static int handle_session_resume(struct msm_vidc_inst *inst, struct hfi_packet *pkt) { @@ -1398,6 +1546,7 @@ static int handle_session_command(struct msm_vidc_inst *inst, {HFI_CMD_SETTINGS_CHANGE, handle_port_settings_change }, {HFI_CMD_SUBSCRIBE_MODE, handle_session_subscribe_mode }, {HFI_CMD_DELIVERY_MODE, handle_session_delivery_mode }, + {HFI_CMD_PAUSE, handle_session_pause }, {HFI_CMD_RESUME, handle_session_resume }, {HFI_CMD_STABILITY, handle_session_stability }, }; @@ -1437,7 +1586,7 @@ static int handle_dpb_list_property(struct msm_vidc_inst *inst, i_vpr_e(inst, "%s: dpb list payload size %d exceeds expected max size %d\n", __func__, payload_size, MAX_DPB_LIST_PAYLOAD_SIZE); - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); } memcpy(inst->dpb_list_payload, payload_start, payload_size); @@ -1764,7 +1913,7 @@ static int __handle_session_response(struct msm_vidc_inst *inst, dequeue |= (packet->type == HFI_CMD_BUFFER); rc = be[i].handle(inst, packet); if (rc) - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); } pkt += packet->size; } @@ -1780,163 +1929,14 @@ static int __handle_session_response(struct msm_vidc_inst *inst, return rc; } -int handle_session_response_work(struct msm_vidc_inst *inst, - struct response_work *resp_work) -{ - int rc = 0; - struct hfi_header *hdr = NULL; - - if (!inst || !inst->core || !resp_work) { - d_vpr_e("%s: invalid params\n", __func__); - return -EINVAL; - } - - hdr = (struct hfi_header *)resp_work->data; - if (!hdr) { - i_vpr_e(inst, "%s: invalid params\n", __func__); - return -EINVAL; - } - if (resp_work->type == RESP_WORK_INPUT_PSC) - msm_vdec_init_input_subcr_params(inst); - - rc = __handle_session_response(inst, hdr); - if (rc) - return rc; - - return 0; -} - -void handle_session_response_work_handler(struct work_struct *work) -{ - int rc = 0; - struct msm_vidc_inst *inst; - struct response_work *resp_work, *dummy = NULL; - - inst = container_of(work, struct msm_vidc_inst, response_work.work); - inst = get_inst_ref(g_core, inst); - if (!inst) { - d_vpr_e("%s: invalid params\n", __func__); - return; - } - - inst_lock(inst, __func__); - list_for_each_entry_safe(resp_work, dummy, &inst->response_works, list) { - switch (resp_work->type) { - case RESP_WORK_INPUT_PSC: - { - enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; - - allow = msm_vidc_allow_input_psc(inst); - if (allow == MSM_VIDC_DISALLOW) { - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); - break; - } else if (allow == MSM_VIDC_DEFER) { - /* continue to next entry processing */ - continue; - } else if (allow == MSM_VIDC_DISCARD) { - /* if ipsc is discarded then override the psc properties again */ - inst->ipsc_properties_set = false; - /* discard current entry processing */ - break; - } else if (allow == MSM_VIDC_ALLOW) { - rc = handle_session_response_work(inst, resp_work); - if (!rc) - rc = msm_vidc_state_change_input_psc(inst); - /* either handle input psc or state change failed */ - if (rc) - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); - } - break; - } - case RESP_WORK_OUTPUT_PSC: - rc = handle_session_response_work(inst, resp_work); - if (rc) - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); - break; - case RESP_WORK_LAST_FLAG: - rc = handle_session_response_work(inst, resp_work); - if (rc) { - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); - break; - } - if (msm_vidc_allow_last_flag(inst)) { - rc = msm_vidc_state_change_last_flag(inst); - if (rc) - msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); - } - break; - default: - i_vpr_e(inst, "%s: invalid response work type %d\n", __func__, - resp_work->type); - break; - } - list_del(&resp_work->list); - msm_vidc_vmem_free((void **)&resp_work->data); - msm_vidc_vmem_free((void **)&resp_work); - } - inst_unlock(inst, __func__); - - put_inst(inst); -} - -static int queue_response_work(struct msm_vidc_inst *inst, - enum response_work_type type, void *hdr, u32 hdr_size) -{ - struct response_work *work = NULL; - - if (msm_vidc_vmem_alloc(sizeof(struct response_work), (void **)&work, __func__)) - return -ENOMEM; - INIT_LIST_HEAD(&work->list); - work->type = type; - work->data_size = hdr_size; - if (msm_vidc_vmem_alloc(hdr_size, (void **)&work->data, "Work data")) - return -ENOMEM; - memcpy(work->data, hdr, hdr_size); - list_add_tail(&work->list, &inst->response_works); - queue_delayed_work(inst->response_workq, - &inst->response_work, msecs_to_jiffies(0)); - return 0; -} - -int cancel_response_work(struct msm_vidc_inst *inst) -{ - struct response_work *work, *dummy_work = NULL; - - if (!inst) { - d_vpr_e("%s: Invalid arguments\n", __func__); - return -EINVAL; - } - cancel_delayed_work(&inst->response_work); - - list_for_each_entry_safe(work, dummy_work, &inst->response_works, list) { - list_del(&work->list); - msm_vidc_vmem_free((void **)&work->data); - msm_vidc_vmem_free((void **)&work); - } - - return 0; -} - -int cancel_response_work_sync(struct msm_vidc_inst *inst) -{ - if (!inst || !inst->response_workq) { - d_vpr_e("%s: Invalid arguments\n", __func__); - return -EINVAL; - } - cancel_delayed_work_sync(&inst->response_work); - - return 0; -} - static int handle_session_response(struct msm_vidc_core *core, struct hfi_header *hdr) { struct msm_vidc_inst *inst; struct hfi_packet *packet; u8 *pkt; - enum response_work_type type; int i, rc = 0; - bool offload = false; + bool found_ipsc = false; if (!core || !hdr) { d_vpr_e("%s: Invalid params\n", __func__); @@ -1950,42 +1950,22 @@ static int handle_session_response(struct msm_vidc_core *core, } inst_lock(inst, __func__); - /* search for special pkt */ + /* search for cmd settings change pkt */ pkt = (u8 *)((u8 *)hdr + sizeof(struct hfi_header)); for (i = 0; i < hdr->num_packets; i++) { packet = (struct hfi_packet *)pkt; - if (packet->type == HFI_CMD_SETTINGS_CHANGE) { if (packet->port == HFI_PORT_BITSTREAM) { - offload = true; - type = RESP_WORK_INPUT_PSC; - } else if (packet->port == HFI_PORT_RAW) { - offload = true; - type = RESP_WORK_OUTPUT_PSC; - } - } else if (packet->type == HFI_CMD_BUFFER && - vidc_port_from_hfi(inst, packet->port) == - OUTPUT_PORT) { - if (check_last_flag(inst, packet)) { - offload = true; - type = RESP_WORK_LAST_FLAG; + found_ipsc = true; + break; } } - - if (offload) - break; - pkt += packet->size; } - if (offload) { - i_vpr_h(inst, "%s: queue response work %#x\n", __func__, type); - rc = queue_response_work(inst, type, (void *)hdr, hdr->size); - if (rc) - i_vpr_e(inst, "%s: Offload response work failed\n", __func__); - - goto exit; - } + /* if ipsc packet is found, initialise subsc_params */ + if (found_ipsc) + msm_vdec_init_input_subcr_params(inst); rc = __handle_session_response(inst, hdr); if (rc) diff --git a/include/uapi/vidc/media/v4l2_vidc_extensions.h b/include/uapi/vidc/media/v4l2_vidc_extensions.h index bdd685b5f3..17e02d8293 100644 --- a/include/uapi/vidc/media/v4l2_vidc_extensions.h +++ b/include/uapi/vidc/media/v4l2_vidc_extensions.h @@ -268,6 +268,9 @@ enum v4l2_h264_encode_delivery_mode { #define V4L2_CID_MPEG_VIDC_CLIENT_ID \ (V4L2_CID_MPEG_VIDC_BASE + 0x41) +#define V4L2_CID_MPEG_VIDC_LAST_FLAG_EVENT_ENABLE \ + (V4L2_CID_MPEG_VIDC_BASE + 0x42) + /* add new controls above this line */ /* Deprecate below controls once availble in gki and gsi bionic header */ #ifndef V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID @@ -461,6 +464,19 @@ struct v4l2_event_vidc_metadata { __u32 offset; __u8 reserved[44]; }; + +#define V4L2_EVENT_VIDC_LAST_FLAG \ + (V4L2_EVENT_PRIVATE_START + 0x2) + +enum v4l2_event_last_flag { + LAST_FLAG_DRC = (1 << 0), + LAST_FLAG_DRAIN = (1 << 1), +}; + +struct v4l2_event_vidc_last_flag { + enum v4l2_event_last_flag flag_type; +}; + /* vendor events end */ /* Default metadata size (align to 4KB) */