[PATCH 1/4] mmc: core: fix timing selection for 1-bit bus width

ziniu.wang_1 at nxp.com ziniu.wang_1 at nxp.com
Mon Mar 2 00:00:54 PST 2026


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

When 1-bit bus width is used with HS200/HS400 capabilities set,
mmc_select_hs200() returns 0 without actually switching. This
causes mmc_select_timing() to skip mmc_select_hs(), leaving eMMC
in legacy mode (26MHz) instead of High Speed SDR (52MHz).

Per JEDEC eMMC spec section 5.3.2, 1-bit width supports High Speed
SDR. Drop incompatible HS200/HS400/UHS/DDR caps early so timing
selection falls through to mmc_select_hs() correctly.

Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
---
 drivers/mmc/core/host.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 88c95dbfd9cf..18b9c3174e1f 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -617,17 +617,26 @@ EXPORT_SYMBOL(devm_mmc_alloc_host);
 static int mmc_validate_host_caps(struct mmc_host *host)
 {
 	struct device *dev = host->parent;
-	u32 caps = host->caps, caps2 = host->caps2;
 
-	if (caps & MMC_CAP_SDIO_IRQ && !host->ops->enable_sdio_irq) {
+	if (host->caps & MMC_CAP_SDIO_IRQ && !host->ops->enable_sdio_irq) {
 		dev_warn(dev, "missing ->enable_sdio_irq() ops\n");
 		return -EINVAL;
 	}
 
-	if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) &&
-	    !(caps & MMC_CAP_8_BIT_DATA) && !(caps2 & MMC_CAP2_NO_MMC)) {
+	/* UHS/DDR/HS200/HS400 modes require at least 4-bit bus */
+	if (!(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) &&
+	    ((host->caps & (MMC_CAP_UHS | MMC_CAP_DDR)) ||
+	     (host->caps2 & (MMC_CAP2_HS200 | MMC_CAP2_HS400_ES | MMC_CAP2_HS400)))) {
+		dev_warn(dev, "drop UHS/DDR/HS200/HS400 support since 1-bit bus only\n");
+		host->caps &= ~(MMC_CAP_UHS | MMC_CAP_DDR);
+		host->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400_ES | MMC_CAP2_HS400);
+	}
+
+	if (host->caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) &&
+	    !(host->caps & MMC_CAP_8_BIT_DATA) &&
+	    !(host->caps2 & MMC_CAP2_NO_MMC)) {
 		dev_warn(dev, "drop HS400 support since no 8-bit bus\n");
-		host->caps2 = caps2 & ~MMC_CAP2_HS400_ES & ~MMC_CAP2_HS400;
+		host->caps2 &= ~(MMC_CAP2_HS400_ES | MMC_CAP2_HS400);
 	}
 
 	return 0;
-- 
2.34.1




More information about the linux-arm-kernel mailing list