summaryrefslogtreecommitdiff
path: root/drivers/media/platform/qcom/venus/pm_helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/qcom/venus/pm_helpers.c')
-rw-r--r--drivers/media/platform/qcom/venus/pm_helpers.c465
1 files changed, 351 insertions, 114 deletions
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
index abf93158857b..f0269524ac70 100644
--- a/drivers/media/platform/qcom/venus/pm_helpers.c
+++ b/drivers/media/platform/qcom/venus/pm_helpers.c
@@ -9,7 +9,9 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/types.h>
#include <media/v4l2-mem2mem.h>
@@ -17,6 +19,7 @@
#include "hfi_parser.h"
#include "hfi_venus_io.h"
#include "pm_helpers.h"
+#include "hfi_platform.h"
static bool legacy_binding;
@@ -37,11 +40,31 @@ static int core_clks_get(struct venus_core *core)
static int core_clks_enable(struct venus_core *core)
{
+ const struct freq_tbl *freq_tbl = core->res->freq_tbl;
+ unsigned int freq_tbl_size = core->res->freq_tbl_size;
const struct venus_resources *res = core->res;
+ struct device *dev = core->dev;
+ unsigned long freq = 0;
+ struct dev_pm_opp *opp;
unsigned int i;
int ret;
+ opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+ if (IS_ERR(opp)) {
+ if (!freq_tbl)
+ return -ENODEV;
+ freq = freq_tbl[freq_tbl_size - 1].freq;
+ } else {
+ dev_pm_opp_put(opp);
+ }
+
for (i = 0; i < res->clks_num; i++) {
+ if (IS_V6(core) || (IS_V4(core) && is_lite(core))) {
+ ret = clk_set_rate(core->clks[i], freq);
+ if (ret)
+ goto err;
+ }
+
ret = clk_prepare_enable(core->clks[i]);
if (ret)
goto err;
@@ -66,10 +89,9 @@ static void core_clks_disable(struct venus_core *core)
static int core_clks_set_rate(struct venus_core *core, unsigned long freq)
{
- struct clk *clk = core->clks[0];
int ret;
- ret = clk_set_rate(clk, freq);
+ ret = dev_pm_opp_set_rate(core->dev, freq);
if (ret)
return ret;
@@ -147,14 +169,12 @@ static u32 load_per_type(struct venus_core *core, u32 session_type)
struct venus_inst *inst = NULL;
u32 mbs_per_sec = 0;
- mutex_lock(&core->lock);
list_for_each_entry(inst, &core->instances, list) {
if (inst->session_type != session_type)
continue;
mbs_per_sec += load_per_instance(inst);
}
- mutex_unlock(&core->lock);
return mbs_per_sec;
}
@@ -185,7 +205,7 @@ static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak)
return;
for (i = 0; i < num_rows; i++) {
- if (mbs > bw_tbl[i].mbs_per_sec)
+ if (i != 0 && mbs > bw_tbl[i].mbs_per_sec)
break;
if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) {
@@ -203,16 +223,24 @@ static int load_scale_bw(struct venus_core *core)
struct venus_inst *inst = NULL;
u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0;
- mutex_lock(&core->lock);
list_for_each_entry(inst, &core->instances, list) {
mbs_per_sec = load_per_instance(inst);
mbs_to_bw(inst, mbs_per_sec, &avg, &peak);
total_avg += avg;
total_peak += peak;
}
- mutex_unlock(&core->lock);
- dev_dbg(core->dev, "total: avg_bw: %u, peak_bw: %u\n",
+ /*
+ * keep minimum bandwidth vote for "video-mem" path,
+ * so that clks can be disabled during vdec_session_release().
+ * Actual bandwidth drop will be done during device supend
+ * so that device can power down without any warnings.
+ */
+
+ if (!total_avg && !total_peak)
+ total_avg = kbps_to_icc(1000);
+
+ dev_dbg(core->dev, VDBGL "total: avg_bw: %u, peak_bw: %u\n",
total_avg, total_peak);
return icc_set_bw(core->video_path, total_avg, total_peak);
@@ -227,8 +255,9 @@ static int load_scale_v1(struct venus_inst *inst)
struct device *dev = core->dev;
u32 mbs_per_sec;
unsigned int i;
- int ret;
+ int ret = 0;
+ mutex_lock(&core->lock);
mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) +
load_per_type(core, VIDC_SESSION_TYPE_DEC);
@@ -253,29 +282,42 @@ set_freq:
if (ret) {
dev_err(dev, "failed to set clock rate %lu (%d)\n",
freq, ret);
- return ret;
+ goto exit;
}
ret = load_scale_bw(core);
if (ret) {
dev_err(dev, "failed to set bandwidth (%d)\n",
ret);
- return ret;
+ goto exit;
}
- return 0;
+exit:
+ mutex_unlock(&core->lock);
+ return ret;
}
-static int core_get_v1(struct device *dev)
+static int core_get_v1(struct venus_core *core)
{
- struct venus_core *core = dev_get_drvdata(dev);
+ int ret;
- return core_clks_get(core);
+ ret = core_clks_get(core);
+ if (ret)
+ return ret;
+
+ ret = devm_pm_opp_set_clkname(core->dev, "core");
+ if (ret)
+ return ret;
+
+ return 0;
}
-static int core_power_v1(struct device *dev, int on)
+static void core_put_v1(struct venus_core *core)
+{
+}
+
+static int core_power_v1(struct venus_core *core, int on)
{
- struct venus_core *core = dev_get_drvdata(dev);
int ret = 0;
if (on == POWER_ON)
@@ -288,6 +330,7 @@ static int core_power_v1(struct device *dev, int on)
static const struct venus_pm_ops pm_ops_v1 = {
.core_get = core_get_v1,
+ .core_put = core_put_v1,
.core_power = core_power_v1,
.load_scale = load_scale_v1,
};
@@ -298,9 +341,9 @@ vcodec_control_v3(struct venus_core *core, u32 session_type, bool enable)
void __iomem *ctrl;
if (session_type == VIDC_SESSION_TYPE_DEC)
- ctrl = core->base + WRAPPER_VDEC_VCODEC_POWER_CONTROL;
+ ctrl = core->wrapper_base + WRAPPER_VDEC_VCODEC_POWER_CONTROL;
else
- ctrl = core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL;
+ ctrl = core->wrapper_base + WRAPPER_VENC_VCODEC_POWER_CONTROL;
if (enable)
writel(0, ctrl);
@@ -360,6 +403,7 @@ static int venc_power_v3(struct device *dev, int on)
static const struct venus_pm_ops pm_ops_v3 = {
.core_get = core_get_v1,
+ .core_put = core_put_v1,
.core_power = core_power_v1,
.vdec_get = vdec_get_v3,
.vdec_power = vdec_power_v3,
@@ -374,12 +418,22 @@ static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable)
u32 val;
int ret;
+ ret = dev_pm_genpd_set_hwmode(core->pmdomains->pd_devs[coreid], !enable);
+ if (ret == -EOPNOTSUPP) {
+ core->hwmode_dev = false;
+ goto legacy;
+ }
+
+ core->hwmode_dev = true;
+ return ret;
+
+legacy:
if (coreid == VIDC_CORE_ID_1) {
- ctrl = core->base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL;
- stat = core->base + WRAPPER_VCODEC0_MMCC_POWER_STATUS;
+ ctrl = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL;
+ stat = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_STATUS;
} else {
- ctrl = core->base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL;
- stat = core->base + WRAPPER_VCODEC1_MMCC_POWER_STATUS;
+ ctrl = core->wrapper_base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL;
+ stat = core->wrapper_base + WRAPPER_VCODEC1_MMCC_POWER_STATUS;
}
if (enable) {
@@ -410,11 +464,13 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
vcodec_clks_disable(core, core->vcodec0_clks);
- ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
- if (ret)
- return ret;
+ if (!core->hwmode_dev) {
+ ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
+ if (ret)
+ return ret;
+ }
- ret = pm_runtime_put_sync(core->pmdomains[1]);
+ ret = pm_runtime_put_sync(core->pmdomains->pd_devs[1]);
if (ret < 0)
return ret;
}
@@ -426,11 +482,13 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
vcodec_clks_disable(core, core->vcodec1_clks);
- ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
- if (ret)
- return ret;
+ if (!core->hwmode_dev) {
+ ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
+ if (ret)
+ return ret;
+ }
- ret = pm_runtime_put_sync(core->pmdomains[2]);
+ ret = pm_runtime_put_sync(core->pmdomains->pd_devs[2]);
if (ret < 0)
return ret;
}
@@ -443,7 +501,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
int ret;
if (coreid_mask & VIDC_CORE_ID_1) {
- ret = pm_runtime_get_sync(core->pmdomains[1]);
+ ret = pm_runtime_get_sync(core->pmdomains->pd_devs[1]);
if (ret < 0)
return ret;
@@ -461,7 +519,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
}
if (coreid_mask & VIDC_CORE_ID_2) {
- ret = pm_runtime_get_sync(core->pmdomains[2]);
+ ret = pm_runtime_get_sync(core->pmdomains->pd_devs[2]);
if (ret < 0)
return ret;
@@ -481,8 +539,50 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
return 0;
}
+static inline int power_save_mode_enable(struct venus_inst *inst,
+ bool enable)
+{
+ struct venc_controls *enc_ctr = &inst->controls.enc;
+ const u32 ptype = HFI_PROPERTY_CONFIG_VENC_PERF_MODE;
+ u32 venc_mode;
+ int ret = 0;
+
+ if (inst->session_type != VIDC_SESSION_TYPE_ENC)
+ return 0;
+
+ if (enc_ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)
+ enable = false;
+
+ venc_mode = enable ? HFI_VENC_PERFMODE_POWER_SAVE :
+ HFI_VENC_PERFMODE_MAX_QUALITY;
+
+ ret = hfi_session_set_property(inst, ptype, &venc_mode);
+ if (ret)
+ return ret;
+
+ inst->flags = enable ? inst->flags | VENUS_LOW_POWER :
+ inst->flags & ~VENUS_LOW_POWER;
+
+ return ret;
+}
+
+static int move_core_to_power_save_mode(struct venus_core *core,
+ u32 core_id)
+{
+ struct venus_inst *inst = NULL;
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ if (inst->clk_data.core_id == core_id &&
+ inst->session_type == VIDC_SESSION_TYPE_ENC)
+ power_save_mode_enable(inst, true);
+ }
+ mutex_unlock(&core->lock);
+ return 0;
+}
+
static void
-min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
+min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load, bool low_power)
{
u32 mbs_per_sec, load, core1_load = 0, core2_load = 0;
u32 cores_max = core_num_max(inst);
@@ -496,7 +596,18 @@ min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
list_for_each_entry(inst_pos, &core->instances, list) {
if (inst_pos == inst)
continue;
- vpp_freq = inst_pos->clk_data.codec_freq_data->vpp_freq;
+
+ if (inst_pos->state != INST_START)
+ continue;
+
+ if (inst->session_type == VIDC_SESSION_TYPE_DEC)
+ vpp_freq = inst_pos->clk_data.vpp_freq;
+ else if (inst->session_type == VIDC_SESSION_TYPE_ENC)
+ vpp_freq = low_power ? inst_pos->clk_data.low_power_freq :
+ inst_pos->clk_data.vpp_freq;
+ else
+ continue;
+
coreid = inst_pos->clk_data.core_id;
mbs_per_sec = load_per_instance(inst_pos);
@@ -528,9 +639,13 @@ static int decide_core(struct venus_inst *inst)
{
const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
struct venus_core *core = inst->core;
- u32 min_coreid, min_load, inst_load;
+ u32 min_coreid, min_load, cur_inst_load;
+ u32 min_lp_coreid, min_lp_load, cur_inst_lp_load;
struct hfi_videocores_usage_type cu;
- unsigned long max_freq;
+ unsigned long max_freq = ULONG_MAX;
+ struct device *dev = core->dev;
+ struct dev_pm_opp *opp;
+ int ret = 0;
if (legacy_binding) {
if (inst->session_type == VIDC_SESSION_TYPE_DEC)
@@ -544,23 +659,45 @@ static int decide_core(struct venus_inst *inst)
if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT)
return 0;
- inst_load = load_per_instance(inst);
- inst_load *= inst->clk_data.codec_freq_data->vpp_freq;
- max_freq = core->res->freq_tbl[0].freq;
-
- min_loaded_core(inst, &min_coreid, &min_load);
-
- if ((inst_load + min_load) > max_freq) {
- dev_warn(core->dev, "HW is overloaded, needed: %u max: %lu\n",
- inst_load, max_freq);
+ cur_inst_load = load_per_instance(inst);
+ cur_inst_load *= inst->clk_data.vpp_freq;
+ /*TODO : divide this inst->load by work_route */
+
+ cur_inst_lp_load = load_per_instance(inst);
+ cur_inst_lp_load *= inst->clk_data.low_power_freq;
+ /*TODO : divide this inst->load by work_route */
+
+ opp = dev_pm_opp_find_freq_floor(dev, &max_freq);
+ if (!IS_ERR(opp))
+ dev_pm_opp_put(opp);
+
+ min_loaded_core(inst, &min_coreid, &min_load, false);
+ min_loaded_core(inst, &min_lp_coreid, &min_lp_load, true);
+
+ if (cur_inst_load + min_load <= max_freq) {
+ inst->clk_data.core_id = min_coreid;
+ cu.video_core_enable_mask = min_coreid;
+ } else if (cur_inst_lp_load + min_load <= max_freq) {
+ /* Move current instance to LP and return */
+ inst->clk_data.core_id = min_coreid;
+ cu.video_core_enable_mask = min_coreid;
+ power_save_mode_enable(inst, true);
+ } else if (cur_inst_lp_load + min_lp_load <= max_freq) {
+ /* Move all instances to LP mode and return */
+ inst->clk_data.core_id = min_lp_coreid;
+ cu.video_core_enable_mask = min_lp_coreid;
+ move_core_to_power_save_mode(core, min_lp_coreid);
+ } else {
+ dev_warn(core->dev, "HW can't support this load");
return -EINVAL;
}
- inst->clk_data.core_id = min_coreid;
- cu.video_core_enable_mask = min_coreid;
-
done:
- return hfi_session_set_property(inst, ptype, &cu);
+ ret = hfi_session_set_property(inst, ptype, &cu);
+ if (ret)
+ return ret;
+
+ return ret;
}
static int acquire_core(struct venus_inst *inst)
@@ -688,7 +825,7 @@ static int vdec_power_v4(struct device *dev, int on)
else
vcodec_clks_disable(core, core->vcodec0_clks);
- vcodec_control_v4(core, VIDC_CORE_ID_1, false);
+ ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
return ret;
}
@@ -733,62 +870,99 @@ static int venc_power_v4(struct device *dev, int on)
else
vcodec_clks_disable(core, core->vcodec1_clks);
- vcodec_control_v4(core, VIDC_CORE_ID_2, false);
+ ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
return ret;
}
-static int vcodec_domains_get(struct device *dev)
+static int vcodec_domains_get(struct venus_core *core)
{
- struct venus_core *core = dev_get_drvdata(dev);
+ int ret;
+ struct device *dev = core->dev;
const struct venus_resources *res = core->res;
- struct device *pd;
- unsigned int i;
+ struct dev_pm_domain_attach_data vcodec_data = {
+ .pd_names = res->vcodec_pmdomains,
+ .num_pd_names = res->vcodec_pmdomains_num,
+ .pd_flags = PD_FLAG_NO_DEV_LINK,
+ };
+ struct dev_pm_domain_attach_data opp_pd_data = {
+ .pd_names = res->opp_pmdomain,
+ .num_pd_names = 1,
+ .pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP,
+ };
if (!res->vcodec_pmdomains_num)
- return -ENODEV;
+ goto skip_pmdomains;
- for (i = 0; i < res->vcodec_pmdomains_num; i++) {
- pd = dev_pm_domain_attach_by_name(dev,
- res->vcodec_pmdomains[i]);
- if (IS_ERR(pd))
- return PTR_ERR(pd);
- core->pmdomains[i] = pd;
- }
+ ret = devm_pm_domain_attach_list(dev, &vcodec_data, &core->pmdomains);
+ if (ret < 0)
+ return ret;
- core->pd_dl_venus = device_link_add(dev, core->pmdomains[0],
- DL_FLAG_PM_RUNTIME |
- DL_FLAG_STATELESS |
- DL_FLAG_RPM_ACTIVE);
- if (!core->pd_dl_venus)
- return -ENODEV;
+skip_pmdomains:
+ if (!res->opp_pmdomain)
+ return 0;
+
+ /* Attach the power domain for setting performance state */
+ ret = devm_pm_domain_attach_list(dev, &opp_pd_data, &core->opp_pmdomain);
+ if (ret < 0)
+ return ret;
return 0;
}
-static void vcodec_domains_put(struct device *dev)
+static int core_resets_reset(struct venus_core *core)
{
- struct venus_core *core = dev_get_drvdata(dev);
const struct venus_resources *res = core->res;
unsigned int i;
+ int ret;
- if (!res->vcodec_pmdomains_num)
- return;
+ if (!res->resets_num)
+ return 0;
- if (core->pd_dl_venus)
- device_link_del(core->pd_dl_venus);
+ for (i = 0; i < res->resets_num; i++) {
+ ret = reset_control_assert(core->resets[i]);
+ if (ret)
+ goto err;
- for (i = 0; i < res->vcodec_pmdomains_num; i++) {
- if (IS_ERR_OR_NULL(core->pmdomains[i]))
- continue;
- dev_pm_domain_detach(core->pmdomains[i], true);
+ usleep_range(150, 250);
+ ret = reset_control_deassert(core->resets[i]);
+ if (ret)
+ goto err;
}
+
+err:
+ return ret;
}
-static int core_get_v4(struct device *dev)
+static int core_resets_get(struct venus_core *core)
{
- struct venus_core *core = dev_get_drvdata(dev);
+ struct device *dev = core->dev;
+ const struct venus_resources *res = core->res;
+ unsigned int i;
+ int ret;
+
+ if (!res->resets_num)
+ return 0;
+
+ for (i = 0; i < res->resets_num; i++) {
+ core->resets[i] =
+ devm_reset_control_get_exclusive(dev, res->resets[i]);
+ if (IS_ERR(core->resets[i])) {
+ ret = PTR_ERR(core->resets[i]);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int core_get_v4(struct venus_core *core)
+{
+ struct device *dev = core->dev;
+ const struct freq_tbl *freq_tbl = core->res->freq_tbl;
+ unsigned int num_rows = core->res->freq_tbl_size;
const struct venus_resources *res = core->res;
+ unsigned int i;
int ret;
ret = core_clks_get(core);
@@ -808,50 +982,110 @@ static int core_get_v4(struct device *dev)
if (ret)
return ret;
+ ret = core_resets_get(core);
+ if (ret)
+ return ret;
+
if (legacy_binding)
return 0;
- ret = vcodec_domains_get(dev);
+ ret = devm_pm_opp_set_clkname(dev, "core");
+ if (ret)
+ return ret;
+
+ ret = vcodec_domains_get(core);
if (ret)
return ret;
+ if (core->res->opp_pmdomain) {
+ ret = devm_pm_opp_of_add_table(dev);
+ if (ret) {
+ if (ret == -ENODEV) {
+ for (i = 0; i < num_rows; i++) {
+ ret = dev_pm_opp_add(dev, freq_tbl[i].freq, 0);
+ if (ret)
+ return ret;
+ }
+ } else {
+ dev_err(dev, "invalid OPP table in device tree\n");
+ return ret;
+ }
+ }
+ }
+
return 0;
}
-static void core_put_v4(struct device *dev)
+static void core_put_v4(struct venus_core *core)
{
- if (legacy_binding)
- return;
-
- vcodec_domains_put(dev);
}
-static int core_power_v4(struct device *dev, int on)
+static int core_power_v4(struct venus_core *core, int on)
{
- struct venus_core *core = dev_get_drvdata(dev);
+ struct device *dev = core->dev;
+ struct device *pmctrl = core->pmdomains ?
+ core->pmdomains->pd_devs[0] : NULL;
int ret = 0;
- if (on == POWER_ON)
+ if (on == POWER_ON) {
+ if (pmctrl) {
+ ret = pm_runtime_resume_and_get(pmctrl);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ ret = core_resets_reset(core);
+ if (ret) {
+ if (pmctrl)
+ pm_runtime_put_sync(pmctrl);
+ return ret;
+ }
+
ret = core_clks_enable(core);
- else
+ if (ret < 0 && pmctrl)
+ pm_runtime_put_sync(pmctrl);
+ } else {
+ /* Drop the performance state vote */
+ if (core->opp_pmdomain)
+ dev_pm_opp_set_rate(dev, 0);
+
core_clks_disable(core);
+ ret = core_resets_reset(core);
+
+ if (pmctrl)
+ pm_runtime_put_sync(pmctrl);
+ }
+
return ret;
}
static unsigned long calculate_inst_freq(struct venus_inst *inst,
unsigned long filled_len)
{
- unsigned long vpp_freq = 0, vsp_freq = 0;
+ unsigned long vpp_freq_per_mb = 0, vpp_freq = 0, vsp_freq = 0;
u32 fps = (u32)inst->fps;
u32 mbs_per_sec;
- mbs_per_sec = load_per_instance(inst) / fps;
+ mbs_per_sec = load_per_instance(inst);
+
+ if (inst->state != INST_START)
+ return 0;
+
+ if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
+ vpp_freq_per_mb = inst->flags & VENUS_LOW_POWER ?
+ inst->clk_data.low_power_freq :
+ inst->clk_data.vpp_freq;
+
+ vpp_freq = mbs_per_sec * vpp_freq_per_mb;
+ } else {
+ vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq;
+ }
- vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq;
/* 21 / 20 is overhead factor */
vpp_freq += vpp_freq / 20;
- vsp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vsp_freq;
+ vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq;
/* 10 / 7 is overhead factor */
if (inst->session_type == VIDC_SESSION_TYPE_ENC)
@@ -865,18 +1099,18 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst,
static int load_scale_v4(struct venus_inst *inst)
{
struct venus_core *core = inst->core;
- const struct freq_tbl *table = core->res->freq_tbl;
- unsigned int num_rows = core->res->freq_tbl_size;
struct device *dev = core->dev;
unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0;
+ unsigned long max_freq = ULONG_MAX;
unsigned long filled_len = 0;
- int i, ret;
+ struct dev_pm_opp *opp;
+ int i, ret = 0;
for (i = 0; i < inst->num_input_bufs; i++)
filled_len = max(filled_len, inst->payloads[i]);
if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len)
- return 0;
+ return ret;
freq = calculate_inst_freq(inst, filled_len);
inst->clk_data.freq = freq;
@@ -892,23 +1126,23 @@ static int load_scale_v4(struct venus_inst *inst)
freq_core2 += inst->clk_data.freq;
}
}
- mutex_unlock(&core->lock);
freq = max(freq_core1, freq_core2);
- if (freq >= table[0].freq) {
- freq = table[0].freq;
- dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n",
- freq, table[0].freq);
+ opp = dev_pm_opp_find_freq_floor(dev, &max_freq);
+ if (!IS_ERR(opp))
+ dev_pm_opp_put(opp);
+
+ if (freq > max_freq) {
+ dev_dbg(dev, VDBGL "requested clock rate: %lu scaling clock rate : %lu\n",
+ freq, max_freq);
+ freq = max_freq;
goto set_freq;
}
- for (i = num_rows - 1 ; i >= 0; i--) {
- if (freq <= table[i].freq) {
- freq = table[i].freq;
- break;
- }
- }
+ opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+ if (!IS_ERR(opp))
+ dev_pm_opp_put(opp);
set_freq:
@@ -916,17 +1150,19 @@ set_freq:
if (ret) {
dev_err(dev, "failed to set clock rate %lu (%d)\n",
freq, ret);
- return ret;
+ goto exit;
}
ret = load_scale_bw(core);
if (ret) {
dev_err(dev, "failed to set bandwidth (%d)\n",
ret);
- return ret;
+ goto exit;
}
- return 0;
+exit:
+ mutex_unlock(&core->lock);
+ return ret;
}
static const struct venus_pm_ops pm_ops_v4 = {
@@ -952,6 +1188,7 @@ const struct venus_pm_ops *venus_pm_get(enum hfi_version version)
case HFI_VERSION_3XX:
return &pm_ops_v3;
case HFI_VERSION_4XX:
+ case HFI_VERSION_6XX:
return &pm_ops_v4;
}