Skip to content

Commit dd673de

Browse files
jonhuntergregkh
authored andcommitted
soc/tegra: pmc: Ensure power-domains are in a known state
commit b6bcbce upstream. After commit 13a4b7f ("pmdomain: core: Leave powered-on genpds on until late_initcall_sync") was applied, the Tegra210 Jetson TX1 board failed to boot. Looking into this issue, before this commit was applied, if any of the Tegra power-domains were in 'on' state when the kernel booted, they were being turned off by the genpd core before any driver had chance to request them. This was purely by luck and a consequence of the power-domains being turned off earlier during boot. After this commit was applied, any power-domains in the 'on' state are kept on for longer during boot and therefore, may never transitioned to the off state before they are requested/used. The hang on the Tegra210 Jetson TX1 is caused because devices in some power-domains are accessed without the power-domain being turned off and on, indicating that the power-domain is not in a completely on state. >From reviewing the Tegra PMC driver code, if a power-domain is in the 'on' state there is no guarantee that all the necessary clocks associated with the power-domain are on and even if they are they would not have been requested via the clock framework and so could be turned off later. Some power-domains also have a 'clamping' register that needs to be configured as well. In short, if a power-domain is already 'on' it is difficult to know if it has been configured correctly. Given that the power-domains happened to be switched off during boot previously, to ensure that they are in a good known state on boot, fix this by switching off any power-domains that are on initially when registering the power-domains with the genpd framework. Note that commit 05cfb98 ("soc/tegra: pmc: Initialise resets associated with a power partition") updated the tegra_powergate_of_get_resets() function to pass the 'off' to ensure that the resets for the power-domain are in the correct state on boot. However, now that we may power off a domain on boot, if it is on, it is better to move this logic into the tegra_powergate_add() function so that there is a single place where we are handling the initial state of the power-domain. Fixes: a380451 ("soc/tegra: pmc: Add generic PM domain support") Signed-off-by: Jon Hunter <jonathanh@nvidia.com> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250731121832.213671-1-jonathanh@nvidia.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent ec8d823 commit dd673de

File tree

1 file changed

+29
-22
lines changed

1 file changed

+29
-22
lines changed

drivers/soc/tegra/pmc.c

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,7 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,
12341234
}
12351235

12361236
static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
1237-
struct device_node *np, bool off)
1237+
struct device_node *np)
12381238
{
12391239
struct device *dev = pg->pmc->dev;
12401240
int err;
@@ -1249,22 +1249,6 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
12491249
err = reset_control_acquire(pg->reset);
12501250
if (err < 0) {
12511251
pr_err("failed to acquire resets: %d\n", err);
1252-
goto out;
1253-
}
1254-
1255-
if (off) {
1256-
err = reset_control_assert(pg->reset);
1257-
} else {
1258-
err = reset_control_deassert(pg->reset);
1259-
if (err < 0)
1260-
goto out;
1261-
1262-
reset_control_release(pg->reset);
1263-
}
1264-
1265-
out:
1266-
if (err) {
1267-
reset_control_release(pg->reset);
12681252
reset_control_put(pg->reset);
12691253
}
12701254

@@ -1309,20 +1293,43 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
13091293
goto set_available;
13101294
}
13111295

1312-
err = tegra_powergate_of_get_resets(pg, np, off);
1296+
err = tegra_powergate_of_get_resets(pg, np);
13131297
if (err < 0) {
13141298
dev_err(dev, "failed to get resets for %pOFn: %d\n", np, err);
13151299
goto remove_clks;
13161300
}
13171301

1318-
if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
1319-
if (off)
1320-
WARN_ON(tegra_powergate_power_up(pg, true));
1302+
/*
1303+
* If the power-domain is off, then ensure the resets are asserted.
1304+
* If the power-domain is on, then power down to ensure that when is
1305+
* it turned on the power-domain, clocks and resets are all in the
1306+
* expected state.
1307+
*/
1308+
if (off) {
1309+
err = reset_control_assert(pg->reset);
1310+
if (err) {
1311+
pr_err("failed to assert resets: %d\n", err);
1312+
goto remove_resets;
1313+
}
1314+
} else {
1315+
err = tegra_powergate_power_down(pg);
1316+
if (err) {
1317+
dev_err(dev, "failed to turn off PM domain %s: %d\n",
1318+
pg->genpd.name, err);
1319+
goto remove_resets;
1320+
}
1321+
}
13211322

1323+
/*
1324+
* If PM_GENERIC_DOMAINS is not enabled, power-on
1325+
* the domain and skip the genpd registration.
1326+
*/
1327+
if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
1328+
WARN_ON(tegra_powergate_power_up(pg, true));
13221329
goto remove_resets;
13231330
}
13241331

1325-
err = pm_genpd_init(&pg->genpd, NULL, off);
1332+
err = pm_genpd_init(&pg->genpd, NULL, true);
13261333
if (err < 0) {
13271334
dev_err(dev, "failed to initialise PM domain %pOFn: %d\n", np,
13281335
err);

0 commit comments

Comments
 (0)