mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
opp: Set required OPPs in reverse order when scaling down
The OPP core already has well-defined semantics to ensure required OPPs/regulators are set before/after the frequency change, depending on if we scale up or down. Similar requirements might exist for the order of required OPPs when multiple power domains need to be scaled for a frequency change. For example, on Qualcomm platforms using CPR (Core Power Reduction), we need to scale the VDDMX and CPR power domain. When scaling up, MX should be scaled up before CPR. When scaling down, CPR should be scaled down before MX. In general, if there are multiple "required-opps" in the device tree I would expect that the order is either irrelevant, or there is some dependency between the power domains. In that case, the power domains should be scaled down in reverse order. This commit updates _set_required_opps() to set required OPPs in reverse order when scaling down. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> [ Viresh: Fix rebase conflict and minor rearrangement of the code ] Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
This commit is contained in:
parent
60cdeae0d6
commit
2c59138c22
@ -800,7 +800,7 @@ static int _set_required_opp(struct device *dev, struct device *pd_dev,
|
|||||||
/* This is only called for PM domain for now */
|
/* This is only called for PM domain for now */
|
||||||
static int _set_required_opps(struct device *dev,
|
static int _set_required_opps(struct device *dev,
|
||||||
struct opp_table *opp_table,
|
struct opp_table *opp_table,
|
||||||
struct dev_pm_opp *opp)
|
struct dev_pm_opp *opp, bool up)
|
||||||
{
|
{
|
||||||
struct opp_table **required_opp_tables = opp_table->required_opp_tables;
|
struct opp_table **required_opp_tables = opp_table->required_opp_tables;
|
||||||
struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
|
struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
|
||||||
@ -820,11 +820,22 @@ static int _set_required_opps(struct device *dev,
|
|||||||
* after it is freed from another thread.
|
* after it is freed from another thread.
|
||||||
*/
|
*/
|
||||||
mutex_lock(&opp_table->genpd_virt_dev_lock);
|
mutex_lock(&opp_table->genpd_virt_dev_lock);
|
||||||
for (i = 0; i < opp_table->required_opp_count; i++) {
|
|
||||||
ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
|
/* Scaling up? Set required OPPs in normal order, else reverse */
|
||||||
if (ret)
|
if (up) {
|
||||||
break;
|
for (i = 0; i < opp_table->required_opp_count; i++) {
|
||||||
|
ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = opp_table->required_opp_count - 1; i >= 0; i--) {
|
||||||
|
ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&opp_table->genpd_virt_dev_lock);
|
mutex_unlock(&opp_table->genpd_virt_dev_lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -883,7 +894,7 @@ static int _opp_set_rate_zero(struct device *dev, struct opp_table *opp_table)
|
|||||||
if (opp_table->regulators)
|
if (opp_table->regulators)
|
||||||
regulator_disable(opp_table->regulators[0]);
|
regulator_disable(opp_table->regulators[0]);
|
||||||
|
|
||||||
ret = _set_required_opps(dev, opp_table, NULL);
|
ret = _set_required_opps(dev, opp_table, NULL, false);
|
||||||
|
|
||||||
opp_table->enabled = false;
|
opp_table->enabled = false;
|
||||||
return ret;
|
return ret;
|
||||||
@ -974,7 +985,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
|
|||||||
|
|
||||||
/* Scaling up? Configure required OPPs before frequency */
|
/* Scaling up? Configure required OPPs before frequency */
|
||||||
if (freq >= old_freq) {
|
if (freq >= old_freq) {
|
||||||
ret = _set_required_opps(dev, opp_table, opp);
|
ret = _set_required_opps(dev, opp_table, opp, true);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto put_opp;
|
goto put_opp;
|
||||||
}
|
}
|
||||||
@ -994,7 +1005,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
|
|||||||
|
|
||||||
/* Scaling down? Configure required OPPs after frequency */
|
/* Scaling down? Configure required OPPs after frequency */
|
||||||
if (!ret && freq < old_freq) {
|
if (!ret && freq < old_freq) {
|
||||||
ret = _set_required_opps(dev, opp_table, opp);
|
ret = _set_required_opps(dev, opp_table, opp, false);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_err(dev, "Failed to set required opps: %d\n", ret);
|
dev_err(dev, "Failed to set required opps: %d\n", ret);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user