[PATCH 8/9] mmc: exynos_dw_mmc: add support for SD UHS mode

Kaustabh Chakraborty kauschluss at disroot.org
Fri Oct 17 17:24:13 CEST 2025


SD UHS mode is already supported by the Exynos DW-MMC driver in mainline
Linux. Using that as reference, add support in the U-Boot driver.

The maximum frequency was capped to 200000000, increase it to 208000000,
which is the required frequency for UHS_SDR104, which has the highest
frequency of all UHS modes. Moreover, add UHS_CAPS to host capailities.
These changes allow both host and card to recognize support for all UHS
modes.

SDR104, SDR50, and DDR50 have their own CLKSEL timing values, which
requires the CIU div value to be set in bits 18:16. Move the function
exynos_dwmci_clksel() below exynos_dwmmc_get_ciu_div() so that the
latter is accessible from the former, and add cases for said timing
modes.

Signed-off-by: Kaustabh Chakraborty <kauschluss at disroot.org>
---
 drivers/mmc/exynos_dw_mmc.c | 48 ++++++++++++++++++++++++++++-----------------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index 8311036109837d710ec141137684cd4f45ae449f..d436d33f53b36aadab3621a14e37ced71b23d96e 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -18,7 +18,7 @@
 #include <linux/printk.h>
 
 #define	DWMMC_MAX_CH_NUM		4
-#define	DWMMC_MAX_FREQ			200000000
+#define	DWMMC_MAX_FREQ			208000000
 #define	DWMMC_MIN_FREQ			400000
 #define	DWMMC_MMC0_SDR_TIMING_VAL	0x03030001
 #define	DWMMC_MMC2_SDR_TIMING_VAL	0x03020001
@@ -126,22 +126,6 @@ static int exynos_dwmmc_set_sclk(struct dwmci_host *host, unsigned long rate)
 	return 0;
 }
 
-/* Configure CLKSEL register with chosen timing values */
-static int exynos_dwmci_clksel(struct dwmci_host *host)
-{
-	struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
-	u32 timing;
-
-	if (host->mmc->selected_mode == MMC_DDR_52)
-		timing = priv->ddr_timing;
-	else
-		timing = priv->sdr_timing;
-
-	dwmci_writel(host, priv->chip->clksel, timing);
-
-	return 0;
-}
-
 /**
  * exynos_dwmmc_get_ciu_div - Get internal clock divider value
  * @host: MMC controller object
@@ -165,6 +149,33 @@ static u8 exynos_dwmmc_get_ciu_div(struct dwmci_host *host)
 				& DWMCI_DIVRATIO_MASK) + 1;
 }
 
+/* Configure CLKSEL register with chosen timing values */
+static int exynos_dwmci_clksel(struct dwmci_host *host)
+{
+	struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
+	u8 clk_div = exynos_dwmmc_get_ciu_div(host) - 1;
+	u32 timing;
+
+	switch (host->mmc->selected_mode) {
+	case MMC_DDR_52:
+		timing = priv->ddr_timing;
+		break;
+	case UHS_SDR104:
+	case UHS_SDR50:
+		timing = (priv->sdr_timing & 0xfff8ffff) | (clk_div << 16);
+		break;
+	case UHS_DDR50:
+		timing = (priv->ddr_timing & 0xfff8ffff) | (clk_div << 16);
+		break;
+	default:
+		timing = priv->sdr_timing;
+	}
+
+	dwmci_writel(host, priv->chip->clksel, timing);
+
+	return 0;
+}
+
 static unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq)
 {
 	unsigned long sclk;
@@ -393,7 +404,8 @@ static int exynos_dwmmc_probe(struct udevice *dev)
 
 	host->name = dev->name;
 	host->board_init = exynos_dwmci_board_init;
-	host->caps = MMC_MODE_DDR_52MHz | MMC_MODE_HS200 | MMC_MODE_HS400;
+	host->caps = MMC_MODE_DDR_52MHz | MMC_MODE_HS200 | MMC_MODE_HS400 |
+		     UHS_CAPS;
 	host->clksel = exynos_dwmci_clksel;
 	host->get_mmc_clk = exynos_dwmci_get_clk;
 

-- 
2.51.0



More information about the U-Boot mailing list