[PATCH 3/8] mmc: sdhci-cadence: Set controller and PHY speed modes for SD and eMMC cards

Tanmay Kathpalia tanmay.kathpalia at altera.com
Mon Nov 10 18:37:32 CET 2025


Replace the legacy clock frequency-based timing mode selection with
proper MMC timing mode constants.

Changes to sdhci-cadence.c:
- Add sdhci_cdns_get_hrs06_mode() helper function for mode selection
- Replace clock frequency logic with mmc->selected_mode switch statement
- Use proper MMC timing constants (MMC_HS, UHS_SDR104, etc.)
- Add SD card specific handling with standard SDHCI control register setup

Changes to sdhci-cadence6.c:
- Add SD high speed PHY and control configuration arrays
- Update sdhci_cdns6_phy_adj() to use timing modes instead of HRS06 modes
- Support both SD and eMMC timing modes with appropriate PHY settings

Signed-off-by: Tanmay Kathpalia <tanmay.kathpalia at altera.com>
Reviewed-by: Balsundar Ponnusamy <balsundar.ponnusamy at altera.com>
---
 drivers/mmc/sdhci-cadence.c  | 72 +++++++++++++++++++++++++++---------
 drivers/mmc/sdhci-cadence6.c | 39 ++++++++++++++++---
 2 files changed, 87 insertions(+), 24 deletions(-)

diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c
index f31437e5eeb..a151ce10ddc 100644
--- a/drivers/mmc/sdhci-cadence.c
+++ b/drivers/mmc/sdhci-cadence.c
@@ -2,6 +2,7 @@
 /*
  * Copyright (C) 2016 Socionext Inc.
  *   Author: Masahiro Yamada <yamada.masahiro at socionext.com>
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
  */
 
 #include <dm.h>
@@ -84,39 +85,74 @@ static int sdhci_cdns_phy_init(struct sdhci_cdns_plat *plat,
 	return 0;
 }
 
+static unsigned int sdhci_cdns_get_hrs06_mode(struct mmc *mmc)
+{
+	unsigned int mode;
+
+	if (IS_SD(mmc)) {
+		mode = SDHCI_CDNS_HRS06_MODE_SD;
+	} else {
+		switch (mmc->selected_mode) {
+		case MMC_LEGACY:
+			mode = SDHCI_CDNS_HRS06_MODE_SD; /* use this for Legacy */
+			break;
+
+		case MMC_HS:
+		case MMC_HS_52:
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
+			break;
+
+		case UHS_DDR50:
+		case MMC_DDR_52:
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
+			break;
+
+		case UHS_SDR104:
+		case MMC_HS_200:
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
+			break;
+
+		case MMC_HS_400:
+		case MMC_HS_400_ES:
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
+			break;
+
+		default:
+			mode = SDHCI_CDNS_HRS06_MODE_SD;
+			break;
+		}
+	}
+	return mode;
+}
+
 static void sdhci_cdns_set_control_reg(struct sdhci_host *host)
 {
 	struct mmc *mmc = host->mmc;
 	struct sdhci_cdns_plat *plat = dev_get_plat(mmc->dev);
-	unsigned int clock = mmc->clock;
 	u32 mode, tmp;
 
 	/*
-	 * REVISIT:
-	 * The mode should be decided by MMC_TIMING_* like Linux, but
-	 * U-Boot does not support timing.  Use the clock frequency instead.
+	 * Select HRS06 mode based on card type and selected timing mode.
+	 * For SD cards, always use SD mode (000b) as per Cadence user guide,
+	 * section 12.7 (HRS06), Part Number: IP6061.
+	 * For eMMC, use selected_mode to pick the appropriate mode.
 	 */
-	if (clock <= 26000000) {
-		mode = SDHCI_CDNS_HRS06_MODE_SD; /* use this for Legacy */
-	} else if (clock <= 52000000) {
-		if (mmc->ddr_mode)
-			mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
-		else
-			mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
-	} else {
-		if (mmc->ddr_mode)
-			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
-		else
-			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
-	}
+	mode = sdhci_cdns_get_hrs06_mode(mmc);
 
 	tmp = readl(plat->hrs_addr + SDHCI_CDNS_HRS06);
 	tmp &= ~SDHCI_CDNS_HRS06_MODE;
 	tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode);
 	writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS06);
 
+	/*
+	 * For SD cards, program standard SDHCI Host Control2 UHS/voltage
+	 * registers for UHS-I support.
+	 */
+	if (IS_SD(mmc))
+		sdhci_set_control_reg(host);
+
 	if (device_is_compatible(mmc->dev, "cdns,sd6hc"))
-		sdhci_cdns6_phy_adj(mmc->dev, plat, mode);
+		sdhci_cdns6_phy_adj(mmc->dev, plat, mmc->selected_mode);
 }
 
 static const struct sdhci_ops sdhci_cdns_ops = {
diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c
index ead96dc0c91..d4e2cb1c83e 100644
--- a/drivers/mmc/sdhci-cadence6.c
+++ b/drivers/mmc/sdhci-cadence6.c
@@ -2,6 +2,7 @@
 /*
  * Copyright (C) 2023 Starfive.
  *   Author: Kuan Lim Lee <kuanlim.lee at starfivetech.com>
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
  */
 
 #include <dm.h>
@@ -77,6 +78,13 @@ static struct sdhci_cdns6_phy_cfg sd_ds_phy_cfgs[] = {
 	{ "cdns,phy-dq-timing-delay-sd-ds", 0x00000001, },
 };
 
+static struct sdhci_cdns6_phy_cfg sd_hs_phy_cfgs[] = {
+	{ "cdns,phy-dqs-timing-delay-sd-hs", 0x00380004, },
+	{ "cdns,phy-gate-lpbk_ctrl-delay-sd-hs", 0x01A00040, },
+	{ "cdns,phy-dll-slave-ctrl-sd-hs", 0x00000000, },
+	{ "cdns,phy-dq-timing-delay-sd-hs", 0x00000001, },
+};
+
 static struct sdhci_cdns6_phy_cfg emmc_sdr_phy_cfgs[] = {
 	{ "cdns,phy-dqs-timing-delay-semmc-sdr", 0x00380004, },
 	{ "cdns,phy-gate-lpbk_ctrl-delay-emmc-sdr", 0x01A00040, },
@@ -112,6 +120,13 @@ static struct sdhci_cdns6_ctrl_cfg sd_ds_ctrl_cfgs[] = {
 	{ "cdns,ctrl-hrs07-timing-delay-sd-ds", 0x00080000, },
 };
 
+static struct sdhci_cdns6_ctrl_cfg sd_hs_ctrl_cfgs[] = {
+	{ "cdns,ctrl-hrs09-timing-delay-sd-hs", 0x0001800C, },
+	{ "cdns,ctrl-hrs10-lpbk_ctrl-delay-sd-hs", 0x00030000, },
+	{ "cdns,ctrl-hrs16-slave-ctrl-sd-hs", 0x00000000, },
+	{ "cdns,ctrl-hrs07-timing-delay-sd-hs", 0x00080000, },
+};
+
 static struct sdhci_cdns6_ctrl_cfg emmc_sdr_ctrl_cfgs[] = {
 	{ "cdns,ctrl-hrs09-timing-delay-emmc-sdr", 0x0001800C, },
 	{ "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-sdr", 0x00030000, },
@@ -186,27 +201,39 @@ int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 m
 	int i, ret;
 
 	switch (mode) {
-	case SDHCI_CDNS_HRS06_MODE_SD:
+	case UHS_SDR12:
+	case MMC_LEGACY:
 		sdhci_cdns6_phy_cfgs = sd_ds_phy_cfgs;
 		sdhci_cdns6_ctrl_cfgs = sd_ds_ctrl_cfgs;
 		break;
 
-	case SDHCI_CDNS_HRS06_MODE_MMC_SDR:
+	case SD_HS:
+	case UHS_SDR25:
+	case MMC_HS:
+		sdhci_cdns6_phy_cfgs = sd_hs_phy_cfgs;
+		sdhci_cdns6_ctrl_cfgs = sd_hs_ctrl_cfgs;
+		break;
+
+	case UHS_SDR50:
+	case MMC_HS_52:
 		sdhci_cdns6_phy_cfgs = emmc_sdr_phy_cfgs;
 		sdhci_cdns6_ctrl_cfgs = emmc_sdr_ctrl_cfgs;
 		break;
 
-	case SDHCI_CDNS_HRS06_MODE_MMC_DDR:
+	case UHS_DDR50:
+	case MMC_DDR_52:
 		sdhci_cdns6_phy_cfgs = emmc_ddr_phy_cfgs;
 		sdhci_cdns6_ctrl_cfgs = emmc_ddr_ctrl_cfgs;
 		break;
 
-	case SDHCI_CDNS_HRS06_MODE_MMC_HS200:
+	case UHS_SDR104:
+	case MMC_HS_200:
 		sdhci_cdns6_phy_cfgs = emmc_hs200_phy_cfgs;
 		sdhci_cdns6_ctrl_cfgs = emmc_hs200_ctrl_cfgs;
 		break;
 
-	case SDHCI_CDNS_HRS06_MODE_MMC_HS400:
+	case MMC_HS_400:
+	case MMC_HS_400_ES:
 		sdhci_cdns6_phy_cfgs = emmc_hs400_phy_cfgs;
 		sdhci_cdns6_ctrl_cfgs = emmc_hs400_ctrl_cfgs;
 		break;
@@ -263,7 +290,7 @@ int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 m
 
 int sdhci_cdns6_phy_init(struct udevice *dev, struct sdhci_cdns_plat *plat)
 {
-	return sdhci_cdns6_phy_adj(dev, plat, SDHCI_CDNS_HRS06_MODE_SD);
+	return sdhci_cdns6_phy_adj(dev, plat, MMC_LEGACY);
 }
 
 int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val)
-- 
2.43.7



More information about the U-Boot mailing list