arch/arm/src/stm32{h7,f7,l4}: add 4-bit wide bus support for MMC/eMMC cards

The STM32H7, STM32F7, STM32L4 and common STM32 SDIO/SDMMC drivers failed
to program the WIDBUS bits when switching MMC/eMMC cards to 4-bit mode,
and the MMC transfer clock presets were hardwired to 1-bit bus width.

Add CLOCK_MMC_TRANSFER_4BIT to the common SDIO clock enum, add 4-bit
MMC clock presets, and update stm32_widebus() to use modifyreg32/
sdmmc_modifyreg32 to set the host controller bus width.

Signed-off-by: DuoYuWang <thirteenking.wang@gmail.com>
This commit is contained in:
DuoYuWang 2026-07-21 07:29:52 +08:00 committed by Alan C. Assis
parent 85ad737463
commit 82ab33aed6
5 changed files with 72 additions and 2 deletions

View file

@ -165,6 +165,8 @@
SDIO_CLKCR_WIDBUS_D1)
#define SDIO_CLKCR_MMCXFR (SDIO_MMCXFR_CLKDIV | SDIO_CLKCR_EDGE | \
SDIO_CLKCR_WIDBUS_D1)
#define SDIO_CLKCR_MMCXFR4 (SDIO_MMCXFR_CLKDIV | SDIO_CLKCR_EDGE | \
SDIO_CLKCR_WIDBUS_D4)
#define SDIO_CLCKR_SDXFR (SDIO_SDXFR_CLKDIV | SDIO_CLKCR_EDGE | \
SDIO_CLKCR_WIDBUS_D1)
#define SDIO_CLCKR_SDWIDEXFR (SDIO_SDXFR_CLKDIV | SDIO_CLKCR_EDGE | \
@ -1734,7 +1736,11 @@ 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 widbus = wide ? SDIO_CLKCR_WIDBUS_D4 : SDIO_CLKCR_WIDBUS_D1;
priv->widebus = wide;
modifyreg32(STM32_SDIO_CLKCR, SDIO_CLKCR_WIDBUS_MASK, widbus);
}
/****************************************************************************
@ -1777,6 +1783,12 @@ static void stm32_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate)
clckr = (SDIO_CLKCR_MMCXFR | SDIO_CLKCR_CLKEN);
break;
/* Enable in MMC wide (4-bit) operation clocking */
case CLOCK_MMC_TRANSFER_4BIT:
clckr = (SDIO_CLKCR_MMCXFR4 | SDIO_CLKCR_CLKEN);
break;
/* SD normal operation clocking (wide 4-bit mode) */
case CLOCK_SD_TRANSFER_4BIT:

View file

@ -204,6 +204,9 @@
#define STM32_SDMMC_CLKCR_MMCXFR (STM32_SDMMC_MMCXFR_CLKDIV | \
STM32_SDMMC_CLKCR_EDGE | \
STM32_SDMMC_CLKCR_WIDBUS_D1)
#define STM32_SDMMC_CLKCR_MMCXFR4 (STM32_SDMMC_MMCXFR_CLKDIV | \
STM32_SDMMC_CLKCR_EDGE | \
STM32_SDMMC_CLKCR_WIDBUS_D4)
#ifdef STM32_SDMMC_SDXFR_BYPCLKDIV
# define STM32_SDMMC_CLCKR_SDXFR (STM32_SDMMC_CLKCR_BYPASS | \
@ -1991,7 +1994,13 @@ 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 widbus = wide ? STM32_SDMMC_CLKCR_WIDBUS_D4 :
STM32_SDMMC_CLKCR_WIDBUS_D1;
priv->widebus = wide;
sdmmc_modifyreg32(priv, STM32_SDMMC_CLKCR_OFFSET,
STM32_SDMMC_CLKCR_WIDBUS_MASK, widbus);
}
/****************************************************************************
@ -2035,6 +2044,12 @@ static void stm32_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate)
clckr = (STM32_SDMMC_CLKCR_MMCXFR | STM32_SDMMC_CLKCR_CLKEN);
break;
/* Enable in MMC wide (4-bit) operation clocking */
case CLOCK_MMC_TRANSFER_4BIT:
clckr = (STM32_SDMMC_CLKCR_MMCXFR4 | STM32_SDMMC_CLKCR_CLKEN);
break;
/* SD normal operation clocking (wide 4-bit mode) */
case CLOCK_SD_TRANSFER_4BIT:

View file

@ -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:

View file

@ -155,6 +155,9 @@
#define STM32_SDMMC_CLKCR_MMCXFR (STM32_SDMMC_MMCXFR_CLKDIV | \
STM32_SDMMC_CLKCR_EDGE | \
STM32_SDMMC_CLKCR_WIDBUS_D1)
#define STM32_SDMMC_CLKCR_MMCXFR4 (STM32_SDMMC_MMCXFR_CLKDIV | \
STM32_SDMMC_CLKCR_EDGE | \
STM32_SDMMC_CLKCR_WIDBUS_D4)
#define STM32_SDMMC_CLCKR_SDXFR (STM32_SDMMC_SDXFR_CLKDIV | \
STM32_SDMMC_CLKCR_EDGE | \
STM32_SDMMC_CLKCR_WIDBUS_D1)
@ -1786,7 +1789,13 @@ 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 widbus = wide ? STM32_SDMMC_CLKCR_WIDBUS_D4 :
STM32_SDMMC_CLKCR_WIDBUS_D1;
priv->widebus = wide;
sdmmc_modifyreg32(priv, STM32_SDMMC_CLKCR_OFFSET,
STM32_SDMMC_CLKCR_WIDBUS_MASK, widbus);
}
/****************************************************************************
@ -1830,6 +1839,12 @@ static void stm32_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate)
clckr = (STM32_SDMMC_CLKCR_MMCXFR | STM32_SDMMC_CLKCR_CLKEN);
break;
/* Enable in MMC wide (4-bit) operation clocking */
case CLOCK_MMC_TRANSFER_4BIT:
clckr = (STM32_SDMMC_CLKCR_MMCXFR4 | STM32_SDMMC_CLKCR_CLKEN);
break;
/* SD normal operation clocking (wide 4-bit mode) */
case CLOCK_SD_TRANSFER_4BIT:

View file

@ -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