From 89c378d9ac5422f31e2e298a591faed650e5519d Mon Sep 17 00:00:00 2001 From: DuoYuWang Date: Fri, 17 Jul 2026 10:54:22 +0800 Subject: [PATCH] arch/arm/src/stm32h7: add 4-bit wide bus support for MMC/eMMC cards The STM32H7 SDMMC driver never programs the WIDBUS bits for MMC cards: stm32_widebus() only records the requested state and the MMC transfer clock preset STM32_SDMMC_CLKCR_MMCXFR is hardwired to WIDBUS_D1. When the mmcsd layer switches an eMMC device to 4-bit mode via CMD6, the host controller stays in 1-bit mode and all subsequent data transfers fail with a bus width mismatch. Program the WIDBUS bits in stm32_widebus() so the host bus width follows the card, and add a CLOCK_MMC_TRANSFER_4BIT clock preset (enum sdio_clock_e extended accordingly). Power saving is disabled in 4-bit mode, same as for the SD 4-bit preset STM32_SDMMC_CLCKR_SDWIDEXFR. Tested on a custom STM32H743 board with eMMC (sd_bench: sequential write ~4.0 MB/s, sequential read ~6.3 MB/s). Signed-off-by: DuoYuWang --- arch/arm/src/stm32h7/stm32_sdmmc.c | 27 +++++++++++++++++++++++++++ include/nuttx/sdio.h | 5 +++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/arch/arm/src/stm32h7/stm32_sdmmc.c b/arch/arm/src/stm32h7/stm32_sdmmc.c index 0e713eadb0795..f1419f258c87c 100644 --- a/arch/arm/src/stm32h7/stm32_sdmmc.c +++ b/arch/arm/src/stm32h7/stm32_sdmmc.c @@ -210,6 +210,10 @@ STM32_SDMMC_CLKCR_EDGE | \ STM32_SDMMC_CLKCR_PWRSAV | \ STM32_SDMMC_CLKCR_WIDBUS_D1) +#define STM32_SDMMC_CLKCR_MMCXFR4 (STM32_SDMMC_MMCXFR_CLKDIV | \ + STM32_SDMMC_CLKCR_EDGE | \ + STM32_SDMMC_CLKCR_PWRSAV | \ + STM32_SDMMC_CLKCR_WIDBUS_D4) #define STM32_SDMMC_CLCKR_SDXFR (STM32_SDMMC_SDXFR_CLKDIV | \ STM32_SDMMC_CLKCR_EDGE | \ STM32_SDMMC_CLKCR_PWRSAV | \ @@ -2045,7 +2049,24 @@ static sdio_statset_t stm32_status(struct sdio_dev_s *dev) static void stm32_widebus(struct sdio_dev_s *dev, bool wide) { struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; + uint32_t regval; + priv->widebus = wide; + + regval = sdmmc_getreg32(priv, STM32_SDMMC_CLKCR_OFFSET); + regval &= ~STM32_SDMMC_CLKCR_WIDBUS_MASK; + + if (wide) + { + regval |= STM32_SDMMC_CLKCR_WIDBUS_D4; + regval &= ~STM32_SDMMC_CLKCR_PWRSAV; + } + else + { + regval |= STM32_SDMMC_CLKCR_WIDBUS_D1; + } + + sdmmc_putreg32(priv, regval, STM32_SDMMC_CLKCR_OFFSET); } /**************************************************************************** @@ -2089,6 +2110,12 @@ static void stm32_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate) clckr = STM32_SDMMC_CLKCR_MMCXFR; break; + /* Enable in MMC wide (4-bit) operation clocking */ + + case CLOCK_MMC_TRANSFER_4BIT: + clckr = STM32_SDMMC_CLKCR_MMCXFR4; + break; + /* SD normal operation clocking (wide 4-bit mode) */ case CLOCK_SD_TRANSFER_4BIT: diff --git a/include/nuttx/sdio.h b/include/nuttx/sdio.h index 48b5ff66e5276..2a8904f2f75f1 100644 --- a/include/nuttx/sdio.h +++ b/include/nuttx/sdio.h @@ -942,9 +942,10 @@ enum sdio_clock_e { CLOCK_SDIO_DISABLED = 0, /* Clock is disabled */ CLOCK_IDMODE, /* Initial ID mode clocking (<400KHz) */ - CLOCK_MMC_TRANSFER, /* MMC normal operation clocking */ + CLOCK_MMC_TRANSFER, /* MMC normal operation clocking (narrow 1-bit mode) */ CLOCK_SD_TRANSFER_1BIT, /* SD normal operation clocking (narrow 1-bit mode) */ - CLOCK_SD_TRANSFER_4BIT /* SD normal operation clocking (wide 4-bit mode) */ + CLOCK_SD_TRANSFER_4BIT, /* SD normal operation clocking (wide 4-bit mode) */ + CLOCK_MMC_TRANSFER_4BIT /* MMC normal operation clocking (wide 4-bit mode) */ }; /* Event set. A uint8_t is big enough to hold a set of 8-events. If more