From f391a1158f3db496ce994b613f76b389ef275552 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Sat, 25 Oct 2025 20:06:53 -0500 Subject: [PATCH 1/7] mmc: exynos_dw_mmc: Extend dm_dwmci_ops without code duplication Instead of extending dm_dwmci_ops by copy-pasting the structure code first, copy the actual structure data with memcpy() and then set the .execute_tuning field. Now if struct dm_dwmci_ops gets modified in future, these changes will be automatically reflected in struct exynos_dwmmc_ops, which prevents possible issues in future. It also avoids code duplication. No functional change, but it can prevent possible isssues in future. Fixes: eda4bd29929c ("mmc: exynos_dw_mmc: add support for MMC HS200 and HS400 modes") Signed-off-by: Sam Protsenko Reviewed-by: Anand Moon Signed-off-by: Peng Fan --- drivers/mmc/exynos_dw_mmc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index b230e9dbbf8..190c6349380 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -367,6 +367,8 @@ static int exynos_dwmmc_execute_tuning(struct udevice *dev, u32 opcode) } #endif +struct dm_mmc_ops exynos_dwmmc_ops; + static int exynos_dwmmc_probe(struct udevice *dev) { struct exynos_mmc_plat *plat = dev_get_plat(dev); @@ -376,6 +378,12 @@ static int exynos_dwmmc_probe(struct udevice *dev) unsigned long freq; int err; + /* Extend generic 'dm_dwmci_ops' with .execute_tuning implementation */ + memcpy(&exynos_dwmmc_ops, &dm_dwmci_ops, sizeof(struct dm_mmc_ops)); +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) + exynos_dwmmc_ops.execute_tuning = exynos_dwmmc_execute_tuning; +#endif + #ifndef CONFIG_CPU_V7A err = clk_get_by_index(dev, 1, &priv->clk); /* ciu */ if (err) @@ -480,14 +488,6 @@ static const struct udevice_id exynos_dwmmc_ids[] = { { } }; -struct dm_mmc_ops exynos_dwmmc_ops = { - .send_cmd = dwmci_send_cmd, - .set_ios = dwmci_set_ios, -#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) - .execute_tuning = exynos_dwmmc_execute_tuning, -#endif -}; - U_BOOT_DRIVER(exynos_dwmmc_drv) = { .name = "exynos_dwmmc", .id = UCLASS_MMC, From 20b19639cdf86f4fb1289443bc47866a8047b619 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Sat, 25 Oct 2025 20:06:54 -0500 Subject: [PATCH 2/7] mmc: dw_mmc: Do not export dwmci_send_cmd() and dwmci_set_ios() Do not over-expose the private dw_mmc API. The glue layer drivers at this point shouldn't be aware and shouldn't use the generic dwmci_send_cmd() and dwmci_set_ios() functions. Making those functions public causes a "leaky abstraction" issue. It clutters the public interface of generic dw_mmc driver and possibly leads to improper usage of those functions, so it's a bad design. If struct dm_dwmci_ops has to be extended, do so by copying it first (like it's done for example in snps_dw_mmc driver). That also makes sure the future changes to struct dm_dwmci_ops in dw_mmc driver will be automatically reflected in all extended copies, and avoid code duplication. This effectively reverts commit ef3b16bb8e73 ("mmc: dw_mmc: export dwmci_send_cmd() and dwmci_set_ios()"). No functional change. Fixes: ef3b16bb8e73 ("mmc: dw_mmc: export dwmci_send_cmd() and dwmci_set_ios()") Signed-off-by: Sam Protsenko Reviewed-by: Anand Moon Signed-off-by: Peng Fan --- drivers/mmc/dw_mmc.c | 6 +++--- include/dwmmc.h | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index f3c0cc5cd8e..d9c05b223d5 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -490,8 +490,8 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd, } #ifdef CONFIG_DM_MMC -int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, - struct mmc_data *data) +static int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) { struct mmc *mmc = mmc_get_mmc_dev(dev); #else @@ -597,7 +597,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) } #ifdef CONFIG_DM_MMC -int dwmci_set_ios(struct udevice *dev) +static int dwmci_set_ios(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); #else diff --git a/include/dwmmc.h b/include/dwmmc.h index 47e3220985e..7e1a6646518 100644 --- a/include/dwmmc.h +++ b/include/dwmmc.h @@ -338,9 +338,6 @@ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk); #ifdef CONFIG_DM_MMC /* Export the operations to drivers */ int dwmci_probe(struct udevice *dev); -int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, - struct mmc_data *data); -int dwmci_set_ios(struct udevice *dev); extern const struct dm_mmc_ops dm_dwmci_ops; #endif From 6f0845fcb2ca687e346b74caae62c5ad418b1879 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Sat, 25 Oct 2025 20:06:55 -0500 Subject: [PATCH 3/7] mmc: exynos_dw_mmc: Improve coding style Exynos DW MMC glue layer driver have seen a lot of changes recently. Stabilize the coding style. No functional change. Signed-off-by: Sam Protsenko Reviewed-by: Anand Moon Signed-off-by: Peng Fan --- drivers/mmc/exynos_dw_mmc.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index 190c6349380..51867a55249 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -26,11 +26,16 @@ #define EXYNOS4412_FIXED_CIU_CLK_DIV 4 /* CLKSEL register defines */ -#define CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) -#define CLKSEL_UP_SAMPLE(x, y) (((x) & ~CLKSEL_CCLK_SAMPLE(7)) |\ +#define CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) +#define CLKSEL_UP_SAMPLE(x, y) (((x) & ~CLKSEL_CCLK_SAMPLE(7)) | \ CLKSEL_CCLK_SAMPLE(y)) -/* Quirks */ +/** + * DOC: Quirk flags for different Exynos DW MMC blocks + * + * %DWMCI_QUIRK_DISABLE_SMU: DW MMC block has Security Management Unit (SMU) + * which has to be configured in non-encryption mode during driver's init. + */ #define DWMCI_QUIRK_DISABLE_SMU BIT(0) #ifdef CONFIG_DM_MMC @@ -183,9 +188,11 @@ static unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq) int err; /* Should be double rate for DDR or HS mode */ - if ((host->mmc->selected_mode == MMC_DDR_52 && host->mmc->bus_width == 8) || - host->mmc->selected_mode == MMC_HS_400) + if ((host->mmc->selected_mode == MMC_DDR_52 && + host->mmc->bus_width == 8) || + host->mmc->selected_mode == MMC_HS_400) { freq *= 2; + } clk_div = exynos_dwmmc_get_ciu_div(host); err = exynos_dwmmc_set_sclk(host, freq * clk_div); @@ -302,7 +309,7 @@ static int exynos_dwmmc_of_to_plat(struct udevice *dev) #if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static int exynos_dwmmc_get_best_clksmpl(u8 candidates) { - u8 i; + int i; for (i = 0; i < 8; i++) { candidates = (candidates >> 1) | (candidates << 7); /* ror */ @@ -317,8 +324,8 @@ static int exynos_dwmmc_get_best_clksmpl(u8 candidates) } /* - * If no valid clock sample values are found, use the first - * canditate bit for clock sample value. + * If no valid clock sample values are found, use the first candidate + * bit for clock sample value. */ for (i = 0; i < 8; i++) { candidates = (candidates >> 1) | (candidates << 7); /* ror */ @@ -344,7 +351,7 @@ static int exynos_dwmmc_execute_tuning(struct udevice *dev, u32 opcode) do { dwmci_writel(host, DWMCI_TMOUT, ~0); - /* move to the next clksmpl */ + /* Move to the next clksmpl */ smpl = (clksel + 1) & 0x7; clksel = CLKSEL_UP_SAMPLE(clksel, smpl); dwmci_writel(host, priv->chip->clksel, clksel); @@ -360,12 +367,11 @@ static int exynos_dwmmc_execute_tuning(struct udevice *dev, u32 opcode) return ret; } - dwmci_writel(host, priv->chip->clksel, - CLKSEL_UP_SAMPLE(clksel, ret)); + dwmci_writel(host, priv->chip->clksel, CLKSEL_UP_SAMPLE(clksel, ret)); return 0; } -#endif +#endif /* CONFIG_MMC_SUPPORTS_TUNING */ struct dm_mmc_ops exynos_dwmmc_ops; @@ -396,7 +402,7 @@ static int exynos_dwmmc_probe(struct udevice *dev) flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; err = exynos_pinmux_config(host->dev_id, flag); if (err) { - printf("DWMMC%d not configure\n", host->dev_index); + printf("DWMMC%d not configured\n", host->dev_index); return err; } #endif @@ -499,4 +505,4 @@ U_BOOT_DRIVER(exynos_dwmmc_drv) = { .priv_auto = sizeof(struct dwmci_exynos_priv_data), .plat_auto = sizeof(struct exynos_mmc_plat), }; -#endif +#endif /* CONFIG_DM_MMC */ From 1e665e543c51d665f3fe1f8dc428f86198812ead Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Sat, 25 Oct 2025 20:06:56 -0500 Subject: [PATCH 4/7] mmc: exynos_dw_mmc: Add quirk for disabling FMP Add DWMCI_QUIRK_DISABLE_FMP which disables Flash Memory Protector (FMP) during driver's init. It's usually done by early bootloaders, but in some cases (like USB boot) the FMP may be left unconfigured. The issue was observed on Exynos850 SoC (the E850-96 board). Enabling this quirk makes eMMC functional even in such cases. No functional change, as this feature is only added here but not enabled for any chips yet. Signed-off-by: Sam Protsenko Reviewed-by: Anand Moon Signed-off-by: Peng Fan --- arch/arm/mach-exynos/include/mach/dwmmc.h | 6 ++++++ drivers/mmc/exynos_dw_mmc.c | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/arch/arm/mach-exynos/include/mach/dwmmc.h b/arch/arm/mach-exynos/include/mach/dwmmc.h index 75d84988b7d..4432deedef7 100644 --- a/arch/arm/mach-exynos/include/mach/dwmmc.h +++ b/arch/arm/mach-exynos/include/mach/dwmmc.h @@ -17,10 +17,16 @@ /* Protector Register */ #define DWMCI_EMMCP_BASE 0x1000 +#define EMMCP_MPSECURITY (DWMCI_EMMCP_BASE + 0x0010) #define EMMCP_MPSBEGIN0 (DWMCI_EMMCP_BASE + 0x0200) #define EMMCP_SEND0 (DWMCI_EMMCP_BASE + 0x0204) #define EMMCP_CTRL0 (DWMCI_EMMCP_BASE + 0x020c) +/* EMMCP_MPSECURITY bits */ +#define MPSECURITY_FMP_ON BIT(29) +#define MPSECURITY_MMC_SFR_PROT_ON BIT(28) + +/* EMMCP_CTRL0 bits */ #define MPSCTRL_SECURE_READ_BIT BIT(7) #define MPSCTRL_SECURE_WRITE_BIT BIT(6) #define MPSCTRL_NON_SECURE_READ_BIT BIT(5) diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index 51867a55249..be17bc4692c 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -35,8 +35,16 @@ * * %DWMCI_QUIRK_DISABLE_SMU: DW MMC block has Security Management Unit (SMU) * which has to be configured in non-encryption mode during driver's init. + * + * %DWMCI_QUIRK_DISABLE_FMP: DW MMC block has Flash Memory Protector (FMP) which + * has to be disabled during driver's init. This flag disables FMP encryption + * and lets external non-secure main CPUs access the SFR (peripheral memory + * region, i.e. registers) in MMC core. Although it's usually done by early + * bootloaders (before U-Boot), in some cases like during USB boot the FMP might + * be left unconfigured. */ #define DWMCI_QUIRK_DISABLE_SMU BIT(0) +#define DWMCI_QUIRK_DISABLE_FMP BIT(1) #ifdef CONFIG_DM_MMC #include @@ -225,6 +233,18 @@ static void exynos_dwmci_board_init(struct dwmci_host *host) MPSCTRL_NON_SECURE_WRITE_BIT | MPSCTRL_VALID); } + if (priv->chip->quirks & DWMCI_QUIRK_DISABLE_FMP) { + u32 reg; + + reg = dwmci_readl(host, EMMCP_MPSECURITY); + if (reg & MPSECURITY_FMP_ON || + reg & MPSECURITY_MMC_SFR_PROT_ON) { + reg &= ~MPSECURITY_FMP_ON; + reg &= ~MPSECURITY_MMC_SFR_PROT_ON; + dwmci_writel(host, EMMCP_MPSECURITY, reg); + } + } + if (priv->sdr_timing) exynos_dwmci_clksel(host); } From cd7b26a254c1685f2519b78f6fa11577cdcfc114 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Sat, 25 Oct 2025 20:06:57 -0500 Subject: [PATCH 5/7] mmc: exynos_dw_mmc: Add exynos850 compatible Up until now "samsung,exynos7-dw-mshc-smu" compatible was used for Exynos850 SoC, as it's present in its device tree. But Exynos850 device tree also supports "samsung,exynos850-dw-mshc-smu" compatible string. Add it in compatible ID list in the driver so that it can be matched against this string for Exynos850 device tree. No functional change, as the driver data is just a copy of "samsung,exynos7-dw-mshc-smu" data for now. Signed-off-by: Sam Protsenko Reviewed-by: Anand Moon Signed-off-by: Peng Fan --- drivers/mmc/exynos_dw_mmc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index be17bc4692c..2027fcb8224 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -488,6 +488,11 @@ static const struct exynos_dwmmc_variant exynos7_smu_drv_data = { .quirks = DWMCI_QUIRK_DISABLE_SMU, }; +static const struct exynos_dwmmc_variant exynos850_drv_data = { + .clksel = DWMCI_CLKSEL64, + .quirks = DWMCI_QUIRK_DISABLE_SMU, +}; + static const struct udevice_id exynos_dwmmc_ids[] = { { .compatible = "samsung,exynos4412-dw-mshc", @@ -510,6 +515,9 @@ static const struct udevice_id exynos_dwmmc_ids[] = { }, { .compatible = "samsung,exynos7870-dw-mshc-smu", .data = (ulong)&exynos7_smu_drv_data, + }, { + .compatible = "samsung,exynos850-dw-mshc-smu", + .data = (ulong)&exynos850_drv_data, }, { } }; From e11db644884242795b01ea10e2949f2f56005b0b Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Sat, 25 Oct 2025 20:06:58 -0500 Subject: [PATCH 6/7] mmc: exynos_dw_mmc: Disable FMP for Exynos850 chip Add DWMCI_QUIRK_DISABLE_FMP flag to Exynos850 driver data to make the driver disable FMP in case of Exynos850 chip. That makes eMMC on Exynos850 functional when U-Boot is executed during USB boot. Signed-off-by: Sam Protsenko Reviewed-by: Anand Moon Signed-off-by: Peng Fan --- drivers/mmc/exynos_dw_mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index 2027fcb8224..7ccd113bd79 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -490,7 +490,7 @@ static const struct exynos_dwmmc_variant exynos7_smu_drv_data = { static const struct exynos_dwmmc_variant exynos850_drv_data = { .clksel = DWMCI_CLKSEL64, - .quirks = DWMCI_QUIRK_DISABLE_SMU, + .quirks = DWMCI_QUIRK_DISABLE_SMU | DWMCI_QUIRK_DISABLE_FMP, }; static const struct udevice_id exynos_dwmmc_ids[] = { From 0408ae531fe8ad01b9b788181fc5b91e0a527b42 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 5 Nov 2025 01:13:51 +0100 Subject: [PATCH 7/7] spl: mmc: avoid including errno.h twice Each include should only be included once. Signed-off-by: Heinrich Schuchardt Reviewed-by: Bin Meng Signed-off-by: Peng Fan --- common/spl/spl_mmc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 0a00d295575..d8ce3a84614 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include