diff --git a/driver/platform/waipio/src/msm_vidc_waipio.c b/driver/platform/waipio/src/msm_vidc_waipio.c index f6030c5779..0f62cf5688 100644 --- a/driver/platform/waipio/src/msm_vidc_waipio.c +++ b/driver/platform/waipio/src/msm_vidc_waipio.c @@ -166,8 +166,10 @@ static struct msm_platform_inst_capability instance_data_waipio[] = { /* (4096 * 2304) / 256 */ {LOSSLESS_MBPF, ENC, H264|HEVC, 64, 36864, 1, 36864}, /* Batch Mode Decode */ + /* TODO: update with new values based on updated voltage corner */ {BATCH_MBPF, DEC, CODECS_ALL, 64, 34816, 1, 34816}, /* (4096 * 2304) / 256 */ + {BATCH_FPS, DEC, CODECS_ALL, 1, 120, 1, 120}, {SECURE_MBPF, ENC|DEC, CODECS_ALL, 64, 36864, 1, 36864}, /* ((1920 * 1088) / 256) * 480 fps */ {MBPS, ENC, CODECS_ALL, 64, 3916800, 1, 3916800}, diff --git a/driver/variant/iris2/src/msm_vidc_iris2.c b/driver/variant/iris2/src/msm_vidc_iris2.c index 1d6103e7d0..92ba209b86 100644 --- a/driver/variant/iris2/src/msm_vidc_iris2.c +++ b/driver/variant/iris2/src/msm_vidc_iris2.c @@ -12,6 +12,7 @@ #include "msm_vidc_inst.h" #include "msm_vidc_core.h" #include "msm_vidc_driver.h" +#include "msm_vidc_control.h" #include "msm_vidc_dt.h" #include "msm_vidc_internal.h" #include "msm_vidc_buffer.h" @@ -564,7 +565,7 @@ int msm_vidc_decide_work_mode_iris2(struct msm_vidc_inst* inst) i_vpr_h(inst, "Configuring work mode = %u low latency = %u", work_mode, lowlatency); - inst->capabilities->cap[STAGE].value = work_mode; + msm_vidc_update_cap_value(inst, STAGE, work_mode, __func__); /* TODO If Encode then Set Low Latency (Enable/Disable) * and Update internal cap struct @@ -609,7 +610,7 @@ int msm_vidc_decide_work_route_iris2(struct msm_vidc_inst* inst) } i_vpr_h(inst, "Configuring work route = %u", work_route); - inst->capabilities->cap[PIPE].value = work_route; + msm_vidc_update_cap_value(inst, PIPE, work_route, __func__); return 0; } @@ -643,7 +644,7 @@ int msm_vidc_decide_quality_mode_iris2(struct msm_vidc_inst* inst) (mbpf <= max_hq_mbpf && mbps <= max_hq_mbps)) mode = MSM_VIDC_MAX_QUALITY_MODE; - capability->cap[QUALITY_MODE].value = mode; + msm_vidc_update_cap_value(inst, QUALITY_MODE, mode, __func__); return 0; } diff --git a/driver/vidc/inc/msm_vdec.h b/driver/vidc/inc/msm_vdec.h index 5371979159..0926cf1e23 100644 --- a/driver/vidc/inc/msm_vdec.h +++ b/driver/vidc/inc/msm_vdec.h @@ -29,5 +29,6 @@ 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_vidc_queue_buffer_batch(struct msm_vidc_inst *inst); #endif // _MSM_VDEC_H_ diff --git a/driver/vidc/inc/msm_vidc_control.h b/driver/vidc/inc/msm_vidc_control.h index 13ad1d2292..0d7fd8a574 100644 --- a/driver/vidc/inc/msm_vidc_control.h +++ b/driver/vidc/inc/msm_vidc_control.h @@ -70,5 +70,7 @@ int msm_vidc_v4l2_menu_to_hfi(struct msm_vidc_inst *inst, enum msm_vidc_inst_capability_type cap_id, u32 *value); int msm_vidc_v4l2_to_hfi_enum(struct msm_vidc_inst *inst, enum msm_vidc_inst_capability_type cap_id, u32 *value); +int msm_vidc_update_cap_value(struct msm_vidc_inst *inst, u32 cap, + s32 adjusted_val, const char *func); #endif diff --git a/driver/vidc/inc/msm_vidc_core.h b/driver/vidc/inc/msm_vidc_core.h index 945aba30c0..a55b8a2fc7 100644 --- a/driver/vidc/inc/msm_vidc_core.h +++ b/driver/vidc/inc/msm_vidc_core.h @@ -88,8 +88,8 @@ struct msm_vidc_core { struct workqueue_struct *device_workq; struct delayed_work pm_work; struct workqueue_struct *pm_workq; + struct workqueue_struct *batch_workq; struct delayed_work fw_unload_work; - struct delayed_work batch_work; struct work_struct ssr_work; struct msm_vidc_core_power power; struct msm_vidc_ssr ssr; diff --git a/driver/vidc/inc/msm_vidc_driver.h b/driver/vidc/inc/msm_vidc_driver.h index a0d5979264..44ed1c4312 100644 --- a/driver/vidc/inc/msm_vidc_driver.h +++ b/driver/vidc/inc/msm_vidc_driver.h @@ -162,6 +162,11 @@ static inline bool is_realtime_session(struct msm_vidc_inst *inst) return !inst->capabilities->cap[PRIORITY].value; } +static inline bool is_lowlatency_session(struct msm_vidc_inst *inst) +{ + return !!(inst->capabilities->cap[LOWLATENCY_MODE].value); +} + static inline bool is_active_session(u64 prev, u64 curr) { u64 ts_delta; @@ -270,7 +275,7 @@ int msm_vidc_map_driver_buf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf); int msm_vidc_put_driver_buf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf); -int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct vb2_buffer *vb2); +int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer *vb2); int msm_vidc_destroy_internal_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buffer); void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst); @@ -317,5 +322,6 @@ int msm_vidc_init_instance_caps(struct msm_vidc_core* core); int msm_vidc_deinit_core_caps(struct msm_vidc_core* core); int msm_vidc_deinit_instance_caps(struct msm_vidc_core* core); int msm_vidc_update_debug_str(struct msm_vidc_inst *inst); +bool msm_vidc_allow_decode_batch(struct msm_vidc_inst *inst); #endif // _MSM_VIDC_DRIVER_H_ diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index ab8e485beb..87b7a62e26 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -307,6 +307,7 @@ enum msm_vidc_inst_capability_type { MBPF, LOSSLESS_MBPF, BATCH_MBPF, + BATCH_FPS, SECURE_MBPF, MBPS, POWER_SAVE_MBPS, diff --git a/driver/vidc/src/msm_vdec.c b/driver/vidc/src/msm_vdec.c index ed2a6f8b10..f450ae98f8 100644 --- a/driver/vidc/src/msm_vdec.c +++ b/driver/vidc/src/msm_vdec.c @@ -18,6 +18,9 @@ #include "msm_vidc_control.h" #include "venus_hfi.h" #include "hfi_packet.h" +/* TODO: update based on clips */ +#define MAX_DEC_BATCH_SIZE 6 +#define SKIP_BATCH_WINDOW 100 u32 msm_vdec_subscribe_for_psc_avc[] = { HFI_PROP_BITSTREAM_RESOLUTION, @@ -206,7 +209,7 @@ static int msm_vdec_set_bit_depth(struct msm_vidc_inst *inst, bitdepth = 10 << 16 | 10; inst->subcr_params[port].bit_depth = bitdepth; - inst->capabilities->cap[BIT_DEPTH].value = bitdepth; + msm_vidc_update_cap_value(inst, BIT_DEPTH, bitdepth, __func__); i_vpr_h(inst, "%s: bit depth: %d", __func__, bitdepth); rc = venus_hfi_session_property(inst, HFI_PROP_LUMA_CHROMA_BIT_DEPTH, @@ -1393,17 +1396,17 @@ static int msm_vdec_read_input_subcr_params(struct msm_vidc_inst *inst) inst->crop.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width - ((subsc_params.crop_offsets[1] >> 16) & 0xFFFF); - inst->capabilities->cap[PROFILE].value = subsc_params.profile; - inst->capabilities->cap[LEVEL].value = subsc_params.level; - inst->capabilities->cap[HEVC_TIER].value = subsc_params.tier; - inst->capabilities->cap[POC].value = subsc_params.pic_order_cnt; - inst->capabilities->cap[BIT_DEPTH].value = subsc_params.bit_depth; + msm_vidc_update_cap_value(inst, PROFILE, subsc_params.profile, __func__); + msm_vidc_update_cap_value(inst, LEVEL, subsc_params.level, __func__); + msm_vidc_update_cap_value(inst, HEVC_TIER, subsc_params.tier, __func__); + msm_vidc_update_cap_value(inst, POC, subsc_params.pic_order_cnt, __func__); + msm_vidc_update_cap_value(inst, BIT_DEPTH, subsc_params.bit_depth, __func__); if (subsc_params.coded_frames & HFI_BITMASK_FRAME_MBS_ONLY_FLAG) - inst->capabilities->cap[CODED_FRAMES].value = - CODED_FRAMES_PROGRESSIVE; + msm_vidc_update_cap_value(inst, CODED_FRAMES, CODED_FRAMES_PROGRESSIVE, __func__); else - inst->capabilities->cap[CODED_FRAMES].value = - CODED_FRAMES_INTERLACE; + msm_vidc_update_cap_value(inst, CODED_FRAMES, CODED_FRAMES_INTERLACE, __func__); + + inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst); return 0; } @@ -1543,6 +1546,8 @@ int msm_vdec_streamon_input(struct msm_vidc_inst *inst) if (rc) goto error; + inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst); + return 0; error: @@ -1551,6 +1556,33 @@ error: return rc; } +static int schedule_batch_work(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + cancel_delayed_work(&inst->decode_batch.work); + queue_delayed_work(core->batch_workq, &inst->decode_batch.work, + msecs_to_jiffies(core->capabilities[DECODE_BATCH_TIMEOUT].value)); + + return 0; +} + +static int cancel_batch_work(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + cancel_delayed_work(&inst->decode_batch.work); + + return 0; +} + int msm_vdec_streamoff_output(struct msm_vidc_inst *inst) { int rc = 0; @@ -1560,6 +1592,8 @@ int msm_vdec_streamoff_output(struct msm_vidc_inst *inst) return -EINVAL; } + /* cancel pending batch work */ + cancel_batch_work(inst); rc = msm_vidc_session_streamoff(inst, OUTPUT_PORT); if (rc) return rc; @@ -1754,6 +1788,8 @@ int msm_vdec_streamon_output(struct msm_vidc_inst *inst) if (rc) goto error; + inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst); + return 0; error: @@ -1765,13 +1801,43 @@ error: static int msm_vdec_qbuf_batch(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) { - int rc = 0; + struct msm_vidc_buffer *buf; + enum msm_vidc_allow allow; + int count, rc; - if (!inst || !vb2) { + if (!inst || !vb2 || !inst->decode_batch.size) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } - i_vpr_h(inst, "%s()\n", __func__); + + buf = msm_vidc_get_driver_buf(inst, vb2); + 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) { + print_vidc_buffer(VIDC_HIGH, "high", "qbuf deferred", inst, buf); + return 0; + } + + /* do not defer buffers initially to avoid latency issues */ + if (inst->power.buffer_counter > SKIP_BATCH_WINDOW) { + count = msm_vidc_num_buffers(inst, MSM_VIDC_BUF_OUTPUT, MSM_VIDC_ATTR_DEFERRED); + if (count < inst->decode_batch.size) { + print_vidc_buffer(VIDC_HIGH, "high", "batch-qbuf deferred", inst, buf); + schedule_batch_work(inst); + return 0; + } + + cancel_batch_work(inst); + } + + rc = msm_vidc_queue_buffer_batch(inst); + if (rc) + return rc; return rc; } @@ -1780,10 +1846,16 @@ int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) { int rc = 0; - if (inst->decode_batch.enable) + if (!inst || !vb2) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* batch decoder output & meta buffer only */ + if (inst->decode_batch.enable && vb2->type == OUTPUT_MPLANE) rc = msm_vdec_qbuf_batch(inst, vb2); else - rc = msm_vidc_queue_buffer(inst, vb2); + rc = msm_vidc_queue_buffer_single(inst, vb2); return rc; } @@ -2142,11 +2214,9 @@ set_default: i_vpr_h(inst, "%s: type %u value %#x\n", __func__, s_parm->type, q16_rate); - if (is_frame_rate) { - capability->cap[FRAME_RATE].value = q16_rate; - } else { - capability->cap[OPERATING_RATE].value = q16_rate; - } + msm_vidc_update_cap_value(inst, + is_frame_rate ? FRAME_RATE : OPERATING_RATE, + q16_rate, __func__); exit: return rc; @@ -2290,6 +2360,10 @@ int msm_vdec_inst_init(struct msm_vidc_inst *inst) core = inst->core; INIT_DELAYED_WORK(&inst->decode_batch.work, msm_vidc_batch_handler); + if (core->capabilities[DECODE_BATCH].value) { + inst->decode_batch.enable = true; + inst->decode_batch.size = MAX_DEC_BATCH_SIZE; + } f = &inst->fmts[INPUT_PORT]; f->type = INPUT_MPLANE; @@ -2372,6 +2446,8 @@ int msm_vdec_inst_deinit(struct msm_vidc_inst *inst) d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } + /* cancel pending batch work */ + cancel_batch_work(inst); rc = msm_vidc_ctrl_deinit(inst); return rc; diff --git a/driver/vidc/src/msm_venc.c b/driver/vidc/src/msm_venc.c index 138e30f637..c968573c17 100644 --- a/driver/vidc/src/msm_venc.c +++ b/driver/vidc/src/msm_venc.c @@ -353,10 +353,8 @@ static int msm_venc_set_csc(struct msm_vidc_inst* inst, return -EINVAL; } - if (msm_venc_csc_required(inst)) - inst->capabilities->cap[CSC].value = 1; - else - inst->capabilities->cap[CSC].value = 0; + msm_vidc_update_cap_value(inst, CSC, + msm_venc_csc_required(inst) ? 1 : 0, __func__); csc = inst->capabilities->cap[CSC].value; i_vpr_h(inst, "%s: csc: %u\n", __func__, csc); @@ -955,7 +953,7 @@ int msm_venc_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) { int rc = 0; - rc = msm_vidc_queue_buffer(inst, vb2); + rc = msm_vidc_queue_buffer_single(inst, vb2); if (rc) return rc; @@ -1590,12 +1588,9 @@ set_default: i_vpr_h(inst, "%s: type %u value %#x\n", __func__, s_parm->type, q16_rate); - if (!is_frame_rate) { - capability->cap[OPERATING_RATE].value = q16_rate; - goto exit; - } else { - capability->cap[FRAME_RATE].value = q16_rate; - } + msm_vidc_update_cap_value(inst, + is_frame_rate ? FRAME_RATE : OPERATING_RATE, + q16_rate, __func__); /* * In static case, frame rate is set via diff --git a/driver/vidc/src/msm_vidc_control.c b/driver/vidc/src/msm_vidc_control.c index d7904af970..9b55cceaa4 100644 --- a/driver/vidc/src/msm_vidc_control.c +++ b/driver/vidc/src/msm_vidc_control.c @@ -359,9 +359,14 @@ static bool is_parent_available(struct msm_vidc_inst* inst, return false; } -static int msm_vidc_update_cap_value(struct msm_vidc_inst* inst, u32 cap, +int msm_vidc_update_cap_value(struct msm_vidc_inst *inst, u32 cap, s32 adjusted_val, const char *func) { + if (!inst || !inst->capabilities) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + if (inst->capabilities->cap[cap].value != adjusted_val) i_vpr_h(inst, "%s: updated database value from %#x to %#x\n", @@ -508,7 +513,7 @@ static int msm_vidc_adjust_dynamic_property(struct msm_vidc_inst *inst, if (rc) goto exit; } else if (ctrl) { - capability->cap[cap_id].value = ctrl->val; + msm_vidc_update_cap_value(inst, cap_id, ctrl->val, __func__); } /* add children if cap value modified */ @@ -741,7 +746,7 @@ int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl) capability->cap[cap_id].flags |= CAP_FLAG_CLIENT_SET; /* Static setting */ if (!inst->vb2q[OUTPUT_PORT].streaming) { - capability->cap[cap_id].value = ctrl->val; + msm_vidc_update_cap_value(inst, cap_id, ctrl->val, __func__); if (is_meta_ctrl(ctrl->id)) msm_vidc_update_meta_port_settings(inst); diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index 5d58e707ac..b8ecd4f062 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -11,6 +11,7 @@ #include "msm_vidc_driver.h" #include "msm_vidc_platform.h" #include "msm_vidc_internal.h" +#include "msm_vidc_control.h" #include "msm_vidc_memory.h" #include "msm_vidc_debug.h" #include "msm_vidc_power.h" @@ -20,6 +21,7 @@ #include "venus_hfi.h" #include "venus_hfi_response.h" #include "hfi_packet.h" +extern struct msm_vidc_core *g_core; #define COUNT_BITS(a, out) { \ while ((a) >= 1) { \ @@ -1024,6 +1026,8 @@ bool 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) { + int port = 0; + if (!inst) { d_vpr_e("%s: invalid params\n", __func__); return MSM_VIDC_DISALLOW; @@ -1032,6 +1036,15 @@ enum msm_vidc_allow msm_vidc_allow_qbuf(struct msm_vidc_inst *inst, u32 type) i_vpr_e(inst, "%s: inst in error state\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->vb2q[port].streaming) + return MSM_VIDC_DEFER; + if (type == INPUT_META_PLANE || type == OUTPUT_META_PLANE) return MSM_VIDC_DEFER; @@ -1679,6 +1692,9 @@ struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst, buf->attr &= MSM_VIDC_ATTR_READ_ONLY; } + /* treat every buffer as deferred buffer initially */ + buf->attr |= MSM_VIDC_ATTR_DEFERRED; + rc = vb2_buffer_to_driver(vb2, buf); if (rc) goto error; @@ -1736,7 +1752,7 @@ bool msm_vidc_is_super_buffer(struct msm_vidc_inst *inst) struct msm_vidc_inst_capability *capability = NULL; if (!inst || !inst->capabilities) { - i_vpr_e(inst, "%s: Invalid params\n", __func__); + d_vpr_e("%s: Invalid params\n", __func__); return false; } @@ -1745,49 +1761,98 @@ bool msm_vidc_is_super_buffer(struct msm_vidc_inst *inst) return !!capability->cap[SUPER_FRAME].value; } -int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) +static bool is_single_session(struct msm_vidc_inst *inst) { - int rc = 0; - struct msm_vidc_buffer *buf; - struct msm_vidc_buffer *meta; - enum msm_vidc_allow allow; - int port; + struct msm_vidc_core *core; + u32 count = 0; - if (!inst || !vb2) { + if (!inst) { + d_vpr_e("%s: Invalid params\n", __func__); + return false; + } + core = inst->core; + + core_lock(core, __func__); + list_for_each_entry(inst, &core->instances, list) + count++; + core_unlock(core, __func__); + + return count == 1; +} + +bool msm_vidc_allow_decode_batch(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + bool allow = false; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + + allow = inst->decode_batch.enable; + if (!allow) { + i_vpr_h(inst, "%s: batching already disabled\n", __func__); + goto exit; + } + + allow = core->capabilities[DECODE_BATCH].value; + if (!allow) { + i_vpr_h(inst, "%s: core doesn't support batching\n", __func__); + goto exit; + } + + allow = is_single_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: multiple sessions running\n", __func__); + goto exit; + } + + allow = is_decode_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: not a decoder session\n", __func__); + goto exit; + } + + allow = !is_thumbnail_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: thumbnail session\n", __func__); + goto exit; + } + + allow = is_realtime_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: non-realtime session\n", __func__); + goto exit; + } + + allow = !is_lowlatency_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: lowlatency session\n", __func__); + goto exit; + } + +exit: + i_vpr_h(inst, "%s: batching %s\n", __func__, allow ? "enabled" : "disabled"); + + return allow; +} + +static int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf) +{ + struct msm_vidc_buffer *meta; + int rc = 0; + + if (!inst || !buf || !inst->capabilities) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } - buf = msm_vidc_get_driver_buf(inst, vb2); - if (!buf) - return -EINVAL; - - /* skip queuing if streamon not completed */ - port = v4l2_type_to_driver_port(inst, vb2->type, __func__); - if (port < 0) - 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; - } - - if (!inst->vb2q[port].streaming || allow == MSM_VIDC_DEFER) { - buf->attr |= MSM_VIDC_ATTR_DEFERRED; - print_vidc_buffer(VIDC_HIGH, "high", "qbuf deferred", inst, buf); - return 0; - } - - if (is_decode_session(inst) && - inst->capabilities->cap[CODEC_CONFIG].value) { + if (is_decode_session(inst) && is_input_buffer(buf->type) && + inst->capabilities->cap[CODEC_CONFIG].value) { buf->flags |= MSM_VIDC_BUF_FLAG_CODECCONFIG; - inst->capabilities->cap[CODEC_CONFIG].value = 0; - } - - if (buf->type == MSM_VIDC_BUF_INPUT) { - inst->power.buffer_counter++; - msm_vidc_scale_power(inst, true); + msm_vidc_update_cap_value(inst, CODEC_CONFIG, 0, __func__); } print_vidc_buffer(VIDC_HIGH, "high", "qbuf", inst, buf); @@ -1819,6 +1884,70 @@ int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) else if (buf->type == MSM_VIDC_BUF_OUTPUT) msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FTB); + return 0; +} + +int msm_vidc_queue_buffer_batch(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf; + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_OUTPUT, __func__); + if (!buffers) + return -EINVAL; + + msm_vidc_scale_power(inst, true); + + list_for_each_entry(buf, &buffers->list, list) { + if (!(buf->attr & MSM_VIDC_ATTR_DEFERRED)) + continue; + rc = msm_vidc_queue_buffer(inst, buf); + if (rc) + return rc; + } + + return 0; +} + +int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) +{ + int rc = 0; + struct msm_vidc_buffer *buf; + enum msm_vidc_allow allow; + + if (!inst || !vb2) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + buf = msm_vidc_get_driver_buf(inst, vb2); + 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) { + print_vidc_buffer(VIDC_HIGH, "high", "qbuf deferred", inst, buf); + return 0; + } + + if (buf->type == MSM_VIDC_BUF_INPUT) { + inst->power.buffer_counter++; + msm_vidc_scale_power(inst, true); + } + + rc = msm_vidc_queue_buffer(inst, buf); + if (rc) + return rc; + return rc; } @@ -2558,6 +2687,9 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, rc = -EINVAL; goto error; } + + /* flush deferred buffers */ + msm_vidc_flush_buffers(inst, buffer_type); return 0; error: @@ -3106,6 +3238,39 @@ 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; + int rc = 0; + + inst = container_of(work, struct msm_vidc_inst, decode_batch.work.work); + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: failled. Session error\n", __func__); + goto exit; + } + + allow = msm_vidc_allow_qbuf(inst, OUTPUT_MPLANE); + if (allow != MSM_VIDC_ALLOW) { + i_vpr_e(inst, "%s: not allowed in state: %s\n", __func__, state_name(inst->state)); + goto exit; + } + + i_vpr_h(inst, "%s: queue pending batch buffers\n", __func__); + rc = msm_vidc_queue_buffer_batch(inst); + if (rc) { + i_vpr_e(inst, "%s: batch qbufs failed\n", __func__); + msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + } + +exit: + inst_unlock(inst, __func__); + put_inst(inst); } int msm_vidc_flush_buffers(struct msm_vidc_inst* inst, diff --git a/driver/vidc/src/msm_vidc_probe.c b/driver/vidc/src/msm_vidc_probe.c index 8f9dcdc5f0..6955846806 100644 --- a/driver/vidc/src/msm_vidc_probe.c +++ b/driver/vidc/src/msm_vidc_probe.c @@ -180,12 +180,19 @@ static int msm_vidc_deinitialize_core(struct msm_vidc_core *core) mutex_destroy(&core->lock); msm_vidc_change_core_state(core, MSM_VIDC_CORE_DEINIT, __func__); + if (core->batch_workq) + destroy_workqueue(core->batch_workq); + if (core->pm_workq) destroy_workqueue(core->pm_workq); if (core->device_workq) destroy_workqueue(core->device_workq); + core->batch_workq = NULL; + core->pm_workq = NULL; + core->device_workq = NULL; + return rc; } @@ -211,7 +218,13 @@ static int msm_vidc_initialize_core(struct msm_vidc_core *core) core->pm_workq = create_singlethread_workqueue("pm_workq"); if (!core->pm_workq) { d_vpr_e("%s: create pm workq failed\n", __func__); - destroy_workqueue(core->device_workq); + rc = -EINVAL; + goto exit; + } + + core->batch_workq = create_singlethread_workqueue("batch_workq"); + if (!core->batch_workq) { + d_vpr_e("%s: create batch workq failed\n", __func__); rc = -EINVAL; goto exit; } @@ -224,10 +237,20 @@ static int msm_vidc_initialize_core(struct msm_vidc_core *core) INIT_WORK(&core->smmu_fault_work, msm_vidc_smmu_fault_work_handler); INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler); INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler); - INIT_DELAYED_WORK(&core->batch_work, msm_vidc_batch_handler); INIT_WORK(&core->ssr_work, msm_vidc_ssr_handler); + return 0; exit: + if (core->batch_workq) + destroy_workqueue(core->batch_workq); + if (core->pm_workq) + destroy_workqueue(core->pm_workq); + if (core->device_workq) + destroy_workqueue(core->device_workq); + core->batch_workq = NULL; + core->pm_workq = NULL; + core->device_workq = NULL; + return rc; }