Message ID | 1588080785-6812-13-git-send-email-rnayak@codeaurora.org (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | DVFS for IO devices on sdm845 and sc7180 | expand |
On Tue, Apr 28, 2020 at 07:03:00PM +0530, Rajendra Nayak wrote: > Add support to add OPP tables and perf voting on the OPP powerdomain. > This is needed so venus votes on the corresponding performance state > for the OPP powerdomain along with setting the core clock rate. > > Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org> > Cc: Stanimir Varbanov <stanimir.varbanov@linaro.org> > Cc: linux-media@vger.kernel.org > --- > drivers/media/platform/qcom/venus/core.c | 28 +++++++++++++++++++ > drivers/media/platform/qcom/venus/core.h | 5 ++++ > drivers/media/platform/qcom/venus/pm_helpers.c | 37 +++++++++++++++++++++++--- > 3 files changed, 66 insertions(+), 4 deletions(-) > > diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c > index 194b10b9..e98fea92 100644 > --- a/drivers/media/platform/qcom/venus/core.c > +++ b/drivers/media/platform/qcom/venus/core.c > @@ -12,6 +12,7 @@ > #include <linux/platform_device.h> > #include <linux/slab.h> > #include <linux/types.h> > +#include <linux/pm_opp.h> > #include <linux/pm_runtime.h> > #include <media/videobuf2-v4l2.h> > #include <media/v4l2-mem2mem.h> > @@ -214,6 +215,20 @@ static int venus_probe(struct platform_device *pdev) > if (!core->pm_ops) > return -ENODEV; > > + core->opp_table = dev_pm_opp_set_clkname(dev, "core"); > + if (IS_ERR(core->opp_table)) > + return PTR_ERR(core->opp_table); > + > + if (core->res->opp_pmdomain) { > + ret = dev_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 (core->pm_ops->core_get) { > ret = core->pm_ops->core_get(dev); > if (ret) > @@ -301,6 +316,9 @@ static int venus_probe(struct platform_device *pdev) > err_venus_shutdown: > venus_shutdown(core); > err_runtime_disable: > + if (core->res->opp_pmdomain && core->has_opp_table) the check for 'core->res->opp_pmdomain' is not needed, 'core->has_opp_table' can only be true when 'core->res->opp_pmdomain' is not NULL. > + dev_pm_opp_of_remove_table(dev); > + dev_pm_opp_put_clkname(core->opp_table); > pm_runtime_set_suspended(dev); > pm_runtime_disable(dev); > hfi_destroy(core); > @@ -326,6 +344,10 @@ static int venus_remove(struct platform_device *pdev) > > venus_firmware_deinit(core); > > + if (core->res->opp_pmdomain && core->has_opp_table) ditto
On 4/29/2020 6:09 AM, Matthias Kaehlcke wrote: > On Tue, Apr 28, 2020 at 07:03:00PM +0530, Rajendra Nayak wrote: >> Add support to add OPP tables and perf voting on the OPP powerdomain. >> This is needed so venus votes on the corresponding performance state >> for the OPP powerdomain along with setting the core clock rate. >> >> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org> >> Cc: Stanimir Varbanov <stanimir.varbanov@linaro.org> >> Cc: linux-media@vger.kernel.org >> --- >> drivers/media/platform/qcom/venus/core.c | 28 +++++++++++++++++++ >> drivers/media/platform/qcom/venus/core.h | 5 ++++ >> drivers/media/platform/qcom/venus/pm_helpers.c | 37 +++++++++++++++++++++++--- >> 3 files changed, 66 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c >> index 194b10b9..e98fea92 100644 >> --- a/drivers/media/platform/qcom/venus/core.c >> +++ b/drivers/media/platform/qcom/venus/core.c >> @@ -12,6 +12,7 @@ >> #include <linux/platform_device.h> >> #include <linux/slab.h> >> #include <linux/types.h> >> +#include <linux/pm_opp.h> >> #include <linux/pm_runtime.h> >> #include <media/videobuf2-v4l2.h> >> #include <media/v4l2-mem2mem.h> >> @@ -214,6 +215,20 @@ static int venus_probe(struct platform_device *pdev) >> if (!core->pm_ops) >> return -ENODEV; >> >> + core->opp_table = dev_pm_opp_set_clkname(dev, "core"); >> + if (IS_ERR(core->opp_table)) >> + return PTR_ERR(core->opp_table); >> + >> + if (core->res->opp_pmdomain) { >> + ret = dev_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 (core->pm_ops->core_get) { >> ret = core->pm_ops->core_get(dev); >> if (ret) >> @@ -301,6 +316,9 @@ static int venus_probe(struct platform_device *pdev) >> err_venus_shutdown: >> venus_shutdown(core); >> err_runtime_disable: >> + if (core->res->opp_pmdomain && core->has_opp_table) > > the check for 'core->res->opp_pmdomain' is not needed, 'core->has_opp_table' > can only be true when 'core->res->opp_pmdomain' is not NULL. ah, that's right, will fix. Thanks. > >> + dev_pm_opp_of_remove_table(dev); >> + dev_pm_opp_put_clkname(core->opp_table); >> pm_runtime_set_suspended(dev); >> pm_runtime_disable(dev); >> hfi_destroy(core); >> @@ -326,6 +344,10 @@ static int venus_remove(struct platform_device *pdev) >> >> venus_firmware_deinit(core); >> >> + if (core->res->opp_pmdomain && core->has_opp_table) > > ditto >
Hi Rajendra, Thanks for the patch! On 4/28/20 4:33 PM, Rajendra Nayak wrote: > Add support to add OPP tables and perf voting on the OPP powerdomain. > This is needed so venus votes on the corresponding performance state > for the OPP powerdomain along with setting the core clock rate. > > Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org> > Cc: Stanimir Varbanov <stanimir.varbanov@linaro.org> > Cc: linux-media@vger.kernel.org > --- > drivers/media/platform/qcom/venus/core.c | 28 +++++++++++++++++++ > drivers/media/platform/qcom/venus/core.h | 5 ++++ > drivers/media/platform/qcom/venus/pm_helpers.c | 37 +++++++++++++++++++++++--- > 3 files changed, 66 insertions(+), 4 deletions(-) > > diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c > index 194b10b9..e98fea92 100644 > --- a/drivers/media/platform/qcom/venus/core.c > +++ b/drivers/media/platform/qcom/venus/core.c > @@ -12,6 +12,7 @@ > #include <linux/platform_device.h> > #include <linux/slab.h> > #include <linux/types.h> > +#include <linux/pm_opp.h> > #include <linux/pm_runtime.h> > #include <media/videobuf2-v4l2.h> > #include <media/v4l2-mem2mem.h> > @@ -214,6 +215,20 @@ static int venus_probe(struct platform_device *pdev) > if (!core->pm_ops) > return -ENODEV; > > + core->opp_table = dev_pm_opp_set_clkname(dev, "core"); Should we set opp clkname if opp_of_add_table fails? We have platforms which don't have opp tables in Venus DT node. We have to be backward compatible for them. > + if (IS_ERR(core->opp_table)) > + return PTR_ERR(core->opp_table); > + > + if (core->res->opp_pmdomain) { > + ret = dev_pm_opp_of_add_table(dev); > + if (!ret) { > + core->has_opp_table = true; > + } else if (ret != -ENODEV) { Is it possible dev_pm_opp_of_add_table() to return EPROBE_DEFER? > + dev_err(dev, "Invalid OPP table in Device tree\n"); ... if so, please drop dev_err. > + return ret; > + } > + } > + > if (core->pm_ops->core_get) { > ret = core->pm_ops->core_get(dev); > if (ret) > @@ -301,6 +316,9 @@ static int venus_probe(struct platform_device *pdev) > err_venus_shutdown: > venus_shutdown(core); > err_runtime_disable: > + if (core->res->opp_pmdomain && core->has_opp_table) > + dev_pm_opp_of_remove_table(dev); > + dev_pm_opp_put_clkname(core->opp_table); > pm_runtime_set_suspended(dev); > pm_runtime_disable(dev); > hfi_destroy(core); > @@ -326,6 +344,10 @@ static int venus_remove(struct platform_device *pdev) > > venus_firmware_deinit(core); > > + if (core->res->opp_pmdomain && core->has_opp_table) > + dev_pm_opp_of_remove_table(dev); > + dev_pm_opp_put_clkname(core->opp_table); > + > pm_runtime_put_sync(dev); > pm_runtime_disable(dev); > > @@ -350,6 +372,10 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) > if (ret) > return ret; > > + /* Drop the performance state vote */ > + if (core->opp_pmdomain) > + dev_pm_opp_set_rate(dev, 0); > + > if (pm_ops->core_power) > ret = pm_ops->core_power(dev, POWER_OFF); > > @@ -511,6 +537,7 @@ static const struct venus_resources sdm845_res_v2 = { > .vcodec_clks_num = 2, > .vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" }, > .vcodec_pmdomains_num = 3, > + .opp_pmdomain = (const char *[]) { "opp-pd", NULL }, > .vcodec_num = 2, > .max_load = 3110400, /* 4096x2160@90 */ > .hfi_version = HFI_VERSION_4XX, > @@ -556,6 +583,7 @@ static const struct venus_resources sc7180_res = { > .vcodec_clks_num = 2, > .vcodec_pmdomains = { "venus", "vcodec0" }, > .vcodec_pmdomains_num = 2, > + .opp_pmdomain = (const char *[]) { "opp-pd", NULL }, > .vcodec_num = 1, > .hfi_version = HFI_VERSION_4XX, > .vmem_id = VIDC_RESOURCE_NONE, > diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h > index bd3ac6a..cc1d511 100644 > --- a/drivers/media/platform/qcom/venus/core.h > +++ b/drivers/media/platform/qcom/venus/core.h > @@ -62,6 +62,7 @@ struct venus_resources { > unsigned int vcodec_clks_num; > const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX]; > unsigned int vcodec_pmdomains_num; > + const char **opp_pmdomain; > unsigned int vcodec_num; > enum hfi_version hfi_version; > u32 max_load; > @@ -144,8 +145,12 @@ struct venus_core { > struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; > struct icc_path *video_path; > struct icc_path *cpucfg_path; > + struct opp_table *opp_table; > + bool has_opp_table; > struct device_link *pd_dl_venus; > struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX]; > + struct device_link *opp_dl_venus; > + struct device *opp_pmdomain; > struct video_device *vdev_dec; > struct video_device *vdev_enc; > struct v4l2_device v4l2_dev; > diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c > index abf9315..bc5bbd2 100644 > --- a/drivers/media/platform/qcom/venus/pm_helpers.c > +++ b/drivers/media/platform/qcom/venus/pm_helpers.c > @@ -9,6 +9,7 @@ > #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/types.h> > #include <media/v4l2-mem2mem.h> > @@ -66,10 +67,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); Is this will work for legacy platforms without OPP tables? Also what about the other clocks (vicodec0,1) in this function. > if (ret) > return ret; > > @@ -740,13 +740,15 @@ static int venc_power_v4(struct device *dev, int on) > > static int vcodec_domains_get(struct device *dev) > { > + struct opp_table *opp_table; > + struct device **opp_virt_dev; > struct venus_core *core = dev_get_drvdata(dev); > const struct venus_resources *res = core->res; > struct device *pd; > unsigned int i; > > 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, > @@ -763,6 +765,24 @@ static int vcodec_domains_get(struct device *dev) > if (!core->pd_dl_venus) > return -ENODEV; > > +skip_pmdomains: > + if (!res->opp_pmdomain || !core->has_opp_table) > + return 0; > + > + /* Attach the power domain for setting performance state */ > + opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev); > + if (IS_ERR(opp_table)) { > + return PTR_ERR(opp_table); > + } else if (opp_virt_dev) { > + 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) > + return -ENODEV; I think as you return ENODEV you have to detach opp domain here because vcodec_domains_put() is not called in error path. > + } > + > return 0; > } > > @@ -773,7 +793,7 @@ static void vcodec_domains_put(struct device *dev) > unsigned int i; > > if (!res->vcodec_pmdomains_num) > - return; > + goto skip_pmdomains; > > if (core->pd_dl_venus) > device_link_del(core->pd_dl_venus); > @@ -783,6 +803,15 @@ static void vcodec_domains_put(struct device *dev) > continue; > dev_pm_domain_detach(core->pmdomains[i], true); > } > + > +skip_pmdomains: > + if (!res->opp_pmdomain) > + return; > + > + if (core->opp_dl_venus) > + device_link_del(core->opp_dl_venus); > + > + dev_pm_domain_detach(core->opp_pmdomain, true); > } > > static int core_get_v4(struct device *dev) >
Hey Stan, On 4/29/2020 8:06 PM, Stanimir Varbanov wrote: > Hi Rajendra, > > Thanks for the patch! > [].. >> #include <linux/pm_runtime.h> >> #include <media/videobuf2-v4l2.h> >> #include <media/v4l2-mem2mem.h> >> @@ -214,6 +215,20 @@ static int venus_probe(struct platform_device *pdev) >> if (!core->pm_ops) >> return -ENODEV; >> >> + core->opp_table = dev_pm_opp_set_clkname(dev, "core"); > > Should we set opp clkname if opp_of_add_table fails? We have platforms > which don't have opp tables in Venus DT node. We have to be backward > compatible for them. so the way its designed, you are expected to call dev_pm_opp_set_clkname() *before* adding any OPPs from the OPP table. As for backward compatibility its already handled by the OPP core now [1] which makes sure dev_pm_opp_set_rate() is equivalent to a clk_set_rate() in case of a missing OPP table. >> + if (IS_ERR(core->opp_table)) >> + return PTR_ERR(core->opp_table); >> + >> + if (core->res->opp_pmdomain) { >> + ret = dev_pm_opp_of_add_table(dev); >> + if (!ret) { >> + core->has_opp_table = true; >> + } else if (ret != -ENODEV) { > > Is it possible dev_pm_opp_of_add_table() to return EPROBE_DEFER? Nope, it does not, I had checked. >> + dev_err(dev, "Invalid OPP table in Device tree\n"); > > ... if so, please drop dev_err. > >> + return ret; >> + } >> + } [].. >> --- a/drivers/media/platform/qcom/venus/pm_helpers.c >> +++ b/drivers/media/platform/qcom/venus/pm_helpers.c >> @@ -9,6 +9,7 @@ >> #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/types.h> >> #include <media/v4l2-mem2mem.h> >> @@ -66,10 +67,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); > > Is this will work for legacy platforms without OPP tables? yes, see [1] which is already merged in mainline. > > Also what about the other clocks (vicodec0,1) in this function. We continue to use clk_set_rate() for those. The performance state is associated with only the core clk. >> if (ret) >> return ret; >> >> @@ -740,13 +740,15 @@ static int venc_power_v4(struct device *dev, int on) >> >> static int vcodec_domains_get(struct device *dev) >> { >> + struct opp_table *opp_table; >> + struct device **opp_virt_dev; >> struct venus_core *core = dev_get_drvdata(dev); >> const struct venus_resources *res = core->res; >> struct device *pd; >> unsigned int i; >> >> 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, >> @@ -763,6 +765,24 @@ static int vcodec_domains_get(struct device *dev) >> if (!core->pd_dl_venus) >> return -ENODEV; >> >> +skip_pmdomains: >> + if (!res->opp_pmdomain || !core->has_opp_table) >> + return 0; >> + >> + /* Attach the power domain for setting performance state */ >> + opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev); >> + if (IS_ERR(opp_table)) { >> + return PTR_ERR(opp_table); >> + } else if (opp_virt_dev) { >> + 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) >> + return -ENODEV; > > I think as you return ENODEV you have to detach opp domain here because > vcodec_domains_put() is not called in error path. Ok, I'll fix that up. Thanks for the review. [1] https://lkml.org/lkml/2020/4/8/413
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 194b10b9..e98fea92 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -12,6 +12,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/types.h> +#include <linux/pm_opp.h> #include <linux/pm_runtime.h> #include <media/videobuf2-v4l2.h> #include <media/v4l2-mem2mem.h> @@ -214,6 +215,20 @@ static int venus_probe(struct platform_device *pdev) if (!core->pm_ops) return -ENODEV; + core->opp_table = dev_pm_opp_set_clkname(dev, "core"); + if (IS_ERR(core->opp_table)) + return PTR_ERR(core->opp_table); + + if (core->res->opp_pmdomain) { + ret = dev_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 (core->pm_ops->core_get) { ret = core->pm_ops->core_get(dev); if (ret) @@ -301,6 +316,9 @@ static int venus_probe(struct platform_device *pdev) err_venus_shutdown: venus_shutdown(core); err_runtime_disable: + if (core->res->opp_pmdomain && core->has_opp_table) + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_clkname(core->opp_table); pm_runtime_set_suspended(dev); pm_runtime_disable(dev); hfi_destroy(core); @@ -326,6 +344,10 @@ static int venus_remove(struct platform_device *pdev) venus_firmware_deinit(core); + if (core->res->opp_pmdomain && core->has_opp_table) + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_clkname(core->opp_table); + pm_runtime_put_sync(dev); pm_runtime_disable(dev); @@ -350,6 +372,10 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) if (ret) return ret; + /* Drop the performance state vote */ + if (core->opp_pmdomain) + dev_pm_opp_set_rate(dev, 0); + if (pm_ops->core_power) ret = pm_ops->core_power(dev, POWER_OFF); @@ -511,6 +537,7 @@ static const struct venus_resources sdm845_res_v2 = { .vcodec_clks_num = 2, .vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" }, .vcodec_pmdomains_num = 3, + .opp_pmdomain = (const char *[]) { "opp-pd", NULL }, .vcodec_num = 2, .max_load = 3110400, /* 4096x2160@90 */ .hfi_version = HFI_VERSION_4XX, @@ -556,6 +583,7 @@ static const struct venus_resources sc7180_res = { .vcodec_clks_num = 2, .vcodec_pmdomains = { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, + .opp_pmdomain = (const char *[]) { "opp-pd", NULL }, .vcodec_num = 1, .hfi_version = HFI_VERSION_4XX, .vmem_id = VIDC_RESOURCE_NONE, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index bd3ac6a..cc1d511 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -62,6 +62,7 @@ struct venus_resources { unsigned int vcodec_clks_num; const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX]; unsigned int vcodec_pmdomains_num; + const char **opp_pmdomain; unsigned int vcodec_num; enum hfi_version hfi_version; u32 max_load; @@ -144,8 +145,12 @@ struct venus_core { struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; struct icc_path *video_path; struct icc_path *cpucfg_path; + struct opp_table *opp_table; + bool has_opp_table; struct device_link *pd_dl_venus; struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX]; + struct device_link *opp_dl_venus; + struct device *opp_pmdomain; struct video_device *vdev_dec; struct video_device *vdev_enc; struct v4l2_device v4l2_dev; diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index abf9315..bc5bbd2 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -9,6 +9,7 @@ #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/types.h> #include <media/v4l2-mem2mem.h> @@ -66,10 +67,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; @@ -740,13 +740,15 @@ static int venc_power_v4(struct device *dev, int on) static int vcodec_domains_get(struct device *dev) { + struct opp_table *opp_table; + struct device **opp_virt_dev; struct venus_core *core = dev_get_drvdata(dev); const struct venus_resources *res = core->res; struct device *pd; unsigned int i; 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, @@ -763,6 +765,24 @@ static int vcodec_domains_get(struct device *dev) if (!core->pd_dl_venus) return -ENODEV; +skip_pmdomains: + if (!res->opp_pmdomain || !core->has_opp_table) + return 0; + + /* Attach the power domain for setting performance state */ + opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev); + if (IS_ERR(opp_table)) { + return PTR_ERR(opp_table); + } else if (opp_virt_dev) { + 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) + return -ENODEV; + } + return 0; } @@ -773,7 +793,7 @@ static void vcodec_domains_put(struct device *dev) unsigned int i; if (!res->vcodec_pmdomains_num) - return; + goto skip_pmdomains; if (core->pd_dl_venus) device_link_del(core->pd_dl_venus); @@ -783,6 +803,15 @@ static void vcodec_domains_put(struct device *dev) continue; dev_pm_domain_detach(core->pmdomains[i], true); } + +skip_pmdomains: + if (!res->opp_pmdomain) + return; + + if (core->opp_dl_venus) + device_link_del(core->opp_dl_venus); + + dev_pm_domain_detach(core->opp_pmdomain, true); } static int core_get_v4(struct device *dev)
Add support to add OPP tables and perf voting on the OPP powerdomain. This is needed so venus votes on the corresponding performance state for the OPP powerdomain along with setting the core clock rate. Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org> Cc: Stanimir Varbanov <stanimir.varbanov@linaro.org> Cc: linux-media@vger.kernel.org --- drivers/media/platform/qcom/venus/core.c | 28 +++++++++++++++++++ drivers/media/platform/qcom/venus/core.h | 5 ++++ drivers/media/platform/qcom/venus/pm_helpers.c | 37 +++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 4 deletions(-)