From b50a013d3317322c2ea3fca1056b51c25c38a2a4 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 25 Sep 2023 15:17:12 +0200 Subject: [PATCH] BACKPORT: OPP: Extend support for the opp-level beyond required-opps At this point the level (performance state) for an OPP is currently limited to be requested for a device that is attached to a PM domain. Moreover, the device needs to have the so called required-opps assigned to it, which are based upon OPP tables being described in DT. To extend the support beyond required-opps and DT, let's enable the level to be set for all OPPs. More precisely, if the requested OPP has a valid level let's try to request it through the device's optional PM domain, via calling dev_pm_domain_set_performance_state(). Signed-off-by: Ulf Hansson [ Viresh: Handle NULL opp in _set_opp_level() ] Signed-off-by: Viresh Kumar Bug: 323966425 Change-Id: I6176127586d50324fbb96f099ddad60bb3c910e5 (cherry picked from commit 0025ff64ffcf6bd6ece5484e7818401f77bf115f) [nikunj: Resolved minor conflict in drivers/opp/core.c ] [anantg: Use dev_pm_genpd_set_performance_state in drivers/opp/core.c ] Signed-off-by: Nikunj Kela Signed-off-by: Anant Goel --- drivers/opp/core.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index f5c410c4ee79..5dd9ae2f3489 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -1011,6 +1011,28 @@ static int _set_required_opps(struct device *dev, return ret; } +static int _set_opp_level(struct device *dev, struct opp_table *opp_table, + struct dev_pm_opp *opp) +{ + unsigned int level = 0; + int ret = 0; + + if (opp) { + if (!opp->level) + return 0; + + level = opp->level; + } + + /* Request a new performance state through the device's PM domain. */ + ret = dev_pm_genpd_set_performance_state(dev, level); + if (ret) + dev_err(dev, "Failed to set performance state %u (%d)\n", level, + ret); + + return ret; +} + static void _find_current_opp(struct device *dev, struct opp_table *opp_table) { struct dev_pm_opp *opp = ERR_PTR(-ENODEV); @@ -1058,8 +1080,13 @@ static int _disable_opp_table(struct device *dev, struct opp_table *opp_table) if (opp_table->regulators) regulator_disable(opp_table->regulators[0]); + ret = _set_opp_level(dev, opp_table, NULL); + if (ret) + goto out; + ret = _set_required_opps(dev, opp_table, NULL, false); +out: opp_table->enabled = false; return ret; } @@ -1102,6 +1129,10 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, return ret; } + ret = _set_opp_level(dev, opp_table, opp); + if (ret) + return ret; + ret = _set_opp_bw(opp_table, opp, dev); if (ret) { dev_err(dev, "Failed to set bw: %d\n", ret); @@ -1145,6 +1176,10 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, return ret; } + ret = _set_opp_level(dev, opp_table, opp); + if (ret) + return ret; + ret = _set_required_opps(dev, opp_table, opp, false); if (ret) { dev_err(dev, "Failed to set required opps: %d\n", ret);