diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt index 50b9b1ac8704..6ca0ac31a581 100644 --- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt +++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt @@ -132,6 +132,9 @@ value is typically max(latencies of every cluster at all power levels) + 1 memory, performance etc. - qcom,debug-timeout = A bool indicating that FW errors such as SYS_ERROR, SESSION_ERROR and timeouts will be treated as Fatal. +- qcom,power-conf = Indicates the value at which or beyond, a video session + is configured in low power mode to have power benefits. Value is defined + interms of HxW of the video session beyond which power benefit is desired. [Second level nodes] Context Banks @@ -226,6 +229,7 @@ Example: qcom,qdss-presets = <0xFC307000 0x1000>, <0xFC322000 0x1000>; qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/ + qcom,power-conf = <8294400>; /* WxH - 3840*2160 */ qcom,never-unload-fw; clock-names = "foo_clk", "bar_clk", "baz_clk"; qcom,clock-configs = <0x3 0x1 0x0>; diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 6127c03df581..7bae34aef6f4 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, 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 @@ -1048,9 +1048,9 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .id = V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE, .name = "Set Encoder performance mode", .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY, + .minimum = V4L2_MPEG_VIDC_VIDEO_PERF_UNINIT, .maximum = V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE, - .default_value = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY, + .default_value = V4L2_MPEG_VIDC_VIDEO_PERF_UNINIT, .step = 1, .qmenu = NULL, }, @@ -1666,9 +1666,10 @@ static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers) static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst) { - u32 rc = 0; - u32 prop_id = 0, power_save_min = 0, power_save_max = 0, inst_load = 0; + u32 rc = 0, height = 0, width = 0; + u32 prop_id = 0, hq_max = 0, power_conf = 0, inst_load = 0; void *pdata = NULL; + bool set_by_client = false, enable_low_power = false; struct hfi_device *hdev = NULL; enum hal_perf_mode venc_mode; enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD | @@ -1679,20 +1680,38 @@ static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst) return -EINVAL; } - inst_load = msm_comm_get_inst_load(inst, quirks); - power_save_min = inst->capability.mbs_per_sec_power_save.min; - power_save_max = inst->capability.mbs_per_sec_power_save.max; - - if (!power_save_min || !power_save_max) - return rc; - hdev = inst->core->device; - if (inst_load >= power_save_min && inst_load <= power_save_max) { + inst_load = msm_comm_get_inst_load(inst, quirks); + hq_max = inst->capability.mbs_per_sec.max; + power_conf = inst->core->resources.power_conf; + height = inst->prop.height[CAPTURE_PORT]; + width = inst->prop.width[CAPTURE_PORT]; + + switch (msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE)) { + case V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY: + case V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE: + set_by_client = true; + break; + } + + if (inst_load > hq_max) { + dprintk(VIDC_INFO, "Setting low power w.r.t core limitation\n"); + enable_low_power = true; + } else if (!set_by_client) { + if (power_conf && width * height >= power_conf) { + dprintk(VIDC_INFO, + "Setting low power w.r.t system power recommendation\n"); + enable_low_power = true; + } + } + + if (enable_low_power) { prop_id = HAL_CONFIG_VENC_PERF_MODE; venc_mode = HAL_PERF_MODE_POWER_SAVE; pdata = &venc_mode; rc = call_hfi_op(hdev, session_set_property, - (void *)inst->session, prop_id, pdata); + (void *)inst->session, prop_id, pdata); if (rc) { dprintk(VIDC_ERR, "%s: Failed to set power save mode for inst: %pK\n", @@ -3143,7 +3162,6 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) break; } pdata = &venc_mode; - 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_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index a3080be8cd7a..022c776a6096 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, 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 @@ -1084,6 +1084,13 @@ int read_platform_resources_from_dt( goto err_load_max_hw_load; } + rc = of_property_read_u32(pdev->dev.of_node, "qcom,power-conf", + &res->power_conf); + if (rc) { + dprintk(VIDC_DBG, + "Failed to read power configuration: %d\n", rc); + } + rc = msm_vidc_populate_legacy_context_bank(res); if (rc) { dprintk(VIDC_ERR, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index 734586a3f76c..03b31d7fd9d1 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, 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 @@ -173,6 +173,7 @@ struct msm_vidc_platform_resources { uint32_t imem_size; enum imem_type imem_type; uint32_t max_load; + uint32_t power_conf; struct platform_device *pdev; struct regulator_set regulator_set; struct clock_set clock_set; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 8fdf57504ab6..c8653a9f0e9e 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -1058,6 +1058,9 @@ enum vl42_mpeg_vidc_video_h264_svc_nal { (V4L2_CID_MPEG_MSM_VIDC_BASE + 68) enum v4l2_mpeg_vidc_video_perf_mode { +#define V4L2_MPEG_VIDC_VIDEO_PERF_UNINIT \ + V4L2_MPEG_VIDC_VIDEO_PERF_UNINIT + V4L2_MPEG_VIDC_VIDEO_PERF_UNINIT = 0, V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY = 1, V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE = 2 };