public inbox for linux-pm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1] pmdomain: ti_sci: re-sync TIFS with genpd on resume
@ 2026-04-27  7:48 Vitor Soares
  0 siblings, 0 replies; only message in thread
From: Vitor Soares @ 2026-04-27  7:48 UTC (permalink / raw)
  To: Nishanth Menon, Tero Kristo, Santosh Shilimkar, Ulf Hansson
  Cc: Vitor Soares, linux-arm-kernel, linux-pm, linux-kernel,
	Tomi Valkeinen, Kevin Hilman, vishalm, sebin.francis, d-gole,
	Devarsh Thakkar, Vignesh Raghavendra, stable

From: Vitor Soares <vitor.soares@toradex.com>

When a device in a TI SCI power domain is on the wakeup path of a
wakeup-capable child, the suspend path skips genpd_sync_power_off().
No put_device is sent to TIFS and the domain's genpd status remains
ON.

TIFS powers off the hardware during deep sleep regardless, since it
was never informed to keep the domain active. On resume, because the
domain's genpd status is ON, no get_device is issued. The driver
then accesses registers of a powered-off domain, causing a
synchronous external abort (AXI bus error, ESR 0x96000010).

Commit 0b5fe1c4ab3c ("pmdomain: ti-sci: Set PD on/off state according
to the HW state") exposed this. Before, domain status was initialized
to OFF, so get_device was always issued on resume.

Add a .resume hook that queries the domain's state from TIFS and
re-syncs TIFS with get_device when genpd has it ON but TIFS has it
OFF. The hook is only registered when the is_on op is available,
since detection depends on it.

Move ti_sci_pm_pd_is_on() earlier in the file so it is available to
the resume hook.

Fixes: 0b5fe1c4ab3c ("pmdomain: ti-sci: Set PD on/off state according to the HW state")
Cc: stable@vger.kernel.org # 6.18+
Signed-off-by: Vitor Soares <vitor.soares@toradex.com>
---
 drivers/pmdomain/ti/ti_sci_pm_domains.c | 66 ++++++++++++++++++-------
 1 file changed, 49 insertions(+), 17 deletions(-)

diff --git a/drivers/pmdomain/ti/ti_sci_pm_domains.c b/drivers/pmdomain/ti/ti_sci_pm_domains.c
index e5d1934f78d9..ec976d77b818 100644
--- a/drivers/pmdomain/ti/ti_sci_pm_domains.c
+++ b/drivers/pmdomain/ti/ti_sci_pm_domains.c
@@ -131,6 +131,23 @@ static int ti_sci_pd_power_on(struct generic_pm_domain *domain)
 		return ti_sci->ops.dev_ops.get_device(ti_sci, pd->idx);
 }
 
+static bool ti_sci_pm_pd_is_on(struct ti_sci_genpd_provider *pd_provider,
+			       int pd_idx)
+{
+	bool is_on;
+	int ret;
+
+	if (!pd_provider->ti_sci->ops.dev_ops.is_on)
+		return false;
+
+	ret = pd_provider->ti_sci->ops.dev_ops.is_on(pd_provider->ti_sci,
+						     pd_idx, NULL, &is_on);
+	if (ret)
+		return false;
+
+	return is_on;
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int ti_sci_pd_suspend(struct device *dev)
 {
@@ -149,8 +166,37 @@ static int ti_sci_pd_suspend(struct device *dev)
 
 	return 0;
 }
+
+static int ti_sci_pd_resume(struct device *dev)
+{
+	struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain);
+	struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(genpd);
+	const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
+	int ret;
+
+	/*
+	 * If genpd's domain state is ON but TIFS powered it OFF during
+	 * suspend, re-sync by issuing get_device before the driver resumes.
+	 */
+	if (genpd->status == GENPD_STATE_ON &&
+	    !ti_sci_pm_pd_is_on(pd->parent, pd->idx)) {
+		dev_dbg(dev, "ti_sci_pd: ID:%d genpd/TIFS out of sync on resume, re-syncing\n",
+			pd->idx);
+		if (pd->exclusive)
+			ret = ti_sci->ops.dev_ops.get_device_exclusive(ti_sci,
+								       pd->idx);
+		else
+			ret = ti_sci->ops.dev_ops.get_device(ti_sci, pd->idx);
+		if (ret)
+			return ret;
+	}
+
+	return pm_generic_resume(dev);
+}
+
 #else
 #define ti_sci_pd_suspend		NULL
+#define ti_sci_pd_resume		NULL
 #endif
 
 /*
@@ -200,23 +246,6 @@ static bool ti_sci_pm_idx_exists(struct ti_sci_genpd_provider *pd_provider, u32
 	return false;
 }
 
-static bool ti_sci_pm_pd_is_on(struct ti_sci_genpd_provider *pd_provider,
-			       int pd_idx)
-{
-	bool is_on;
-	int ret;
-
-	if (!pd_provider->ti_sci->ops.dev_ops.is_on)
-		return false;
-
-	ret = pd_provider->ti_sci->ops.dev_ops.is_on(pd_provider->ti_sci,
-						     pd_idx, NULL, &is_on);
-	if (ret)
-		return false;
-
-	return is_on;
-}
-
 static int ti_sci_pm_domain_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -283,6 +312,9 @@ static int ti_sci_pm_domain_probe(struct platform_device *pdev)
 				    pd_provider->ti_sci->ops.pm_ops.set_latency_constraint)
 					pd->pd.domain.ops.suspend = ti_sci_pd_suspend;
 
+				if (pd_provider->ti_sci->ops.dev_ops.is_on)
+					pd->pd.domain.ops.resume = ti_sci_pd_resume;
+
 				is_on = ti_sci_pm_pd_is_on(pd_provider,
 							   pd->idx);
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-04-27  7:48 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-27  7:48 [PATCH v1] pmdomain: ti_sci: re-sync TIFS with genpd on resume Vitor Soares

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox