diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 05232f862e55..fdf6e1b1c5d0 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -2290,6 +2290,8 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) rc = -ENOTSUPP; break; } + + msm_dcvs_try_enable(inst); msm_comm_scale_clocks_and_bus(inst); break; case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT: diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 5eb287a28bbd..99f30d9cb97b 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1665,7 +1665,6 @@ static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst) goto fail_power_mode_set; } inst->flags |= VIDC_LOW_POWER; - msm_dcvs_enc_set_power_save_mode(inst, true); dprintk(VIDC_INFO, "Power Save Mode set for inst: %pK\n", inst); } @@ -2939,6 +2938,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) break; } + msm_dcvs_try_enable(inst); msm_comm_scale_clocks_and_bus(inst); break; case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT: @@ -3052,8 +3052,6 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } pdata = &venc_mode; - msm_dcvs_enc_set_power_save_mode(inst, - ctrl->val == V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE); break; case V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS: if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_HEVC) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 10dcc30f4aaa..566441e9c546 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1239,8 +1239,6 @@ static void handle_event_change(enum hal_command_response cmd, void *data) inst->prop.width[OUTPUT_PORT] = event_notify->width; } - inst->seqchanged_count++; - if (inst->session_type == MSM_VIDC_DECODER) msm_dcvs_init_load(inst); @@ -2227,11 +2225,32 @@ void handle_cmd_response(enum hal_command_response cmd, void *data) int msm_comm_scale_clocks(struct msm_vidc_core *core) { - int num_mbs_per_sec = - msm_comm_get_load(core, MSM_VIDC_ENCODER, LOAD_CALC_NO_QUIRKS) + + int num_mbs_per_sec, enc_mbs_per_sec, dec_mbs_per_sec; + + enc_mbs_per_sec = + msm_comm_get_load(core, MSM_VIDC_ENCODER, LOAD_CALC_NO_QUIRKS); + dec_mbs_per_sec = msm_comm_get_load(core, MSM_VIDC_DECODER, LOAD_CALC_NO_QUIRKS); + + if (enc_mbs_per_sec >= dec_mbs_per_sec) { + /* + * If Encoder load is higher, use that load. Encoder votes for higher + * clock. Since Encoder and Deocder run on parallel cores, this clock + * should suffice decoder usecases. + */ + num_mbs_per_sec = enc_mbs_per_sec; + } else { + /* + * If Decoder load is higher, it's tricky to decide clock. Decoder + * higher load might results less clocks than Encoder smaller load. + * At this point driver doesn't know which clock to vote. Hence use + * total load. + */ + num_mbs_per_sec = enc_mbs_per_sec + dec_mbs_per_sec; + } + return msm_comm_scale_clocks_load(core, num_mbs_per_sec, - LOAD_CALC_NO_QUIRKS); + LOAD_CALC_NO_QUIRKS); } int msm_comm_scale_clocks_load(struct msm_vidc_core *core, @@ -4896,6 +4915,9 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) return -ENOTSUPP; } + if (!rc) + msm_dcvs_try_enable(inst); + if (!rc) { if (inst->prop.width[CAPTURE_PORT] < capability->width.min || inst->prop.height[CAPTURE_PORT] < @@ -5205,6 +5227,7 @@ int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a) msm_dcvs_init_load(inst); } msm_comm_scale_clocks_and_bus(inst); + msm_dcvs_try_enable(inst); } exit: return rc; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c index c03f887be6f6..9e67ef096c63 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c @@ -20,10 +20,19 @@ ((__cur_mbpf) >= (__min_mbpf)) static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst); -static bool msm_dcvs_enc_check(struct msm_vidc_inst *inst); static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst); static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd); +int msm_dcvs_try_enable(struct msm_vidc_inst *inst) +{ + if (!inst) { + dprintk(VIDC_ERR, "%s: Invalid args: %p\n", __func__, inst); + return -EINVAL; + } + inst->dcvs_mode = msm_dcvs_check_supported(inst); + return 0; +} + static inline int msm_dcvs_get_mbs_per_frame(struct msm_vidc_inst *inst) { int height, width; @@ -41,20 +50,27 @@ static inline int msm_dcvs_get_mbs_per_frame(struct msm_vidc_inst *inst) return NUM_MBS_PER_FRAME(height, width); } -static inline int msm_dcvs_count_active_instances(struct msm_vidc_core *core) +static inline int msm_dcvs_count_active_instances(struct msm_vidc_core *core, + enum session_type session_type) { int active_instances = 0; - struct msm_vidc_inst *inst = NULL; + struct msm_vidc_inst *temp = NULL; if (!core) { dprintk(VIDC_ERR, "%s: Invalid args: %pK\n", __func__, core); return -EINVAL; } + /* DCVS condition is as following + * Decoder DCVS : Only for ONE decoder session. + * Encoder DCVS : Only for ONE encoder session + ONE decoder session + */ mutex_lock(&core->lock); - list_for_each_entry(inst, &core->instances, list) { - if (inst->state >= MSM_VIDC_OPEN_DONE && - inst->state < MSM_VIDC_STOP_DONE) + list_for_each_entry(temp, &core->instances, list) { + if (temp->state >= MSM_VIDC_OPEN_DONE && + temp->state < MSM_VIDC_STOP_DONE && + (temp->session_type == session_type || + temp->session_type == MSM_VIDC_ENCODER)) active_instances++; } mutex_unlock(&core->lock); @@ -112,17 +128,12 @@ static void msm_dcvs_enc_check_and_scale_clocks(struct msm_vidc_inst *inst) { int rc = 0; - if (inst->session_type == MSM_VIDC_ENCODER && msm_vidc_enc_dcvs_mode) { - inst->dcvs_mode = msm_dcvs_check_supported(inst); - dprintk(VIDC_DBG, "%s: session DCVS %s supported\n", - __func__, inst->dcvs_mode ? "" : "not"); - - if (inst->dcvs_mode) { - rc = msm_dcvs_enc_scale_clocks(inst); - if (rc) { - dprintk(VIDC_DBG, + if (inst->session_type == MSM_VIDC_ENCODER && + msm_vidc_enc_dcvs_mode) { + rc = msm_dcvs_enc_scale_clocks(inst); + if (rc) { + dprintk(VIDC_DBG, "ENC_DCVS: error while scaling clocks\n"); - } } } } @@ -131,28 +142,14 @@ static void msm_dcvs_dec_check_and_scale_clocks(struct msm_vidc_inst *inst) { int rc = 0; - if (inst->session_type != MSM_VIDC_DECODER || !msm_vidc_dec_dcvs_mode) - return; - - if (msm_dcvs_check_supported(inst)) { - inst->dcvs_mode = true; - dprintk(VIDC_DBG, - "%s: session DCVS supported, decode_dcvs_mode = %d\n", - __func__, inst->dcvs_mode); - } else { - inst->dcvs_mode = false; - dprintk(VIDC_DBG, - "%s: session DCVS not supported, decode_dcvs_mode = %d\n", - __func__, inst->dcvs_mode); - } - - if (msm_vidc_dec_dcvs_mode && inst->dcvs_mode) { + if (inst->session_type == MSM_VIDC_DECODER && + msm_vidc_dec_dcvs_mode) { msm_dcvs_monitor_buffer(inst); rc = msm_dcvs_dec_scale_clocks(inst, false); if (rc) { dprintk(VIDC_ERR, - "%s: Failed to scale clocks in DCVS: %d\n", - __func__, rc); + "%s: Failed to scale clocks in DCVS: %d\n", + __func__, rc); } } } @@ -163,6 +160,11 @@ void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb) dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst); return; } + msm_dcvs_try_enable(inst); + if (!inst->dcvs_mode) { + dprintk(VIDC_DBG, "DCVS is not enabled\n"); + return; + } if (is_etb) msm_dcvs_enc_check_and_scale_clocks(inst); @@ -531,48 +533,6 @@ static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd) return rc; } -static bool msm_dcvs_enc_check(struct msm_vidc_inst *inst) -{ - int num_mbs_per_frame = 0; - long int instance_load = 0; - long int dcvs_limit = 0; - bool dcvs_check_passed = false, is_codec_supported = false; - struct msm_vidc_platform_resources *res = NULL; - - if (!inst || !inst->core) { - dprintk(VIDC_ERR, "%s Invalid params\n", __func__); - return dcvs_check_passed; - } - - res = &inst->core->resources; - if (!res->dcvs_limit) { - dprintk(VIDC_ERR, - "%s Dcvs limit table uninitialized\n", __func__); - return false; - } - - is_codec_supported = - msm_dcvs_check_codec_supported( - inst->fmts[CAPTURE_PORT]->fourcc, - inst->dcvs.supported_codecs, - inst->session_type); - - num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst); - instance_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS); - dcvs_limit = - (long int)res->dcvs_limit[inst->session_type].min_mbpf * - res->dcvs_limit[inst->session_type].fps; - - if (msm_vidc_enc_dcvs_mode && is_codec_supported && - inst->dcvs.is_power_save_mode && - IS_VALID_DCVS_SESSION(num_mbs_per_frame, - res->dcvs_limit[inst->session_type].min_mbpf) && - IS_VALID_DCVS_SESSION(instance_load, dcvs_limit)) { - dcvs_check_passed = true; - } - return dcvs_check_passed; -} - static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst) { int num_mbs_per_frame = 0, instance_count = 0; @@ -583,6 +543,7 @@ static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst) struct hal_buffer_requirements *output_buf_req; struct dcvs_stats *dcvs; bool is_codec_supported = false; + bool is_dcvs_supported = true; struct msm_vidc_platform_resources *res = NULL; if (!inst || !inst->core || !inst->core->device) { @@ -599,104 +560,88 @@ static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst) "%s: dcvs limit table not found\n", __func__); return false; } - instance_count = msm_dcvs_count_active_instances(core); + instance_count = msm_dcvs_count_active_instances(core, + inst->session_type); + num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst); + instance_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS); + dcvs_limit = + (long int)res->dcvs_limit[inst->session_type].min_mbpf * + res->dcvs_limit[inst->session_type].fps; + inst->dcvs.extra_buffer_count = 0; - if (instance_count == 1 && inst->session_type == MSM_VIDC_DECODER && - !msm_comm_turbo_session(inst)) { - num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst); - instance_load = msm_comm_get_inst_load(inst, - LOAD_CALC_NO_QUIRKS); + if (!IS_VALID_DCVS_SESSION(num_mbs_per_frame, + res->dcvs_limit[inst->session_type].min_mbpf)) { + inst->dcvs.extra_buffer_count = 0; + is_dcvs_supported = false; + goto dcvs_decision_done; + + } + + if (inst->session_type == MSM_VIDC_DECODER) { + inst->dcvs.extra_buffer_count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS; output_buf_req = get_buff_req_buffer(inst, - msm_comm_get_hal_output_buffer(inst)); - dcvs_limit = - (long int)res->dcvs_limit[inst->session_type].min_mbpf * - res->dcvs_limit[inst->session_type].fps; - is_codec_supported = - msm_dcvs_check_codec_supported( - inst->fmts[OUTPUT_PORT]->fourcc, - inst->dcvs.supported_codecs, - inst->session_type); - if (!is_codec_supported || - !IS_VALID_DCVS_SESSION(num_mbs_per_frame, - res->dcvs_limit[inst->session_type].min_mbpf) || - !IS_VALID_DCVS_SESSION(instance_load, dcvs_limit) || - inst->seqchanged_count > 1) - return false; - + msm_comm_get_hal_output_buffer(inst)); if (!output_buf_req) { dprintk(VIDC_ERR, - "%s: No buffer requirement for buffer type %x\n", - __func__, HAL_BUFFER_OUTPUT); + "%s: No buffer requirement for buffer type %x\n", + __func__, HAL_BUFFER_OUTPUT); return false; } - } else if (instance_count == 1 && - inst->session_type == MSM_VIDC_ENCODER && - !msm_comm_turbo_session(inst)) { - if (!msm_dcvs_enc_check(inst)) - return false; - } else { - /* - * For multiple instance use case with 4K, clocks will be scaled - * as per load in streamon, but the clocks may be scaled - * down as DCVS is running for first playback instance - * Rescaling the core clock for multiple instance use case - */ - if (!dcvs->is_clock_scaled) { - if (!msm_comm_scale_clocks(core)) { - dcvs->is_clock_scaled = true; - dprintk(VIDC_DBG, - "%s: Scaled clocks = %d\n", - __func__, dcvs->is_clock_scaled); - } else { - dprintk(VIDC_DBG, - "%s: Failed to Scale clocks. Perf might be impacted\n", - __func__); - } + is_codec_supported = + msm_dcvs_check_codec_supported( + inst->fmts[OUTPUT_PORT]->fourcc, + inst->dcvs.supported_codecs, + inst->session_type); + if (!is_codec_supported || + !msm_vidc_dec_dcvs_mode) { + inst->dcvs.extra_buffer_count = 0; + is_dcvs_supported = false; + goto dcvs_decision_done; } - /* - * For multiple instance use case turn OFF DCVS algorithm - * immediately - */ + if (msm_comm_turbo_session(inst) || + !IS_VALID_DCVS_SESSION(instance_load, dcvs_limit || + instance_count > 1)) + is_dcvs_supported = false; + } + if (inst->session_type == MSM_VIDC_ENCODER) { + inst->dcvs.extra_buffer_count = DCVS_ENC_EXTRA_OUTPUT_BUFFERS; + is_codec_supported = + msm_dcvs_check_codec_supported( + inst->fmts[CAPTURE_PORT]->fourcc, + inst->dcvs.supported_codecs, + inst->session_type); + if (!is_codec_supported || + !msm_vidc_enc_dcvs_mode) { + inst->dcvs.extra_buffer_count = 0; + is_dcvs_supported = false; + goto dcvs_decision_done; + } + if (msm_comm_turbo_session(inst) || + !IS_VALID_DCVS_SESSION(instance_load, dcvs_limit || + instance_count > 1)) + is_dcvs_supported = false; + } +dcvs_decision_done: + if (!is_dcvs_supported) { + msm_comm_scale_clocks(core); if (instance_count > 1) { mutex_lock(&core->lock); list_for_each_entry(temp, &core->instances, list) temp->dcvs_mode = false; mutex_unlock(&core->lock); } - - return false; } - - return true; + return is_dcvs_supported; } int msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst) { - int extra_buffer = 0; - if (!inst) { dprintk(VIDC_ERR, "%s Invalid args\n", __func__); return 0; } - if (inst->session_type == MSM_VIDC_ENCODER) { - if (msm_dcvs_enc_check(inst)) - extra_buffer = DCVS_ENC_EXTRA_OUTPUT_BUFFERS; - } else if (inst->session_type == MSM_VIDC_DECODER) { - if (msm_dcvs_check_supported(inst)) - extra_buffer = DCVS_DEC_EXTRA_OUTPUT_BUFFERS; - } - return extra_buffer; + return inst->dcvs.extra_buffer_count; } -void msm_dcvs_enc_set_power_save_mode(struct msm_vidc_inst *inst, - bool is_power_save_mode) -{ - if (!inst) { - dprintk(VIDC_ERR, "%s Invalid args\n", __func__); - return; - } - - inst->dcvs.is_power_save_mode = is_power_save_mode; -} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.h b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.h index 17040166b1e4..d40473976ebb 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -36,6 +36,5 @@ void msm_dcvs_init_load(struct msm_vidc_inst *inst); void msm_dcvs_monitor_buffer(struct msm_vidc_inst *inst); void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb); int msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst); -void msm_dcvs_enc_set_power_save_mode(struct msm_vidc_inst *inst, - bool is_power_save_mode); +int msm_dcvs_try_enable(struct msm_vidc_inst *inst); #endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index 72c1ddcf3a70..b6e74715ad07 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -204,9 +204,9 @@ struct dcvs_stats { int load_high; int min_threshold; int max_threshold; - bool is_clock_scaled; int etb_counter; bool is_power_save_mode; + unsigned int extra_buffer_count; u32 supported_codecs; }; @@ -279,7 +279,6 @@ struct msm_vidc_inst { bool in_reconfig; u32 reconfig_width; u32 reconfig_height; - u32 seqchanged_count; struct dentry *debugfs_root; void *priv; struct msm_vidc_debug debug;