diff options
Diffstat (limited to 'drivers/media/platform/qcom/venus/pm_helpers.c')
| -rw-r--r-- | drivers/media/platform/qcom/venus/pm_helpers.c | 193 |
1 files changed, 91 insertions, 102 deletions
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 48c9084bb4db..f0269524ac70 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -40,20 +40,26 @@ static int core_clks_get(struct venus_core *core) static int core_clks_enable(struct venus_core *core) { - const struct venus_resources *res = core->res; const struct freq_tbl *freq_tbl = core->res->freq_tbl; unsigned int freq_tbl_size = core->res->freq_tbl_size; - unsigned long freq; + 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; - if (!freq_tbl) - return -EINVAL; - - freq = freq_tbl[freq_tbl_size - 1].freq; + 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)) { + if (IS_V6(core) || (IS_V4(core) && is_lite(core))) { ret = clk_set_rate(core->clks[i], freq); if (ret) goto err; @@ -412,10 +418,17 @@ static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable) u32 val; int ret; - if (IS_V6(core)) { - ctrl = core->wrapper_base + WRAPPER_CORE_POWER_CONTROL_V6; - stat = core->wrapper_base + WRAPPER_CORE_POWER_STATUS_V6; - } else if (coreid == VIDC_CORE_ID_1) { + 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->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL; stat = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_STATUS; } else { @@ -451,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; } @@ -467,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; } @@ -484,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; @@ -502,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; @@ -625,7 +642,9 @@ static int decide_core(struct venus_inst *inst) 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) { @@ -648,7 +667,9 @@ static int decide_core(struct venus_inst *inst) cur_inst_lp_load *= inst->clk_data.low_power_freq; /*TODO : divide this inst->load by work_route */ - max_freq = core->res->freq_tbl[0].freq; + 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); @@ -804,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; } @@ -849,7 +870,7 @@ 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; } @@ -857,74 +878,36 @@ static int venc_power_v4(struct device *dev, int on) static int vcodec_domains_get(struct venus_core *core) { int ret; - struct device **opp_virt_dev; 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) 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_OR_NULL(pd)) - return PTR_ERR(pd) ? : -ENODATA; - core->pmdomains[i] = pd; - } + ret = devm_pm_domain_attach_list(dev, &vcodec_data, &core->pmdomains); + if (ret < 0) + return ret; skip_pmdomains: - if (!core->res->opp_pmdomain) + if (!res->opp_pmdomain) return 0; /* Attach the power domain for setting performance state */ - ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev); - if (ret) - goto opp_attach_err; - - core->opp_pmdomain = *opp_virt_dev; - core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain, - DL_FLAG_RPM_ACTIVE | - DL_FLAG_PM_RUNTIME | - DL_FLAG_STATELESS); - if (!core->opp_dl_venus) { - ret = -ENODEV; - goto opp_attach_err; - } + ret = devm_pm_domain_attach_list(dev, &opp_pd_data, &core->opp_pmdomain); + if (ret < 0) + return ret; return 0; - -opp_attach_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); - } - - return ret; -} - -static void vcodec_domains_put(struct venus_core *core) -{ - const struct venus_resources *res = core->res; - unsigned int i; - - if (!res->vcodec_pmdomains_num) - goto skip_pmdomains; - - 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); - } - -skip_pmdomains: - if (!core->has_opp_table) - return; - - if (core->opp_dl_venus) - device_link_del(core->opp_dl_venus); } static int core_resets_reset(struct venus_core *core) @@ -976,7 +959,10 @@ static int core_resets_get(struct venus_core *core) 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); @@ -1013,11 +999,17 @@ static int core_get_v4(struct venus_core *core) if (core->res->opp_pmdomain) { ret = devm_pm_opp_of_add_table(dev); - if (!ret) { - core->has_opp_table = true; - } else if (ret != -ENODEV) { - dev_err(dev, "invalid OPP table in device tree\n"); - return ret; + 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; + } } } @@ -1026,16 +1018,13 @@ static int core_get_v4(struct venus_core *core) static void core_put_v4(struct venus_core *core) { - if (legacy_binding) - return; - - vcodec_domains_put(core); } static int core_power_v4(struct venus_core *core, int on) { struct device *dev = core->dev; - struct device *pmctrl = core->pmdomains[0]; + struct device *pmctrl = core->pmdomains ? + core->pmdomains->pd_devs[0] : NULL; int ret = 0; if (on == POWER_ON) { @@ -1110,11 +1099,11 @@ 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; + struct dev_pm_opp *opp; int i, ret = 0; for (i = 0; i < inst->num_input_bufs; i++) @@ -1140,20 +1129,20 @@ static int load_scale_v4(struct venus_inst *inst) freq = max(freq_core1, freq_core2); - if (freq > table[0].freq) { - dev_dbg(dev, VDBGL "requested clock rate: %lu scaling clock rate : %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); - freq = table[0].freq; + 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: |
