Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] mmc: sdhci-esdhc-imx: fix SDIO suspend/resume issues
@ 2026-06-25 10:59 ziniu.wang_1
  2026-06-25 10:59 ` [PATCH v2 1/5] mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check for tuning save/restore ziniu.wang_1
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: ziniu.wang_1 @ 2026-06-25 10:59 UTC (permalink / raw)
  To: adrian.hunter, ulfh, haibo.chen
  Cc: Frank.Li, s.hauer, kernel, festevam, imx, linux-mmc, s32,
	linux-arm-kernel, linux-kernel

From: Luke Wang <ziniu.wang_1@nxp.com>

This series fixes several issues with SDIO suspend/resume on i.MX
platforms using the sdhci-esdhc-imx driver:

1. Remove unnecessary mmc_card_wake_sdio_irq() check that prevented
   tuning save/restore for non-SDIO cards that keep power during PM.

2. Restore DLL override settings for DDR50/DDR52 modes on resume,
   since sdhci_esdhc_imx_hwinit() unconditionally clears ESDHC_DLL_CTRL.

3. Restore pinctrl state based on current timing mode before
   pm_runtime_force_resume() on resume. Only for non-wakeup devices
   to avoid glitching SD bus pins for powered SDIO cards.

4. Move disable_irq() before the wakeup check in suspend to prevent
   unhandled interrupts during the suspend sequence.

5. Fix error handling in suspend/resume paths: use
   pm_runtime_resume_and_get(), make non-critical failures non-fatal,
   and properly handle pm_runtime_force_resume() failure.

Changes since v1:
- Added patch 5 to fix error handling issues identified during review
- Use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
- Make pinctrl and cd-wake failures non-fatal (dev_warn only)
- Use esdhc_change_pinstate() instead of pinctrl_pm_select_default_state()
  in resume to restore correct pin state based on timing mode
- Skip pinctrl restore for wakeup devices to avoid SD bus glitch
- Check pm_runtime_force_resume() return value in resume

Luke Wang (5):
  mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check
    for tuning save/restore
  mmc: sdhci-esdhc-imx: restore DLL override for DDR modes on resume
  mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing on
    resume
  mmc: sdhci-esdhc-imx: disable irq during suspend to fix unhandled
    interrupt
  mmc: sdhci-esdhc-imx: fix suspend/resume error handling

 drivers/mmc/host/sdhci-esdhc-imx.c | 75 ++++++++++++++++++++----------
 1 file changed, 51 insertions(+), 24 deletions(-)

-- 
2.34.1



^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 1/5] mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check for tuning save/restore
  2026-06-25 10:59 [PATCH v2 0/5] mmc: sdhci-esdhc-imx: fix SDIO suspend/resume issues ziniu.wang_1
@ 2026-06-25 10:59 ` ziniu.wang_1
  2026-06-25 16:26   ` Frank Li
  2026-06-25 10:59 ` [PATCH v2 2/5] mmc: sdhci-esdhc-imx: restore DLL override for DDR modes on resume ziniu.wang_1
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: ziniu.wang_1 @ 2026-06-25 10:59 UTC (permalink / raw)
  To: adrian.hunter, ulfh, haibo.chen
  Cc: Frank.Li, s.hauer, kernel, festevam, imx, linux-mmc, s32,
	linux-arm-kernel, linux-kernel

From: Luke Wang <ziniu.wang_1@nxp.com>

The tuning save/restore during system PM is conditioned on
mmc_card_wake_sdio_irq(), but this check is unrelated to whether
tuning values need to be preserved. The actual requirement is that
the card keeps power during suspend and the controller is a uSDHC.

SDIO devices using out-of-band GPIO wakeup maintain power during
suspend but do not set the SDIO IRQ wake flag. In this case the
tuning delay values are not saved/restored.

Remove the unnecessary mmc_card_wake_sdio_irq() condition from both
the suspend save and resume restore paths.

Fixes: c63d25cdc59a ("mmc: sdhci-esdhc-imx: Save tuning value when card stays powered in suspend")
Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 18ecddd6df6f..6526d65538de 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -2064,8 +2064,7 @@ static int sdhci_esdhc_suspend(struct device *dev)
 	 * to save the tuning delay value just in case the usdhc
 	 * lost power during system PM.
 	 */
-	if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) &&
-	    esdhc_is_usdhc(imx_data))
+	if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
 		sdhc_esdhc_tuning_save(host);
 
 	if (device_may_wakeup(dev)) {
@@ -2124,8 +2123,7 @@ static int sdhci_esdhc_resume(struct device *dev)
 	 * restore the saved tuning delay value for the device which keep
 	 * power during system PM.
 	 */
-	if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) &&
-	    esdhc_is_usdhc(imx_data))
+	if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
 		sdhc_esdhc_tuning_restore(host);
 
 	pm_runtime_put_autosuspend(dev);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 2/5] mmc: sdhci-esdhc-imx: restore DLL override for DDR modes on resume
  2026-06-25 10:59 [PATCH v2 0/5] mmc: sdhci-esdhc-imx: fix SDIO suspend/resume issues ziniu.wang_1
  2026-06-25 10:59 ` [PATCH v2 1/5] mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check for tuning save/restore ziniu.wang_1
@ 2026-06-25 10:59 ` ziniu.wang_1
  2026-06-25 16:29   ` Frank Li
  2026-06-25 10:59 ` [PATCH v2 3/5] mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing " ziniu.wang_1
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: ziniu.wang_1 @ 2026-06-25 10:59 UTC (permalink / raw)
  To: adrian.hunter, ulfh, haibo.chen
  Cc: Frank.Li, s.hauer, kernel, festevam, imx, linux-mmc, s32,
	linux-arm-kernel, linux-kernel

From: Luke Wang <ziniu.wang_1@nxp.com>

sdhci_esdhc_imx_hwinit() unconditionally clears ESDHC_DLL_CTRL by
writing zero. For SDIO devices that keep power during system suspend
and operate in DDR mode, the card remains in DDR timing while the host
DLL override configuration is lost.

Extract the DLL override setup from esdhc_set_uhs_signaling() into
a helper esdhc_set_dll_override(), and call it on the resume path
when the card kept power and is using a DDR timing mode.

Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM logic")
Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 38 ++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 6526d65538de..a944351dbcdf 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -1349,6 +1349,23 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
 	return pinctrl_select_state(imx_data->pinctrl, pinctrl);
 }
 
+static void esdhc_set_dll_override(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
+	u32 v;
+
+	if (!boarddata->delay_line)
+		return;
+
+	v = boarddata->delay_line << ESDHC_DLL_OVERRIDE_VAL_SHIFT |
+	    (1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
+	if (is_imx53_esdhc(imx_data))
+		v <<= 1;
+	writel(v, host->ioaddr + ESDHC_DLL_CTRL);
+}
+
 /*
  * For HS400 eMMC, there is a data_strobe line. This signal is generated
  * by the device and used for data output and CRC status response output
@@ -1425,15 +1442,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 		m |= ESDHC_MIX_CTRL_DDREN;
 		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
 		imx_data->is_ddr = 1;
-		if (boarddata->delay_line) {
-			u32 v;
-			v = boarddata->delay_line <<
-				ESDHC_DLL_OVERRIDE_VAL_SHIFT |
-				(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
-			if (is_imx53_esdhc(imx_data))
-				v <<= 1;
-			writel(v, host->ioaddr + ESDHC_DLL_CTRL);
-		}
+		esdhc_set_dll_override(host);
 		break;
 	case MMC_TIMING_MMC_HS400:
 		m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
@@ -2123,9 +2132,18 @@ static int sdhci_esdhc_resume(struct device *dev)
 	 * restore the saved tuning delay value for the device which keep
 	 * power during system PM.
 	 */
-	if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
+	if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data)) {
 		sdhc_esdhc_tuning_restore(host);
 
+		/*
+		 * Restore DLL override for DDR modes. hwinit unconditionally
+		 * clears ESDHC_DLL_CTRL, but the card is still in DDR mode.
+		 */
+		if (host->timing == MMC_TIMING_UHS_DDR50 ||
+		    host->timing == MMC_TIMING_MMC_DDR52)
+			esdhc_set_dll_override(host);
+	}
+
 	pm_runtime_put_autosuspend(dev);
 
 	return ret;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 3/5] mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing on resume
  2026-06-25 10:59 [PATCH v2 0/5] mmc: sdhci-esdhc-imx: fix SDIO suspend/resume issues ziniu.wang_1
  2026-06-25 10:59 ` [PATCH v2 1/5] mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check for tuning save/restore ziniu.wang_1
  2026-06-25 10:59 ` [PATCH v2 2/5] mmc: sdhci-esdhc-imx: restore DLL override for DDR modes on resume ziniu.wang_1
@ 2026-06-25 10:59 ` ziniu.wang_1
  2026-06-25 16:35   ` Frank Li
  2026-06-25 10:59 ` [PATCH v2 4/5] mmc: sdhci-esdhc-imx: disable irq during suspend to fix unhandled interrupt ziniu.wang_1
  2026-06-25 10:59 ` [PATCH v2 5/5] mmc: sdhci-esdhc-imx: fix suspend/resume error handling ziniu.wang_1
  4 siblings, 1 reply; 15+ messages in thread
From: ziniu.wang_1 @ 2026-06-25 10:59 UTC (permalink / raw)
  To: adrian.hunter, ulfh, haibo.chen
  Cc: Frank.Li, s.hauer, kernel, festevam, imx, linux-mmc, s32,
	linux-arm-kernel, linux-kernel

From: Luke Wang <ziniu.wang_1@nxp.com>

SDIO devices such as WiFi may keep power during suspend, so the MMC
core skips full card re-initialization on resume and directly restores
the host controller's ios timing to match the card. For DDR mode,
pm_runtime_force_resume() sets DDR_EN before the pin configuration is
restored from sleep state. When DDR_EN is set while the pinctrl is still
muxed to GPIO or other non-uSDHC function, the loopback clock from the
external pad is not valid, resulting in an incorrect internal sampling
point being selected. This causes persistent read CRC errors on subsequent
data transfers, even after the pinctrl is later configured correctly.

SD/eMMC running in DDR mode are unaffected as they are fully re-initialized
from legacy timing after resume.

Fix this by restoring the pinctrl state based on current timing mode
using esdhc_change_pinstate() before pm_runtime_force_resume(). This
ensures the correct pin configuration (e.g., 100/200MHz for UHS modes)
is applied. Only restore for non-wakeup devices since wakeup devices
kept their active pin state during suspend to avoid glitching the SD
bus pins for powered SDIO cards.

Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM logic")
Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index a944351dbcdf..7fcaecdd4ec6 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -2114,6 +2114,12 @@ static int sdhci_esdhc_resume(struct device *dev)
 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
 	int ret;
 
+	if (!device_may_wakeup(dev)) {
+		ret = esdhc_change_pinstate(host, host->timing);
+		if (ret)
+			dev_warn(dev, "Failed to restore pinctrl state\n");
+	}
+
 	pm_runtime_force_resume(dev);
 
 	ret = mmc_gpio_set_cd_wake(host->mmc, false);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 4/5] mmc: sdhci-esdhc-imx: disable irq during suspend to fix unhandled interrupt
  2026-06-25 10:59 [PATCH v2 0/5] mmc: sdhci-esdhc-imx: fix SDIO suspend/resume issues ziniu.wang_1
                   ` (2 preceding siblings ...)
  2026-06-25 10:59 ` [PATCH v2 3/5] mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing " ziniu.wang_1
@ 2026-06-25 10:59 ` ziniu.wang_1
  2026-06-25 16:37   ` Frank Li
  2026-06-25 10:59 ` [PATCH v2 5/5] mmc: sdhci-esdhc-imx: fix suspend/resume error handling ziniu.wang_1
  4 siblings, 1 reply; 15+ messages in thread
From: ziniu.wang_1 @ 2026-06-25 10:59 UTC (permalink / raw)
  To: adrian.hunter, ulfh, haibo.chen
  Cc: Frank.Li, s.hauer, kernel, festevam, imx, linux-mmc, s32,
	linux-arm-kernel, linux-kernel

From: Luke Wang <ziniu.wang_1@nxp.com>

When using WIFI out-of-band wakeup, an "irq xxx: nobody cared" warning
occurs. This happens because the usdhc interrupt is not disabled during
system suspend when device_may_wakeup() returns false.

The sequence of events leading to this issue:
1. System enters suspend without disabling usdhc interrupt
(because device_may_wakeup() returns false for usdhc device)
2. WIFI out-of-band wakeup triggers system resume via GPIO interrupt
3. WIFI sends a Card interrupt before usdhc has fully resumed
4. usdhc is still in runtime suspend state and cannot handle the
interrupt properly
5. The unhandled interrupt triggers "nobody cared" warning

Fix this by unconditionally disabling the usdhc interrupt during suspend
and re-enabling it during resume, regardless of the wakeup capability.
This ensures no interrupts are processed during the suspend/resume
transition.

Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM logic")
Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 7fcaecdd4ec6..c4a22e42628e 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -2076,9 +2076,10 @@ static int sdhci_esdhc_suspend(struct device *dev)
 	if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
 		sdhc_esdhc_tuning_save(host);
 
+	/* The irqs of imx are not shared. It is safe to disable */
+	disable_irq(host->irq);
+
 	if (device_may_wakeup(dev)) {
-		/* The irqs of imx are not shared. It is safe to disable */
-		disable_irq(host->irq);
 		ret = sdhci_enable_irq_wakeups(host);
 		if (!ret)
 			dev_warn(dev, "Failed to enable irq wakeup\n");
@@ -2129,10 +2130,10 @@ static int sdhci_esdhc_resume(struct device *dev)
 	/* re-initialize hw state in case it's lost in low power mode */
 	sdhci_esdhc_imx_hwinit(host);
 
-	if (host->irq_wake_enabled) {
+	if (host->irq_wake_enabled)
 		sdhci_disable_irq_wakeups(host);
-		enable_irq(host->irq);
-	}
+
+	enable_irq(host->irq);
 
 	/*
 	 * restore the saved tuning delay value for the device which keep
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 5/5] mmc: sdhci-esdhc-imx: fix suspend/resume error handling
  2026-06-25 10:59 [PATCH v2 0/5] mmc: sdhci-esdhc-imx: fix SDIO suspend/resume issues ziniu.wang_1
                   ` (3 preceding siblings ...)
  2026-06-25 10:59 ` [PATCH v2 4/5] mmc: sdhci-esdhc-imx: disable irq during suspend to fix unhandled interrupt ziniu.wang_1
@ 2026-06-25 10:59 ` ziniu.wang_1
  2026-06-25 16:39   ` Frank Li
  4 siblings, 1 reply; 15+ messages in thread
From: ziniu.wang_1 @ 2026-06-25 10:59 UTC (permalink / raw)
  To: adrian.hunter, ulfh, haibo.chen
  Cc: Frank.Li, s.hauer, kernel, festevam, imx, linux-mmc, s32,
	linux-arm-kernel, linux-kernel

From: Luke Wang <ziniu.wang_1@nxp.com>

Fix several error handling issues in sdhci_esdhc_suspend/resume:

1. Use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
   to simplify error handling. If it fails, the device is unclocked
   and accessing hardware registers would cause a kernel panic.

2. Make pinctrl_pm_select_sleep_state() and mmc_gpio_set_cd_wake()
   failures non-fatal in suspend path. These failures only mean
   slightly higher power consumption or missing CD wakeup, but should
   not block system suspend.

3. Check pm_runtime_force_resume() return value in resume. If it
   fails (clock enable failure), return immediately since accessing
   hardware registers on an unclocked device would cause a panic.

4. Make mmc_gpio_set_cd_wake(false) call in resume not check return
   value since it always returns 0.

5. Always return 0 on success path instead of propagating non-fatal
   warning return values.

Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index c4a22e42628e..4d6818c95809 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -2060,7 +2060,9 @@ static int sdhci_esdhc_suspend(struct device *dev)
 	 * 2, make sure the pm_runtime_force_resume() in sdhci_esdhc_resume() really
 	 *    invoke its ->runtime_resume callback (needs_force_resume = 1).
 	 */
-	pm_runtime_get_sync(dev);
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		return ret;
 
 	if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
 		(host->tuning_mode != SDHCI_TUNING_MODE_1)) {
@@ -2094,10 +2096,12 @@ static int sdhci_esdhc_suspend(struct device *dev)
 		 */
 		ret = pinctrl_pm_select_sleep_state(dev);
 		if (ret)
-			return ret;
+			dev_warn(dev, "Failed to select sleep pinctrl state\n");
 	}
 
 	ret = mmc_gpio_set_cd_wake(host->mmc, true);
+	if (ret)
+		dev_warn(dev, "Failed to enable cd wake\n");
 
 	/*
 	 * Make sure invoke runtime_suspend to gate off clock.
@@ -2105,7 +2109,7 @@ static int sdhci_esdhc_suspend(struct device *dev)
 	 */
 	pm_runtime_force_suspend(dev);
 
-	return ret;
+	return 0;
 }
 
 static int sdhci_esdhc_resume(struct device *dev)
@@ -2121,12 +2125,12 @@ static int sdhci_esdhc_resume(struct device *dev)
 			dev_warn(dev, "Failed to restore pinctrl state\n");
 	}
 
-	pm_runtime_force_resume(dev);
-
-	ret = mmc_gpio_set_cd_wake(host->mmc, false);
+	ret = pm_runtime_force_resume(dev);
 	if (ret)
 		return ret;
 
+	mmc_gpio_set_cd_wake(host->mmc, false);
+
 	/* re-initialize hw state in case it's lost in low power mode */
 	sdhci_esdhc_imx_hwinit(host);
 
@@ -2153,7 +2157,7 @@ static int sdhci_esdhc_resume(struct device *dev)
 
 	pm_runtime_put_autosuspend(dev);
 
-	return ret;
+	return 0;
 }
 
 static int sdhci_esdhc_runtime_suspend(struct device *dev)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/5] mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check for tuning save/restore
  2026-06-25 10:59 ` [PATCH v2 1/5] mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check for tuning save/restore ziniu.wang_1
@ 2026-06-25 16:26   ` Frank Li
  0 siblings, 0 replies; 15+ messages in thread
From: Frank Li @ 2026-06-25 16:26 UTC (permalink / raw)
  To: ziniu.wang_1
  Cc: adrian.hunter, ulfh, haibo.chen, Frank.Li, s.hauer, kernel,
	festevam, imx, linux-mmc, s32, linux-arm-kernel, linux-kernel

On Thu, Jun 25, 2026 at 06:59:30PM +0800, ziniu.wang_1@oss.nxp.com wrote:
> From: Luke Wang <ziniu.wang_1@nxp.com>
>
> The tuning save/restore during system PM is conditioned on
> mmc_card_wake_sdio_irq(), but this check is unrelated to whether
> tuning values need to be preserved. The actual requirement is that
> the card keeps power during suspend and the controller is a uSDHC.
>
> SDIO devices using out-of-band GPIO wakeup maintain power during
> suspend but do not set the SDIO IRQ wake flag. In this case the
> tuning delay values are not saved/restored.
>
> Remove the unnecessary mmc_card_wake_sdio_irq() condition from both
> the suspend save and resume restore paths.
>
> Fixes: c63d25cdc59a ("mmc: sdhci-esdhc-imx: Save tuning value when card stays powered in suspend")
> Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 18ecddd6df6f..6526d65538de 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -2064,8 +2064,7 @@ static int sdhci_esdhc_suspend(struct device *dev)
>  	 * to save the tuning delay value just in case the usdhc
>  	 * lost power during system PM.
>  	 */
> -	if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) &&
> -	    esdhc_is_usdhc(imx_data))
> +	if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
>  		sdhc_esdhc_tuning_save(host);
>
>  	if (device_may_wakeup(dev)) {
> @@ -2124,8 +2123,7 @@ static int sdhci_esdhc_resume(struct device *dev)
>  	 * restore the saved tuning delay value for the device which keep
>  	 * power during system PM.
>  	 */
> -	if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) &&
> -	    esdhc_is_usdhc(imx_data))
> +	if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
>  		sdhc_esdhc_tuning_restore(host);
>
>  	pm_runtime_put_autosuspend(dev);
> --
> 2.34.1
>
>


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/5] mmc: sdhci-esdhc-imx: restore DLL override for DDR modes on resume
  2026-06-25 10:59 ` [PATCH v2 2/5] mmc: sdhci-esdhc-imx: restore DLL override for DDR modes on resume ziniu.wang_1
@ 2026-06-25 16:29   ` Frank Li
  0 siblings, 0 replies; 15+ messages in thread
From: Frank Li @ 2026-06-25 16:29 UTC (permalink / raw)
  To: ziniu.wang_1
  Cc: adrian.hunter, ulfh, haibo.chen, Frank.Li, s.hauer, kernel,
	festevam, imx, linux-mmc, s32, linux-arm-kernel, linux-kernel

On Thu, Jun 25, 2026 at 06:59:31PM +0800, ziniu.wang_1@oss.nxp.com wrote:
> From: Luke Wang <ziniu.wang_1@nxp.com>
>
> sdhci_esdhc_imx_hwinit() unconditionally clears ESDHC_DLL_CTRL by
> writing zero. For SDIO devices that keep power during system suspend
> and operate in DDR mode, the card remains in DDR timing while the host
> DLL override configuration is lost.
>
> Extract the DLL override setup from esdhc_set_uhs_signaling() into
> a helper esdhc_set_dll_override(), and call it on the resume path
> when the card kept power and is using a DDR timing mode.
>
> Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM logic")
> Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/mmc/host/sdhci-esdhc-imx.c | 38 ++++++++++++++++++++++--------
>  1 file changed, 28 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 6526d65538de..a944351dbcdf 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -1349,6 +1349,23 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
>  	return pinctrl_select_state(imx_data->pinctrl, pinctrl);
>  }
>
> +static void esdhc_set_dll_override(struct sdhci_host *host)
> +{
> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
> +	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
> +	u32 v;
> +
> +	if (!boarddata->delay_line)
> +		return;
> +
> +	v = boarddata->delay_line << ESDHC_DLL_OVERRIDE_VAL_SHIFT |
> +	    (1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
> +	if (is_imx53_esdhc(imx_data))
> +		v <<= 1;
> +	writel(v, host->ioaddr + ESDHC_DLL_CTRL);
> +}
> +
>  /*
>   * For HS400 eMMC, there is a data_strobe line. This signal is generated
>   * by the device and used for data output and CRC status response output
> @@ -1425,15 +1442,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
>  		m |= ESDHC_MIX_CTRL_DDREN;
>  		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
>  		imx_data->is_ddr = 1;
> -		if (boarddata->delay_line) {
> -			u32 v;
> -			v = boarddata->delay_line <<
> -				ESDHC_DLL_OVERRIDE_VAL_SHIFT |
> -				(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
> -			if (is_imx53_esdhc(imx_data))
> -				v <<= 1;
> -			writel(v, host->ioaddr + ESDHC_DLL_CTRL);
> -		}
> +		esdhc_set_dll_override(host);
>  		break;
>  	case MMC_TIMING_MMC_HS400:
>  		m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
> @@ -2123,9 +2132,18 @@ static int sdhci_esdhc_resume(struct device *dev)
>  	 * restore the saved tuning delay value for the device which keep
>  	 * power during system PM.
>  	 */
> -	if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
> +	if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data)) {
>  		sdhc_esdhc_tuning_restore(host);
>
> +		/*
> +		 * Restore DLL override for DDR modes. hwinit unconditionally
> +		 * clears ESDHC_DLL_CTRL, but the card is still in DDR mode.
> +		 */
> +		if (host->timing == MMC_TIMING_UHS_DDR50 ||
> +		    host->timing == MMC_TIMING_MMC_DDR52)
> +			esdhc_set_dll_override(host);
> +	}
> +
>  	pm_runtime_put_autosuspend(dev);
>
>  	return ret;
> --
> 2.34.1
>
>


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 3/5] mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing on resume
  2026-06-25 10:59 ` [PATCH v2 3/5] mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing " ziniu.wang_1
@ 2026-06-25 16:35   ` Frank Li
  2026-06-26  6:03     ` Luke Wang (OSS)
  0 siblings, 1 reply; 15+ messages in thread
From: Frank Li @ 2026-06-25 16:35 UTC (permalink / raw)
  To: ziniu.wang_1
  Cc: adrian.hunter, ulfh, haibo.chen, Frank.Li, s.hauer, kernel,
	festevam, imx, linux-mmc, s32, linux-arm-kernel, linux-kernel

On Thu, Jun 25, 2026 at 06:59:32PM +0800, ziniu.wang_1@oss.nxp.com wrote:
> From: Luke Wang <ziniu.wang_1@nxp.com>
>
> SDIO devices such as WiFi may keep power during suspend, so the MMC
> core skips full card re-initialization on resume and directly restores
> the host controller's ios timing to match the card. For DDR mode,
> pm_runtime_force_resume() sets DDR_EN before the pin configuration is
> restored from sleep state. When DDR_EN is set while the pinctrl is still
> muxed to GPIO or other non-uSDHC function, the loopback clock from the
> external pad is not valid, resulting in an incorrect internal sampling
> point being selected. This causes persistent read CRC errors on subsequent
> data transfers, even after the pinctrl is later configured correctly.
>
> SD/eMMC running in DDR mode are unaffected as they are fully re-initialized
> from legacy timing after resume.
>
> Fix this by restoring the pinctrl state based on current timing mode
> using esdhc_change_pinstate() before pm_runtime_force_resume(). This
> ensures the correct pin configuration (e.g., 100/200MHz for UHS modes)
> is applied. Only restore for non-wakeup devices since wakeup devices
> kept their active pin state during suspend to avoid glitching the SD
> bus pins for powered SDIO cards.

pin state change should only impact driver strength, why cause glitch ?

Frank
>
> Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM logic")
> Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++++++
>  1 file changed, 6 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index a944351dbcdf..7fcaecdd4ec6 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -2114,6 +2114,12 @@ static int sdhci_esdhc_resume(struct device *dev)
>  	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
>  	int ret;
>
> +	if (!device_may_wakeup(dev)) {
> +		ret = esdhc_change_pinstate(host, host->timing);
> +		if (ret)
> +			dev_warn(dev, "Failed to restore pinctrl state\n");
> +	}
>  	pm_runtime_force_resume(dev);
>
>  	ret = mmc_gpio_set_cd_wake(host->mmc, false);
> --
> 2.34.1
>
>


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 4/5] mmc: sdhci-esdhc-imx: disable irq during suspend to fix unhandled interrupt
  2026-06-25 10:59 ` [PATCH v2 4/5] mmc: sdhci-esdhc-imx: disable irq during suspend to fix unhandled interrupt ziniu.wang_1
@ 2026-06-25 16:37   ` Frank Li
  2026-06-26  6:04     ` Luke Wang (OSS)
  0 siblings, 1 reply; 15+ messages in thread
From: Frank Li @ 2026-06-25 16:37 UTC (permalink / raw)
  To: ziniu.wang_1
  Cc: adrian.hunter, ulfh, haibo.chen, Frank.Li, s.hauer, kernel,
	festevam, imx, linux-mmc, s32, linux-arm-kernel, linux-kernel

On Thu, Jun 25, 2026 at 06:59:33PM +0800, ziniu.wang_1@oss.nxp.com wrote:
> From: Luke Wang <ziniu.wang_1@nxp.com>
>
> When using WIFI out-of-band wakeup, an "irq xxx: nobody cared" warning
> occurs. This happens because the usdhc interrupt is not disabled during
> system suspend when device_may_wakeup() returns false.
>
> The sequence of events leading to this issue:
> 1. System enters suspend without disabling usdhc interrupt
> (because device_may_wakeup() returns false for usdhc device)
> 2. WIFI out-of-band wakeup triggers system resume via GPIO interrupt
> 3. WIFI sends a Card interrupt before usdhc has fully resumed
> 4. usdhc is still in runtime suspend state and cannot handle the
> interrupt properly
> 5. The unhandled interrupt triggers "nobody cared" warning
>
> Fix this by unconditionally disabling the usdhc interrupt during suspend
> and re-enabling it during resume, regardless of the wakeup capability.
> This ensures no interrupts are processed during the suspend/resume
> transition.

Does it impact the case if WIFI don't use out-of-band wakeup?

Frank
>
> Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM logic")
> Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c | 11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 7fcaecdd4ec6..c4a22e42628e 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -2076,9 +2076,10 @@ static int sdhci_esdhc_suspend(struct device *dev)
>  	if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
>  		sdhc_esdhc_tuning_save(host);
>
> +	/* The irqs of imx are not shared. It is safe to disable */
> +	disable_irq(host->irq);
> +
>  	if (device_may_wakeup(dev)) {
> -		/* The irqs of imx are not shared. It is safe to disable */
> -		disable_irq(host->irq);
>  		ret = sdhci_enable_irq_wakeups(host);
>  		if (!ret)
>  			dev_warn(dev, "Failed to enable irq wakeup\n");
> @@ -2129,10 +2130,10 @@ static int sdhci_esdhc_resume(struct device *dev)
>  	/* re-initialize hw state in case it's lost in low power mode */
>  	sdhci_esdhc_imx_hwinit(host);
>
> -	if (host->irq_wake_enabled) {
> +	if (host->irq_wake_enabled)
>  		sdhci_disable_irq_wakeups(host);
> -		enable_irq(host->irq);
> -	}
> +
> +	enable_irq(host->irq);
>
>  	/*
>  	 * restore the saved tuning delay value for the device which keep
> --
> 2.34.1
>
>


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 5/5] mmc: sdhci-esdhc-imx: fix suspend/resume error handling
  2026-06-25 10:59 ` [PATCH v2 5/5] mmc: sdhci-esdhc-imx: fix suspend/resume error handling ziniu.wang_1
@ 2026-06-25 16:39   ` Frank Li
  2026-06-26  6:07     ` Luke Wang (OSS)
  0 siblings, 1 reply; 15+ messages in thread
From: Frank Li @ 2026-06-25 16:39 UTC (permalink / raw)
  To: ziniu.wang_1
  Cc: adrian.hunter, ulfh, haibo.chen, Frank.Li, s.hauer, kernel,
	festevam, imx, linux-mmc, s32, linux-arm-kernel, linux-kernel

On Thu, Jun 25, 2026 at 06:59:34PM +0800, ziniu.wang_1@oss.nxp.com wrote:
> From: Luke Wang <ziniu.wang_1@nxp.com>
>
> Fix several error handling issues in sdhci_esdhc_suspend/resume:
>
> 1. Use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
>    to simplify error handling. If it fails, the device is unclocked
>    and accessing hardware registers would cause a kernel panic.
>
> 2. Make pinctrl_pm_select_sleep_state() and mmc_gpio_set_cd_wake()
>    failures non-fatal in suspend path. These failures only mean
>    slightly higher power consumption or missing CD wakeup, but should
>    not block system suspend.
>
> 3. Check pm_runtime_force_resume() return value in resume. If it
>    fails (clock enable failure), return immediately since accessing
>    hardware registers on an unclocked device would cause a panic.
>
> 4. Make mmc_gpio_set_cd_wake(false) call in resume not check return
>    value since it always returns 0.
>
> 5. Always return 0 on success path instead of propagating non-fatal
>    warning return values.

each patch fix one problem.

Frank

>
> Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c | 18 +++++++++++-------
>  1 file changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index c4a22e42628e..4d6818c95809 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -2060,7 +2060,9 @@ static int sdhci_esdhc_suspend(struct device *dev)
>  	 * 2, make sure the pm_runtime_force_resume() in sdhci_esdhc_resume() really
>  	 *    invoke its ->runtime_resume callback (needs_force_resume = 1).
>  	 */
> -	pm_runtime_get_sync(dev);
> +	ret = pm_runtime_resume_and_get(dev);
> +	if (ret)
> +		return ret;
>
>  	if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
>  		(host->tuning_mode != SDHCI_TUNING_MODE_1)) {
> @@ -2094,10 +2096,12 @@ static int sdhci_esdhc_suspend(struct device *dev)
>  		 */
>  		ret = pinctrl_pm_select_sleep_state(dev);
>  		if (ret)
> -			return ret;
> +			dev_warn(dev, "Failed to select sleep pinctrl state\n");
>  	}
>
>  	ret = mmc_gpio_set_cd_wake(host->mmc, true);
> +	if (ret)
> +		dev_warn(dev, "Failed to enable cd wake\n");
>
>  	/*
>  	 * Make sure invoke runtime_suspend to gate off clock.
> @@ -2105,7 +2109,7 @@ static int sdhci_esdhc_suspend(struct device *dev)
>  	 */
>  	pm_runtime_force_suspend(dev);
>
> -	return ret;
> +	return 0;
>  }
>
>  static int sdhci_esdhc_resume(struct device *dev)
> @@ -2121,12 +2125,12 @@ static int sdhci_esdhc_resume(struct device *dev)
>  			dev_warn(dev, "Failed to restore pinctrl state\n");
>  	}
>
> -	pm_runtime_force_resume(dev);
> -
> -	ret = mmc_gpio_set_cd_wake(host->mmc, false);
> +	ret = pm_runtime_force_resume(dev);
>  	if (ret)
>  		return ret;
>
> +	mmc_gpio_set_cd_wake(host->mmc, false);
> +
>  	/* re-initialize hw state in case it's lost in low power mode */
>  	sdhci_esdhc_imx_hwinit(host);
>
> @@ -2153,7 +2157,7 @@ static int sdhci_esdhc_resume(struct device *dev)
>
>  	pm_runtime_put_autosuspend(dev);
>
> -	return ret;
> +	return 0;
>  }
>
>  static int sdhci_esdhc_runtime_suspend(struct device *dev)
> --
> 2.34.1
>
>


^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH v2 3/5] mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing on resume
  2026-06-25 16:35   ` Frank Li
@ 2026-06-26  6:03     ` Luke Wang (OSS)
  2026-06-26  6:58       ` Bough Chen
  0 siblings, 1 reply; 15+ messages in thread
From: Luke Wang (OSS) @ 2026-06-26  6:03 UTC (permalink / raw)
  To: Frank Li (OSS), Luke Wang (OSS)
  Cc: adrian.hunter@intel.com, ulfh@kernel.org, Bough Chen, Frank Li,
	s.hauer@pengutronix.de, kernel@pengutronix.de, festevam@gmail.com,
	imx@lists.linux.dev, linux-mmc@vger.kernel.org, dl-S32,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org



> -----Original Message-----
> From: Frank Li (OSS) <frank.li@oss.nxp.com>
> Sent: Friday, June 26, 2026 12:36 AM
> To: Luke Wang (OSS) <ziniu.wang_1@oss.nxp.com>
> Cc: adrian.hunter@intel.com; ulfh@kernel.org; Bough Chen
> <haibo.chen@nxp.com>; Frank Li <frank.li@nxp.com>;
> s.hauer@pengutronix.de; kernel@pengutronix.de; festevam@gmail.com;
> imx@lists.linux.dev; linux-mmc@vger.kernel.org; dl-S32 <S32@nxp.com>;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v2 3/5] mmc: sdhci-esdhc-imx: restore pinctrl before
> restoring ios timing on resume
> 
> On Thu, Jun 25, 2026 at 06:59:32PM +0800, ziniu.wang_1@oss.nxp.com
> wrote:
> > From: Luke Wang <ziniu.wang_1@nxp.com>
> >
> > SDIO devices such as WiFi may keep power during suspend, so the MMC
> > core skips full card re-initialization on resume and directly restores
> > the host controller's ios timing to match the card. For DDR mode,
> > pm_runtime_force_resume() sets DDR_EN before the pin configuration is
> > restored from sleep state. When DDR_EN is set while the pinctrl is still
> > muxed to GPIO or other non-uSDHC function, the loopback clock from the
> > external pad is not valid, resulting in an incorrect internal sampling
> > point being selected. This causes persistent read CRC errors on subsequent
> > data transfers, even after the pinctrl is later configured correctly.
> >
> > SD/eMMC running in DDR mode are unaffected as they are fully re-
> initialized
> > from legacy timing after resume.
> >
> > Fix this by restoring the pinctrl state based on current timing mode
> > using esdhc_change_pinstate() before pm_runtime_force_resume(). This
> > ensures the correct pin configuration (e.g., 100/200MHz for UHS modes)
> > is applied. Only restore for non-wakeup devices since wakeup devices
> > kept their active pin state during suspend to avoid glitching the SD
> > bus pins for powered SDIO cards.
> 
> pin state change should only impact driver strength, why cause glitch ?

You're right that switching driver strength alone won't cause a glitch. 
The issue is more specific to the sleep pinctrl state: the uSDHC clock pin is
low when the clock is stopped, but the sleep pinctrl enables a pull-up on that
pin, driving it high during suspend. When we switch back to the uSDHC function
pinctrl on resume, the pin transitions from high back to low, generating 
a falling edge glitch.

I'll update the commit message in v3 to clarify this.

Thanks, 
Luke

> 
> Frank
> >
> > Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM
> logic")
> > Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
> > ---
> >  drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++++++
> >  1 file changed, 6 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-
> esdhc-imx.c
> > index a944351dbcdf..7fcaecdd4ec6 100644
> > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > @@ -2114,6 +2114,12 @@ static int sdhci_esdhc_resume(struct device
> *dev)
> >  	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
> >  	int ret;
> >
> > +	if (!device_may_wakeup(dev)) {
> > +		ret = esdhc_change_pinstate(host, host->timing);
> > +		if (ret)
> > +			dev_warn(dev, "Failed to restore pinctrl state\n");
> > +	}
> >  	pm_runtime_force_resume(dev);
> >
> >  	ret = mmc_gpio_set_cd_wake(host->mmc, false);
> > --
> > 2.34.1
> >
> >


^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH v2 4/5] mmc: sdhci-esdhc-imx: disable irq during suspend to fix unhandled interrupt
  2026-06-25 16:37   ` Frank Li
@ 2026-06-26  6:04     ` Luke Wang (OSS)
  0 siblings, 0 replies; 15+ messages in thread
From: Luke Wang (OSS) @ 2026-06-26  6:04 UTC (permalink / raw)
  To: Frank Li (OSS), Luke Wang (OSS)
  Cc: adrian.hunter@intel.com, ulfh@kernel.org, Bough Chen, Frank Li,
	s.hauer@pengutronix.de, kernel@pengutronix.de, festevam@gmail.com,
	imx@lists.linux.dev, linux-mmc@vger.kernel.org, dl-S32,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org



> -----Original Message-----
> From: Frank Li (OSS) <frank.li@oss.nxp.com>
> Sent: Friday, June 26, 2026 12:38 AM
> To: Luke Wang (OSS) <ziniu.wang_1@oss.nxp.com>
> Cc: adrian.hunter@intel.com; ulfh@kernel.org; Bough Chen
> <haibo.chen@nxp.com>; Frank Li <frank.li@nxp.com>;
> s.hauer@pengutronix.de; kernel@pengutronix.de; festevam@gmail.com;
> imx@lists.linux.dev; linux-mmc@vger.kernel.org; dl-S32 <S32@nxp.com>;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v2 4/5] mmc: sdhci-esdhc-imx: disable irq during
> suspend to fix unhandled interrupt
> 
> On Thu, Jun 25, 2026 at 06:59:33PM +0800, ziniu.wang_1@oss.nxp.com
> wrote:
> > From: Luke Wang <ziniu.wang_1@nxp.com>
> >
> > When using WIFI out-of-band wakeup, an "irq xxx: nobody cared" warning
> > occurs. This happens because the usdhc interrupt is not disabled during
> > system suspend when device_may_wakeup() returns false.
> >
> > The sequence of events leading to this issue:
> > 1. System enters suspend without disabling usdhc interrupt
> > (because device_may_wakeup() returns false for usdhc device)
> > 2. WIFI out-of-band wakeup triggers system resume via GPIO interrupt
> > 3. WIFI sends a Card interrupt before usdhc has fully resumed
> > 4. usdhc is still in runtime suspend state and cannot handle the
> > interrupt properly
> > 5. The unhandled interrupt triggers "nobody cared" warning
> >
> > Fix this by unconditionally disabling the usdhc interrupt during suspend
> > and re-enabling it during resume, regardless of the wakeup capability.
> > This ensures no interrupts are processed during the suspend/resume
> > transition.
> 
> Does it impact the case if WIFI don't use out-of-band wakeup?

It doesn't impact other cases.

Thanks,
Luke

> 
> Frank
> >
> > Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM
> logic")
> > Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
> > ---
> >  drivers/mmc/host/sdhci-esdhc-imx.c | 11 ++++++-----
> >  1 file changed, 6 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-
> esdhc-imx.c
> > index 7fcaecdd4ec6..c4a22e42628e 100644
> > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > @@ -2076,9 +2076,10 @@ static int sdhci_esdhc_suspend(struct device
> *dev)
> >  	if (mmc_card_keep_power(host->mmc) &&
> esdhc_is_usdhc(imx_data))
> >  		sdhc_esdhc_tuning_save(host);
> >
> > +	/* The irqs of imx are not shared. It is safe to disable */
> > +	disable_irq(host->irq);
> > +
> >  	if (device_may_wakeup(dev)) {
> > -		/* The irqs of imx are not shared. It is safe to disable */
> > -		disable_irq(host->irq);
> >  		ret = sdhci_enable_irq_wakeups(host);
> >  		if (!ret)
> >  			dev_warn(dev, "Failed to enable irq wakeup\n");
> > @@ -2129,10 +2130,10 @@ static int sdhci_esdhc_resume(struct device
> *dev)
> >  	/* re-initialize hw state in case it's lost in low power mode */
> >  	sdhci_esdhc_imx_hwinit(host);
> >
> > -	if (host->irq_wake_enabled) {
> > +	if (host->irq_wake_enabled)
> >  		sdhci_disable_irq_wakeups(host);
> > -		enable_irq(host->irq);
> > -	}
> > +
> > +	enable_irq(host->irq);
> >
> >  	/*
> >  	 * restore the saved tuning delay value for the device which keep
> > --
> > 2.34.1
> >
> >


^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH v2 5/5] mmc: sdhci-esdhc-imx: fix suspend/resume error handling
  2026-06-25 16:39   ` Frank Li
@ 2026-06-26  6:07     ` Luke Wang (OSS)
  0 siblings, 0 replies; 15+ messages in thread
From: Luke Wang (OSS) @ 2026-06-26  6:07 UTC (permalink / raw)
  To: Frank Li (OSS), Luke Wang (OSS)
  Cc: adrian.hunter@intel.com, ulfh@kernel.org, Bough Chen, Frank Li,
	s.hauer@pengutronix.de, kernel@pengutronix.de, festevam@gmail.com,
	imx@lists.linux.dev, linux-mmc@vger.kernel.org, dl-S32,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org



> -----Original Message-----
> From: Frank Li (OSS) <frank.li@oss.nxp.com>
> Sent: Friday, June 26, 2026 12:40 AM
> To: Luke Wang (OSS) <ziniu.wang_1@oss.nxp.com>
> Cc: adrian.hunter@intel.com; ulfh@kernel.org; Bough Chen
> <haibo.chen@nxp.com>; Frank Li <frank.li@nxp.com>;
> s.hauer@pengutronix.de; kernel@pengutronix.de; festevam@gmail.com;
> imx@lists.linux.dev; linux-mmc@vger.kernel.org; dl-S32 <S32@nxp.com>;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v2 5/5] mmc: sdhci-esdhc-imx: fix suspend/resume error
> handling
> 
> On Thu, Jun 25, 2026 at 06:59:34PM +0800, ziniu.wang_1@oss.nxp.com
> wrote:
> > From: Luke Wang <ziniu.wang_1@nxp.com>
> >
> > Fix several error handling issues in sdhci_esdhc_suspend/resume:
> >
> > 1. Use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
> >    to simplify error handling. If it fails, the device is unclocked
> >    and accessing hardware registers would cause a kernel panic.
> >
> > 2. Make pinctrl_pm_select_sleep_state() and mmc_gpio_set_cd_wake()
> >    failures non-fatal in suspend path. These failures only mean
> >    slightly higher power consumption or missing CD wakeup, but should
> >    not block system suspend.
> >
> > 3. Check pm_runtime_force_resume() return value in resume. If it
> >    fails (clock enable failure), return immediately since accessing
> >    hardware registers on an unclocked device would cause a panic.
> >
> > 4. Make mmc_gpio_set_cd_wake(false) call in resume not check return
> >    value since it always returns 0.
> >
> > 5. Always return 0 on success path instead of propagating non-fatal
> >    warning return values.
> 
> each patch fix one problem.

I will split this patch in v3

Thanks,
Luke

> 
> Frank
> 
> >
> > Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
> > ---
> >  drivers/mmc/host/sdhci-esdhc-imx.c | 18 +++++++++++-------
> >  1 file changed, 11 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-
> esdhc-imx.c
> > index c4a22e42628e..4d6818c95809 100644
> > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > @@ -2060,7 +2060,9 @@ static int sdhci_esdhc_suspend(struct device
> *dev)
> >  	 * 2, make sure the pm_runtime_force_resume() in
> sdhci_esdhc_resume() really
> >  	 *    invoke its ->runtime_resume callback (needs_force_resume = 1).
> >  	 */
> > -	pm_runtime_get_sync(dev);
> > +	ret = pm_runtime_resume_and_get(dev);
> > +	if (ret)
> > +		return ret;
> >
> >  	if ((imx_data->socdata->flags &
> ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
> >  		(host->tuning_mode != SDHCI_TUNING_MODE_1)) {
> > @@ -2094,10 +2096,12 @@ static int sdhci_esdhc_suspend(struct device
> *dev)
> >  		 */
> >  		ret = pinctrl_pm_select_sleep_state(dev);
> >  		if (ret)
> > -			return ret;
> > +			dev_warn(dev, "Failed to select sleep pinctrl
> state\n");
> >  	}
> >
> >  	ret = mmc_gpio_set_cd_wake(host->mmc, true);
> > +	if (ret)
> > +		dev_warn(dev, "Failed to enable cd wake\n");
> >
> >  	/*
> >  	 * Make sure invoke runtime_suspend to gate off clock.
> > @@ -2105,7 +2109,7 @@ static int sdhci_esdhc_suspend(struct device
> *dev)
> >  	 */
> >  	pm_runtime_force_suspend(dev);
> >
> > -	return ret;
> > +	return 0;
> >  }
> >
> >  static int sdhci_esdhc_resume(struct device *dev)
> > @@ -2121,12 +2125,12 @@ static int sdhci_esdhc_resume(struct device
> *dev)
> >  			dev_warn(dev, "Failed to restore pinctrl state\n");
> >  	}
> >
> > -	pm_runtime_force_resume(dev);
> > -
> > -	ret = mmc_gpio_set_cd_wake(host->mmc, false);
> > +	ret = pm_runtime_force_resume(dev);
> >  	if (ret)
> >  		return ret;
> >
> > +	mmc_gpio_set_cd_wake(host->mmc, false);
> > +
> >  	/* re-initialize hw state in case it's lost in low power mode */
> >  	sdhci_esdhc_imx_hwinit(host);
> >
> > @@ -2153,7 +2157,7 @@ static int sdhci_esdhc_resume(struct device
> *dev)
> >
> >  	pm_runtime_put_autosuspend(dev);
> >
> > -	return ret;
> > +	return 0;
> >  }
> >
> >  static int sdhci_esdhc_runtime_suspend(struct device *dev)
> > --
> > 2.34.1
> >
> >


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 3/5] mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing on resume
  2026-06-26  6:03     ` Luke Wang (OSS)
@ 2026-06-26  6:58       ` Bough Chen
  0 siblings, 0 replies; 15+ messages in thread
From: Bough Chen @ 2026-06-26  6:58 UTC (permalink / raw)
  To: Luke Wang (OSS)
  Cc: Frank Li (OSS), adrian.hunter@intel.com, ulfh@kernel.org,
	Bough Chen, Frank Li, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com, imx@lists.linux.dev,
	linux-mmc@vger.kernel.org, dl-S32,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org

On Fri, Jun 26, 2026 at 06:03:05AM +0000, Luke Wang (OSS) wrote:
> 
> 
> > -----Original Message-----
> > From: Frank Li (OSS) <frank.li@oss.nxp.com>
> > Sent: Friday, June 26, 2026 12:36 AM
> > To: Luke Wang (OSS) <ziniu.wang_1@oss.nxp.com>
> > Cc: adrian.hunter@intel.com; ulfh@kernel.org; Bough Chen
> > <haibo.chen@nxp.com>; Frank Li <frank.li@nxp.com>;
> > s.hauer@pengutronix.de; kernel@pengutronix.de; festevam@gmail.com;
> > imx@lists.linux.dev; linux-mmc@vger.kernel.org; dl-S32 <S32@nxp.com>;
> > linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> > Subject: Re: [PATCH v2 3/5] mmc: sdhci-esdhc-imx: restore pinctrl before
> > restoring ios timing on resume
> > 
> > On Thu, Jun 25, 2026 at 06:59:32PM +0800, ziniu.wang_1@oss.nxp.com
> > wrote:
> > > From: Luke Wang <ziniu.wang_1@nxp.com>
> > >
> > > SDIO devices such as WiFi may keep power during suspend, so the MMC
> > > core skips full card re-initialization on resume and directly restores
> > > the host controller's ios timing to match the card. For DDR mode,
> > > pm_runtime_force_resume() sets DDR_EN before the pin configuration is
> > > restored from sleep state. When DDR_EN is set while the pinctrl is still
> > > muxed to GPIO or other non-uSDHC function, the loopback clock from the
> > > external pad is not valid, resulting in an incorrect internal sampling
> > > point being selected. This causes persistent read CRC errors on subsequent
> > > data transfers, even after the pinctrl is later configured correctly.
> > >
> > > SD/eMMC running in DDR mode are unaffected as they are fully re-
> > initialized
> > > from legacy timing after resume.
> > >
> > > Fix this by restoring the pinctrl state based on current timing mode
> > > using esdhc_change_pinstate() before pm_runtime_force_resume(). This
> > > ensures the correct pin configuration (e.g., 100/200MHz for UHS modes)
> > > is applied. Only restore for non-wakeup devices since wakeup devices
> > > kept their active pin state during suspend to avoid glitching the SD
> > > bus pins for powered SDIO cards.
> > 
> > pin state change should only impact driver strength, why cause glitch ?
> 
> You're right that switching driver strength alone won't cause a glitch. 
> The issue is more specific to the sleep pinctrl state: the uSDHC clock pin is
> low when the clock is stopped, but the sleep pinctrl enables a pull-up on that
> pin, driving it high during suspend. When we switch back to the uSDHC function
> pinctrl on resume, the pin transitions from high back to low, generating 
> a falling edge glitch.
> 
> I'll update the commit message in v3 to clarify this.

The glitch should be related to the SoC IP intergration, switch pinctrl setting
(change alt from GPIO to USDHC) impact the internal loopback path. If pinctrl
config the pad to GPIO function, once DDR_EN configed, the dll delay will fix
based on the GPIO function loopback path, but then change the pinctrl to function
USDHC, the internal loopback path change, the original fixed sample point maybe
not suitable for current loopback path.

Luke, please add this in the commit log.

Regards
Haibo Chen
> 
> Thanks, 
> Luke
> 
> > 
> > Frank
> > >
> > > Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM
> > logic")
> > > Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
> > > ---
> > >  drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++++++
> > >  1 file changed, 6 insertions(+)
> > >
> > > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-
> > esdhc-imx.c
> > > index a944351dbcdf..7fcaecdd4ec6 100644
> > > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > > @@ -2114,6 +2114,12 @@ static int sdhci_esdhc_resume(struct device
> > *dev)
> > >  	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
> > >  	int ret;
> > >
> > > +	if (!device_may_wakeup(dev)) {
> > > +		ret = esdhc_change_pinstate(host, host->timing);
> > > +		if (ret)
> > > +			dev_warn(dev, "Failed to restore pinctrl state\n");
> > > +	}
> > >  	pm_runtime_force_resume(dev);
> > >
> > >  	ret = mmc_gpio_set_cd_wake(host->mmc, false);
> > > --
> > > 2.34.1
> > >
> > >


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-06-26  7:03 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-25 10:59 [PATCH v2 0/5] mmc: sdhci-esdhc-imx: fix SDIO suspend/resume issues ziniu.wang_1
2026-06-25 10:59 ` [PATCH v2 1/5] mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check for tuning save/restore ziniu.wang_1
2026-06-25 16:26   ` Frank Li
2026-06-25 10:59 ` [PATCH v2 2/5] mmc: sdhci-esdhc-imx: restore DLL override for DDR modes on resume ziniu.wang_1
2026-06-25 16:29   ` Frank Li
2026-06-25 10:59 ` [PATCH v2 3/5] mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing " ziniu.wang_1
2026-06-25 16:35   ` Frank Li
2026-06-26  6:03     ` Luke Wang (OSS)
2026-06-26  6:58       ` Bough Chen
2026-06-25 10:59 ` [PATCH v2 4/5] mmc: sdhci-esdhc-imx: disable irq during suspend to fix unhandled interrupt ziniu.wang_1
2026-06-25 16:37   ` Frank Li
2026-06-26  6:04     ` Luke Wang (OSS)
2026-06-25 10:59 ` [PATCH v2 5/5] mmc: sdhci-esdhc-imx: fix suspend/resume error handling ziniu.wang_1
2026-06-25 16:39   ` Frank Li
2026-06-26  6:07     ` Luke Wang (OSS)

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