Skip to content

Commit

Permalink
media: venus: core: Add support for opp tables/perf voting
Browse files Browse the repository at this point in the history
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>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
  • Loading branch information
Rajendra Nayak authored and mchehab committed Aug 18, 2020
1 parent 98cd831 commit 9a538b8
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 7 deletions.
2 changes: 2 additions & 0 deletions drivers/media/platform/qcom/venus/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,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 *[]) { "cx", NULL },
.vcodec_num = 2,
.max_load = 3110400, /* 4096x2160@90 */
.hfi_version = HFI_VERSION_4XX,
Expand Down Expand Up @@ -573,6 +574,7 @@ static const struct venus_resources sc7180_res = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2,
.opp_pmdomain = (const char *[]) { "cx", NULL },
.vcodec_num = 1,
.hfi_version = HFI_VERSION_4XX,
.vmem_id = VIDC_RESOURCE_NONE,
Expand Down
5 changes: 5 additions & 0 deletions drivers/media/platform/qcom/venus/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -145,8 +146,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;
Expand Down
92 changes: 85 additions & 7 deletions drivers/media/platform/qcom/venus/pm_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -744,13 +744,16 @@ static int venc_power_v4(struct device *dev, int on)

static int vcodec_domains_get(struct device *dev)
{
int ret;
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,
Expand All @@ -767,7 +770,41 @@ static int vcodec_domains_get(struct device *dev)
if (!core->pd_dl_venus)
return -ENODEV;

skip_pmdomains:
if (!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)) {
ret = PTR_ERR(opp_table);
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_dl_add_err;
}

return 0;

opp_dl_add_err:
dev_pm_domain_detach(core->opp_pmdomain, true);
opp_attach_err:
if (core->pd_dl_venus) {
device_link_del(core->pd_dl_venus);
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 device *dev)
Expand All @@ -777,7 +814,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);
Expand All @@ -787,6 +824,15 @@ static void vcodec_domains_put(struct device *dev)
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);

dev_pm_domain_detach(core->opp_pmdomain, true);
}

static int core_get_v4(struct device *dev)
Expand Down Expand Up @@ -815,30 +861,62 @@ static int core_get_v4(struct device *dev)
if (legacy_binding)
return 0;

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");
dev_pm_opp_put_clkname(core->opp_table);
return ret;
}
}

ret = vcodec_domains_get(dev);
if (ret)
if (ret) {
if (core->has_opp_table)
dev_pm_opp_of_remove_table(dev);
dev_pm_opp_put_clkname(core->opp_table);
return ret;
}

return 0;
}

static void core_put_v4(struct device *dev)
{
struct venus_core *core = dev_get_drvdata(dev);

if (legacy_binding)
return;

vcodec_domains_put(dev);

if (core->has_opp_table)
dev_pm_opp_of_remove_table(dev);
if (core->opp_table)
dev_pm_opp_put_clkname(core->opp_table);

}

static int core_power_v4(struct device *dev, int on)
{
struct venus_core *core = dev_get_drvdata(dev);
int ret = 0;

if (on == POWER_ON)
if (on == POWER_ON) {
ret = core_clks_enable(core);
else
} else {
/* Drop the performance state vote */
if (core->opp_pmdomain)
dev_pm_opp_set_rate(dev, 0);

core_clks_disable(core);
}

return ret;
}
Expand Down

0 comments on commit 9a538b8

Please sign in to comment.