Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc/tegra: pmc: Ensure power-domains are in a known state

After commit 13a4b7fb6260 ("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 05cfb988a4d0 ("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: a38045121bf4 ("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>

authored by

Jon Hunter and committed by
Ulf Hansson
b6bcbce3 8f5ae30d

+29 -22
+29 -22
drivers/soc/tegra/pmc.c
··· 1232 1232 } 1233 1233 1234 1234 static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, 1235 - struct device_node *np, bool off) 1235 + struct device_node *np) 1236 1236 { 1237 1237 struct device *dev = pg->pmc->dev; 1238 1238 int err; ··· 1247 1247 err = reset_control_acquire(pg->reset); 1248 1248 if (err < 0) { 1249 1249 pr_err("failed to acquire resets: %d\n", err); 1250 - goto out; 1251 - } 1252 - 1253 - if (off) { 1254 - err = reset_control_assert(pg->reset); 1255 - } else { 1256 - err = reset_control_deassert(pg->reset); 1257 - if (err < 0) 1258 - goto out; 1259 - 1260 - reset_control_release(pg->reset); 1261 - } 1262 - 1263 - out: 1264 - if (err) { 1265 - reset_control_release(pg->reset); 1266 1250 reset_control_put(pg->reset); 1267 1251 } 1268 1252 ··· 1292 1308 goto set_available; 1293 1309 } 1294 1310 1295 - err = tegra_powergate_of_get_resets(pg, np, off); 1311 + err = tegra_powergate_of_get_resets(pg, np); 1296 1312 if (err < 0) { 1297 1313 dev_err(dev, "failed to get resets for %pOFn: %d\n", np, err); 1298 1314 goto remove_clks; 1299 1315 } 1300 1316 1301 - if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { 1302 - if (off) 1303 - WARN_ON(tegra_powergate_power_up(pg, true)); 1317 + /* 1318 + * If the power-domain is off, then ensure the resets are asserted. 1319 + * If the power-domain is on, then power down to ensure that when is 1320 + * it turned on the power-domain, clocks and resets are all in the 1321 + * expected state. 1322 + */ 1323 + if (off) { 1324 + err = reset_control_assert(pg->reset); 1325 + if (err) { 1326 + pr_err("failed to assert resets: %d\n", err); 1327 + goto remove_resets; 1328 + } 1329 + } else { 1330 + err = tegra_powergate_power_down(pg); 1331 + if (err) { 1332 + dev_err(dev, "failed to turn off PM domain %s: %d\n", 1333 + pg->genpd.name, err); 1334 + goto remove_resets; 1335 + } 1336 + } 1304 1337 1338 + /* 1339 + * If PM_GENERIC_DOMAINS is not enabled, power-on 1340 + * the domain and skip the genpd registration. 1341 + */ 1342 + if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { 1343 + WARN_ON(tegra_powergate_power_up(pg, true)); 1305 1344 goto remove_resets; 1306 1345 } 1307 1346 1308 - err = pm_genpd_init(&pg->genpd, NULL, off); 1347 + err = pm_genpd_init(&pg->genpd, NULL, true); 1309 1348 if (err < 0) { 1310 1349 dev_err(dev, "failed to initialise PM domain %pOFn: %d\n", np, 1311 1350 err);