summaryrefslogtreecommitdiff
path: root/drivers/mmc/core
diff options
context:
space:
mode:
authorLuke Wang <ziniu.wang_1@nxp.com>2026-03-10 09:35:52 +0800
committerUlf Hansson <ulf.hansson@linaro.org>2026-03-16 15:46:58 +0100
commite98f926e5a2d8023a74ec2ba7a973b5d76610f4e (patch)
tree68ae28ffa3bb63d5fd08c52021609230a6fef4ab /drivers/mmc/core
parentcc1060a18e0464a7b03c06fb64889935d27acee0 (diff)
mmc: core: Validate UHS/DDR/HS200 timing selection for 1-bit bus width
UHS/DDR/HS200 modes require at least 4-bit bus support. Host controllers that lack relevant capability registers rely on paring properties provided by firmware, which may incorrectly set these modes. Now that mmc_validate_host_caps() has been introduced to validate such configuration violations, let's also add checks for UHS/DDR/HS200 modes. This fixes an issue where, if the HS200/HS400 property is set while only a 1-bit bus width is used, mmc_select_hs200() returns 0 without actually performing the mode switch. Consequently, mmc_select_timing() proceeds without falling back to mmc_select_hs(), leaving the eMMC device operating in legacy mode (26 MHz) instead of switching to High Speed mode (52 MHz). Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com> [Shawn: reword the commit msg and rework the code] Signed-off-by: Shawn Lin <shawn.lin@linux.dev> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/host.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 88c95dbfd9cf..a457c88fdcbc 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -624,12 +624,24 @@ static int mmc_validate_host_caps(struct mmc_host *host)
return -EINVAL;
}
+ /* UHS/DDR/HS200 modes require at least 4-bit bus */
+ if (!(caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) &&
+ ((caps & (MMC_CAP_UHS | MMC_CAP_DDR)) || (caps2 & MMC_CAP2_HS200))) {
+ dev_warn(dev, "drop UHS/DDR/HS200 support since 1-bit bus only\n");
+ caps &= ~(MMC_CAP_UHS | MMC_CAP_DDR);
+ caps2 &= ~MMC_CAP2_HS200;
+ }
+
+ /* HS400 and HS400ES modes require 8-bit bus */
if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) &&
!(caps & MMC_CAP_8_BIT_DATA) && !(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;
+ caps2 &= ~(MMC_CAP2_HS400_ES | MMC_CAP2_HS400);
}
+ host->caps = caps;
+ host->caps2 = caps2;
+
return 0;
}