Skip to content

Commit ae8ac19

Browse files
abelvesarafaeljw
authored andcommitted
PM: domains: Reverse the order of performance and enabling ops
The ->set_performance_state() needs to be called before ->power_on() when a genpd is powered on, and after ->power_off() when a genpd is powered off. Do this in order to let the provider know to which performance state to power on the genpd, on the power on sequence, and also to maintain the performance for that genpd until after powering off, on power off sequence. There is no scenario where a consumer would need its genpd enabled and then its performance state increased. Instead, in every scenario, the consumer needs the genpd to be enabled from the start at a specific performance state. And same logic applies to the powering down. No consumer would need its genpd performance state dropped right before powering down. Now, there are currently two vendors which use ->set_performance_state() in their genpd providers. One of them is Tegra, but the only genpd provider (PMC) that makes use of ->set_performance_state() doesn't implement the ->power_on() or ->power_off(), and so it will not be affected by the ops reversal. The other vendor that uses it is Qualcomm, in multiple genpd providers actually (RPM, RPMh and CPR). But all Qualcomm genpd providers that make use of ->set_performance_state() need the order between enabling ops and the performance setting op to be reversed. And the reason for that is that it currently translates into two different voltages in order to power on a genpd to a specific performance state. Basically, ->power_on() switches to the minimum (enabling) voltage for that genpd, and then ->set_performance_state() sets it to the voltage level required by the consumer. By reversing the call order, we rely on the provider to know what to do on each call, but most popular usecase is to cache the performance state and postpone the voltage setting until the ->power_on() gets called. As for the reason of still needing the ->power_on() and ->power_off() for a provider which could get away with just having ->set_performance_state() implemented, there are consumers that do not (nor should) provide an opp-table. For those consumers, ->set_performance_state() will not be called, and so they will enable the genpd to its minimum performance state by a ->power_on() call. Same logic goes for the disabling. Signed-off-by: Abel Vesa <abel.vesa@linaro.org> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent ebb486b commit ae8ac19

1 file changed

Lines changed: 21 additions & 15 deletions

File tree

drivers/base/power/domain.c

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -939,8 +939,8 @@ static int genpd_runtime_suspend(struct device *dev)
939939
return 0;
940940

941941
genpd_lock(genpd);
942-
gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
943942
genpd_power_off(genpd, true, 0);
943+
gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
944944
genpd_unlock(genpd);
945945

946946
return 0;
@@ -978,9 +978,8 @@ static int genpd_runtime_resume(struct device *dev)
978978
goto out;
979979

980980
genpd_lock(genpd);
981+
genpd_restore_performance_state(dev, gpd_data->rpm_pstate);
981982
ret = genpd_power_on(genpd, 0);
982-
if (!ret)
983-
genpd_restore_performance_state(dev, gpd_data->rpm_pstate);
984983
genpd_unlock(genpd);
985984

986985
if (ret)
@@ -1018,8 +1017,8 @@ static int genpd_runtime_resume(struct device *dev)
10181017
err_poweroff:
10191018
if (!pm_runtime_is_irq_safe(dev) || genpd_is_irq_safe(genpd)) {
10201019
genpd_lock(genpd);
1021-
gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
10221020
genpd_power_off(genpd, true, 0);
1021+
gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
10231022
genpd_unlock(genpd);
10241023
}
10251024

@@ -2707,17 +2706,6 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
27072706
dev->pm_domain->detach = genpd_dev_pm_detach;
27082707
dev->pm_domain->sync = genpd_dev_pm_sync;
27092708

2710-
if (power_on) {
2711-
genpd_lock(pd);
2712-
ret = genpd_power_on(pd, 0);
2713-
genpd_unlock(pd);
2714-
}
2715-
2716-
if (ret) {
2717-
genpd_remove_device(pd, dev);
2718-
return -EPROBE_DEFER;
2719-
}
2720-
27212709
/* Set the default performance state */
27222710
pstate = of_get_required_opp_performance_state(dev->of_node, index);
27232711
if (pstate < 0 && pstate != -ENODEV && pstate != -EOPNOTSUPP) {
@@ -2729,6 +2717,24 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
27292717
goto err;
27302718
dev_gpd_data(dev)->default_pstate = pstate;
27312719
}
2720+
2721+
if (power_on) {
2722+
genpd_lock(pd);
2723+
ret = genpd_power_on(pd, 0);
2724+
genpd_unlock(pd);
2725+
}
2726+
2727+
if (ret) {
2728+
/* Drop the default performance state */
2729+
if (dev_gpd_data(dev)->default_pstate) {
2730+
dev_pm_genpd_set_performance_state(dev, 0);
2731+
dev_gpd_data(dev)->default_pstate = 0;
2732+
}
2733+
2734+
genpd_remove_device(pd, dev);
2735+
return -EPROBE_DEFER;
2736+
}
2737+
27322738
return 1;
27332739

27342740
err:

0 commit comments

Comments
 (0)