Skip to contentSkip to conversation

mmc: add HS400 support

PATCH Superseded Peng Fan 5 participants 10 messages Mar 5, 2018 – Apr 26, 2018 MMC, SD and SDIO

v1 of 4 Superseded Latest is v4 →

lore
Share & tools
lore

Peng Fan

author
#0 lore raw

PATCH 1/2 mmc: add HS400 support

Add HS400 support.
Selecting HS400 needs first select HS199 according to spec, so use a dedicated function for HS400.
Add HS400 related macros.
Remove the restriction of only using the low 6 bits of EXT_CSD_CARD_TYPE, using all the 8 bits.

Cc Jaehoon Chung <[email protected]>
Cc Jean-Jacques Hiblot <[email protected]>
Cc Stefano Babic <[email protected]>
Cc Simon Glass <[email protected]>
Cc Kishon Vijay Abraham I <[email protected]>
Cc Bin Meng <[email protected]>
---
 drivers/mmc/Kconfig |   7 +++
 drivers/mmc/mmc.c   | 133 ++++++++++++++++++++++++++++++++++++++++++----------
 include/mmc.h       |  12 +++++
 3 files changed, 127 insertions(+), 25 deletions(-)
drivers/mmc/Kconfig +7 -0
index 5f67e336db..e9be18b333 100644
@@ -104,6 +104,13 @@ config SPL_MMC_UHS_SUPPORT
 	  cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
 	  frequency can go up to 208MHz (SDR104)
 
+config MMC_HS400_SUPPORT
+	bool "enable HS400 support"
+	select MMC_HS200_SUPPORT
+	help
+	  The HS400 mode is support by some eMMC. The bus frequency is up to
+	  200MHz. This mode requires tuning the IO.
+
 config MMC_HS200_SUPPORT
 	bool "enable HS200 support"
 	help
drivers/mmc/mmc.c +108 -25

194 lines not on this page · raw message

include/mmc.h +12 -0
index 86f885b504..8c01c6a530 100644
@@ -65,6 +65,7 @@
 #define MMC_MODE_HS_52MHz	MMC_CAP(MMC_HS_52)
 #define MMC_MODE_DDR_52MHz	MMC_CAP(MMC_DDR_52)
 #define MMC_MODE_HS200		MMC_CAP(MMC_HS_200)
+#define MMC_MODE_HS400		MMC_CAP(MMC_HS_400)
 
 #define MMC_MODE_8BIT		BIT(30)
 #define MMC_MODE_4BIT		BIT(29)
@@ -250,6 +251,11 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
 #define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
 					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	BIT(6)
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	BIT(7)
+#define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
@@ -260,6 +266,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
 #define EXT_CSD_TIMING_LEGACY	0	/* no high speed */
 #define EXT_CSD_TIMING_HS	1	/* HS */
 #define EXT_CSD_TIMING_HS200	2	/* HS200 */
+#define EXT_CSD_TIMING_HS400	3	/* HS400 */
 
 #define EXT_CSD_BOOT_ACK_ENABLE			(1 << 6)
 #define EXT_CSD_BOOT_PARTITION_ENABLE		(1 << 3)
@@ -520,6 +527,7 @@ enum bus_mode {
 	UHS_DDR50,
 	UHS_SDR104,
 	MMC_HS_200,
+	MMC_HS_400,
 	MMC_MODES_END
 };
 
@@ -533,6 +541,10 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode)
 #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
 	else if (mode == UHS_DDR50)
 		return true;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	else if (mode == MMC_HS_400)
+		return true;
 #endif
 	else
 		return false;
Signature · 1 line
2.14.1
author
#1 lore raw

PATCH 2/2 mmc: fsl_esdhc: enable HS400 feature

The strobe dll code is ported from Linux Kernel:
drivers/mmc/host/sdhci-esdhc-imx.c
The comments are from the above file,
"For HS400 eMMC, there is a data_strobe line. This signal is generated by the device and used for data output and CRC status response output in HS400 mode. The frequency of this signal follows the frequency of CLK generated by host. The host receives the data which is aligned to the edge of data_strobe line. Due to the time delay between CLK line and data_strobe line, if the delay time is larger than one clock cycle, then CLK and data_strobe line will be misaligned, read error shows up. So when the CLK is higher than 100MHz, each clock cycle is short enough, host should configure the delay target. "

Cc Jaehoon Chung <[email protected]>
Cc Stefano Babic <[email protected]>
---
 drivers/mmc/fsl_esdhc.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)
drivers/mmc/fsl_esdhc.c +34 -1
index 6018f84307..e42bdb6941 100644
@@ -663,6 +663,7 @@ static int esdhc_change_pinstate(struct udevice *dev)
 		break;
 	case UHS_SDR104:
 	case MMC_HS_200:
+	case MMC_HS_400:
 		ret = pinctrl_select_state(dev, "state_200mhz");
 		break;
 	default:
@@ -690,6 +691,33 @@ static void esdhc_reset_tuning(struct mmc *mmc)
 	}
 }
 
+static void esdhc_set_strobe_dll(struct mmc *mmc)
+{
+	struct fsl_esdhc_priv *priv = dev_get_priv(mmc->dev);
+	struct fsl_esdhc *regs = priv->esdhc_regs;
+	u32 v;
+
+	if (priv->clock > ESDHC_STROBE_DLL_CLK_FREQ) {
+		writel(ESDHC_STROBE_DLL_CTRL_RESET, &regs->strobe_dllctrl);
+
+		/*
+		 * enable strobe dll ctrl and adjust the delay target
+		 * for the uSDHC loopback read clock
+		 */
+		v = ESDHC_STROBE_DLL_CTRL_ENABLE |
+			(priv->strobe_dll_delay_target <<
+			 ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
+		writel(v, &regs->strobe_dllctrl);
+		/* wait 1us to make sure strobe dll status register stable */
+		mdelay(1);
+		v = readl(&regs->strobe_dllstat);
+		if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK))
+			pr_warn("HS400 strobe DLL status REF not lock!\n");
+		if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK))
+			pr_warn("HS400 strobe DLL status SLV not lock!\n");
+	}
+}
+
 static int esdhc_set_timing(struct mmc *mmc)
 {
 	struct fsl_esdhc_priv *priv = dev_get_priv(mmc->dev);
@@ -704,6 +732,11 @@ static int esdhc_set_timing(struct mmc *mmc)
 	case SD_LEGACY:
 		esdhc_reset_tuning(mmc);
 		break;
+	case MMC_HS_400:
+		mixctrl |= MIX_CTRL_DDREN | MIX_CTRL_HS400_EN;
+		writel(mixctrl, &regs->mixctrl);
+		esdhc_set_strobe_dll(mmc);
+		break;
 	case MMC_HS:
 	case MMC_HS_52:
 	case MMC_HS_200:
@@ -1439,7 +1472,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
 #endif
 
 	if (fdt_get_property(fdt, node, "no-1-8-v", NULL))
-		priv->caps &= ~(UHS_CAPS | MMC_MODE_HS200);
+		priv->caps &= ~(UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_HS400);
 
 	/*
 	 * TODO:
Signature · 1 line
2.14.1
#2 lore raw

PATCH 2/2 mmc: fsl_esdhc: enable HS400 feature

Hi,

Quoted 4 lines · Peng Fan

The strobe dll code is ported from Linux Kernel:
drivers/mmc/host/sdhci-esdhc-imx.c
The comments are from the above file,
"For HS400 eMMC, there is a data_strobe line. This signal is generated

Quoted 8 lines

by the device and used for data output and CRC status response output in HS400 mode. The frequency of this signal follows the frequency of CLK generated by host. The host receives the data which is aligned to the edge of data_strobe line. Due to the time delay between CLK line and data_strobe line, if the delay time is larger than one clock cycle, then CLK and data_strobe line will be misaligned, read error shows up. So when the CLK is higher than 100MHz, each clock cycle is short enough, host should configure the delay target. "

Sorry for late.

Quoted 21 lines
Cc Jaehoon Chung <[email protected]>
Cc Stefano Babic <[email protected]>
---
 drivers/mmc/fsl_esdhc.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)
drivers/mmc/fsl_esdhc.c +1 -0
index 6018f84307..e42bdb6941 100644
@@ -663,6 +663,7 @@ static int esdhc_change_pinstate(struct udevice *dev)
 		break;
 	case UHS_SDR104:
 	case MMC_HS_200:
+	case MMC_HS_400:
 		ret = pinctrl_select_state(dev, "state_200mhz");
 		break;
 	default:

drivers/mmc/fsl_esdhc.c static void esdhc_reset_tuning(struct mmc *mmc) · line 698

Quoted 8 lines
drivers/mmc/fsl_esdhc.c +5 -0
@@ -690,6 +691,33 @@ static void esdhc_reset_tuning(struct mmc *mmc)
 	}
 }
 
+static void esdhc_set_strobe_dll(struct mmc *mmc)
+{
+	struct fsl_esdhc_priv *priv = dev_get_priv(mmc->dev);
+	struct fsl_esdhc *regs = priv->esdhc_regs;
+	u32 v;

v? I want to use the meaningful variable name. :)

Quoted 47 lines
drivers/mmc/fsl_esdhc.c +28 -1
+
+	if (priv->clock > ESDHC_STROBE_DLL_CLK_FREQ) {
+		writel(ESDHC_STROBE_DLL_CTRL_RESET, &regs->strobe_dllctrl);
+
+		/*
+		 * enable strobe dll ctrl and adjust the delay target
+		 * for the uSDHC loopback read clock
+		 */
+		v = ESDHC_STROBE_DLL_CTRL_ENABLE |
+			(priv->strobe_dll_delay_target <<
+			 ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
+		writel(v, &regs->strobe_dllctrl);
+		/* wait 1us to make sure strobe dll status register stable */
+		mdelay(1);
+		v = readl(&regs->strobe_dllstat);
+		if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK))
+			pr_warn("HS400 strobe DLL status REF not lock!\n");
+		if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK))
+			pr_warn("HS400 strobe DLL status SLV not lock!\n");
+	}
+}
+
 static int esdhc_set_timing(struct mmc *mmc)
 {
 	struct fsl_esdhc_priv *priv = dev_get_priv(mmc->dev);
@@ -704,6 +732,11 @@ static int esdhc_set_timing(struct mmc *mmc)
 	case SD_LEGACY:
 		esdhc_reset_tuning(mmc);
 		break;
+	case MMC_HS_400:
+		mixctrl |= MIX_CTRL_DDREN | MIX_CTRL_HS400_EN;
+		writel(mixctrl, &regs->mixctrl);
+		esdhc_set_strobe_dll(mmc);
+		break;
 	case MMC_HS:
 	case MMC_HS_52:
 	case MMC_HS_200:
@@ -1439,7 +1472,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
 #endif
 
 	if (fdt_get_property(fdt, node, "no-1-8-v", NULL))
-		priv->caps &= ~(UHS_CAPS | MMC_MODE_HS200);
+		priv->caps &= ~(UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_HS400);
 
 	/*
 	 * TODO:
#3 lore raw

PATCH 1/2 mmc: add HS400 support

In reply to Peng Fan

Hi Peng,

I'm glad you are adding HS400 support. Thanks.

Quoted 25 lines · Peng Fan

Add HS400 support.
Selecting HS400 needs first select HS199 according to spec, so use a dedicated function for HS400.
Add HS400 related macros.
Remove the restriction of only using the low 6 bits of EXT_CSD_CARD_TYPE, using all the 8 bits.

Cc Jaehoon Chung <[email protected]>
Cc Jean-Jacques Hiblot <[email protected]>
Cc Stefano Babic <[email protected]>
Cc Simon Glass <[email protected]>
Cc Kishon Vijay Abraham I <[email protected]>
Cc Bin Meng <[email protected]>
---
  drivers/mmc/Kconfig |   7 +++
  drivers/mmc/mmc.c   | 133 ++++++++++++++++++++++++++++++++++++++++++----------
  include/mmc.h       |  12 +++++
  3 files changed, 127 insertions(+), 25 deletions(-)
drivers/mmc/Kconfig +0 -0
index 5f67e336db..e9be18b333 100644

drivers/mmc/Kconfig config SPL_MMC_UHS_SUPPORT · line 109

Quoted 6 lines
drivers/mmc/Kconfig +3 -0
@@ -104,6 +104,13 @@ config SPL_MMC_UHS_SUPPORT
  	  cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
  	  frequency can go up to 208MHz (SDR104)
 
+config MMC_HS400_SUPPORT
+	bool "enable HS400 support"
+	select MMC_HS200_SUPPORT

I'd use "depends on" instead of select or maybe use the same option for both HS200 and HS400

Quoted 109 lines
drivers/mmc/Kconfig +4 -0
+	help
+	  The HS400 mode is support by some eMMC. The bus frequency is up to
+	  200MHz. This mode requires tuning the IO.
+
  config MMC_HS200_SUPPORT
  	bool "enable HS200 support"
  	help
drivers/mmc/mmc.c +44 -1
index 92ea78b8af..eef229c8b4 100644
@@ -169,6 +169,7 @@ const char *mmc_mode_name(enum bus_mode mode)
  	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
  	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
  	      [MMC_HS_200]	= "HS200 (200MHz)",
+	      [MMC_HS_400]	= "HS400 (200MHz)",
  	};
 
  	if (mode >= MMC_MODES_END)
@@ -193,6 +194,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
  	      [UHS_DDR50]	= 50000000,
  	      [UHS_SDR104]	= 208000000,
  	      [MMC_HS_200]	= 200000000,
+	      [MMC_HS_400]	= 200000000,
  	};
 
  	if (mode == MMC_LEGACY)
@@ -790,6 +792,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
  	case MMC_HS_200:
  		speed_bits = EXT_CSD_TIMING_HS200;
  		break;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	case MMC_HS_400:
+		speed_bits = EXT_CSD_TIMING_HS400;
+		break;
  #endif
  	case MMC_LEGACY:
  		speed_bits = EXT_CSD_TIMING_LEGACY;
@@ -837,7 +844,7 @@ static int mmc_get_capabilities(struct mmc *mmc)
 
  	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
 
-	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
+	cardtype = ext_csd[EXT_CSD_CARD_TYPE];
  	mmc->cardtype = cardtype;
 
  #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
@@ -845,6 +852,12 @@ static int mmc_get_capabilities(struct mmc *mmc)
  			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
  		mmc->card_caps |= MMC_MODE_HS200;
  	}
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V |
+			EXT_CSD_CARD_TYPE_HS400_1_8V)) {
+		mmc->card_caps |= MMC_MODE_HS400;
+	}
  #endif
  	if (cardtype & EXT_CSD_CARD_TYPE_52) {
  		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
@@ -1748,6 +1761,12 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
  	u32 card_mask = 0;
 
  	switch (mode) {
+	case MMC_HS_400:
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_8V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_180;
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_2V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_120;
+		break;
  	case MMC_HS_200:
  		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
  			card_mask |= MMC_SIGNAL_VOLTAGE_180;
@@ -1787,6 +1806,13 @@ static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
  #endif
 
  static const struct mode_width_tuning mmc_modes_by_pref[] = {
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	{
+		.mode = MMC_HS_400,
+		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
+		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
+	},
+#endif
  #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
  	{
  		.mode = MMC_HS_200,
@@ -1830,6 +1856,54 @@ static const struct ext_csd_bus_width {
  	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
  };
 
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+static int mmc_select_hs400(struct mmc *mmc)
+{
+	int err;
+
+	/* Set timing to HS200 for tuning */
+	err = mmc_set_card_speed(mmc, MMC_HS_200);
+	if (err)
+		return err;
+
+	/* configure the bus mode (host) */
+	mmc_select_mode(mmc, MMC_HS_200);
+	mmc_set_clock(mmc, mmc->tran_speed, false);
+
+	/* execute tuning if needed */
+	err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200);
+	if (err) {

drivers/mmc/mmc.c static const struct ext_csd_bus_width { · line 1885

Quoted 10 lines
drivers/mmc/mmc.c +10 -0
+		debug("tuning failed\n");
+		return err;
+	}
+
+	/* Set back to HS */
+	mmc_set_card_speed(mmc, MMC_HS);
+	mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
+
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG);

What happens if only 4 wires are used. It is a legit mode, isn't it ?

Quoted 38 lines
drivers/mmc/mmc.c +21 -10
+	if (err)
+		return err;
+
+	err = mmc_set_card_speed(mmc, MMC_HS_400);
+	if (err)
+		return err;
+
+	mmc_select_mode(mmc, MMC_HS_400);
+	err = mmc_set_clock(mmc, mmc->tran_speed, false);
+	if (err)
+		return err;
+
+	return 0;
+}
+#else
+static int mmc_select_hs400(struct mmc *mmc)
+{
+	return -ENOTSUPP;
+}
+#endif
+
  #define for_each_supported_width(caps, ddr, ecbv) \
  	for (ecbv = ext_csd_bus_width;\
  	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
@@ -1883,37 +1957,46 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
  				goto error;
  			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
 
-			/* configure the bus speed (card) */
-			err = mmc_set_card_speed(mmc, mwt->mode);
-			if (err)
-				goto error;
-
-			/*
-			 * configure the bus width AND the ddr mode (card)
-			 * The host side will be taken care of in the next step
-			 */
-			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {

drivers/mmc/mmc.c static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) · line 1966

Quoted 10 lines
drivers/mmc/mmc.c +7 -3
-				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
-						 EXT_CSD_BUS_WIDTH,
-						 ecbw->ext_csd_bits);
+			if (mwt->mode == MMC_HS_400) {
+				err = mmc_select_hs400(mmc);
+				if (err)
+					goto error;
+			} else {
+				/* configure the bus speed (card) */
+				err = mmc_set_card_speed(mmc, mwt->mode);

Instead of having  a separate mmc_select_hs400() is not possible to leverage the existing code ?

JJ

Quoted 98 lines
drivers/mmc/mmc.c +26 -11
  				if (err)
  					goto error;
-			}
 
-			/* configure the bus mode (host) */
-			mmc_select_mode(mmc, mwt->mode);
-			mmc_set_clock(mmc, mmc->tran_speed, false);
+				/*
+				 * configure the bus width AND the ddr mode
+				 * (card). The host side will be taken care
+				 * of in the next step
+				 */
+				if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
+					err = mmc_switch(mmc,
+							 EXT_CSD_CMD_SET_NORMAL,
+							 EXT_CSD_BUS_WIDTH,
+							 ecbw->ext_csd_bits);
+					if (err)
+						goto error;
+				}
+
+				/* configure the bus mode (host) */
+				mmc_select_mode(mmc, mwt->mode);
+				mmc_set_clock(mmc, mmc->tran_speed, false);
  #ifdef MMC_SUPPORTS_TUNING
 
-			/* execute tuning if needed */
-			if (mwt->tuning) {
-				err = mmc_execute_tuning(mmc, mwt->tuning);
-				if (err) {
-					pr_debug("tuning failed\n");
-					goto error;
+				/* execute tuning if needed */
+				if (mwt->tuning) {
+					err = mmc_execute_tuning(mmc,
+								 mwt->tuning);
+					if (err) {
+						pr_debug("tuning failed\n");
+						goto error;
+					}
  				}
-			}
  #endif
+			}
 
  			/* do a transfer to check the configuration */
  			err = mmc_read_and_compare_ext_csd(mmc);
include/mmc.h +12 -0
index 86f885b504..8c01c6a530 100644
@@ -65,6 +65,7 @@
  #define MMC_MODE_HS_52MHz	MMC_CAP(MMC_HS_52)
  #define MMC_MODE_DDR_52MHz	MMC_CAP(MMC_DDR_52)
  #define MMC_MODE_HS200		MMC_CAP(MMC_HS_200)
+#define MMC_MODE_HS400		MMC_CAP(MMC_HS_400)
 
  #define MMC_MODE_8BIT		BIT(30)
  #define MMC_MODE_4BIT		BIT(29)
@@ -250,6 +251,11 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
  #define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
  					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	BIT(6)
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	BIT(7)
+#define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+
  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
@@ -260,6 +266,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
  #define EXT_CSD_TIMING_LEGACY	0	/* no high speed */
  #define EXT_CSD_TIMING_HS	1	/* HS */
  #define EXT_CSD_TIMING_HS200	2	/* HS200 */
+#define EXT_CSD_TIMING_HS400	3	/* HS400 */
 
  #define EXT_CSD_BOOT_ACK_ENABLE			(1 << 6)
  #define EXT_CSD_BOOT_PARTITION_ENABLE		(1 << 3)
@@ -520,6 +527,7 @@ enum bus_mode {
  	UHS_DDR50,
  	UHS_SDR104,
  	MMC_HS_200,
+	MMC_HS_400,
  	MMC_MODES_END
  };
 
@@ -533,6 +541,10 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode)
  #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
  	else if (mode == UHS_DDR50)
  		return true;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	else if (mode == MMC_HS_400)
+		return true;
  #endif
  	else
  		return false;
#4 lore raw

PATCH 1/2 mmc: add HS400 support

Hi,

Quoted 142 lines · Jean-Jacques Hiblot

Hi Peng,

I'm glad you are adding HS400 support. Thanks.

Quoted 25 lines · Peng Fan

Add HS400 support.
Selecting HS400 needs first select HS199 according to spec, so use a dedicated function for HS400.
Add HS400 related macros.
Remove the restriction of only using the low 6 bits of EXT_CSD_CARD_TYPE, using all the 8 bits.

Cc Jaehoon Chung <[email protected]>
Cc Jean-Jacques Hiblot <[email protected]>
Cc Stefano Babic <[email protected]>
Cc Simon Glass <[email protected]>
Cc Kishon Vijay Abraham I <[email protected]>
Cc Bin Meng <[email protected]>
---
 drivers/mmc/Kconfig |   7 +++
 drivers/mmc/mmc.c   | 133 ++++++++++++++++++++++++++++++++++++++++++----------
 include/mmc.h       |  12 +++++
 3 files changed, 127 insertions(+), 25 deletions(-)
drivers/mmc/Kconfig +0 -0
index 5f67e336db..e9be18b333 100644

drivers/mmc/Kconfig config SPL_MMC_UHS_SUPPORT · line 108

Quoted 5 lines
drivers/mmc/Kconfig +3 -0
@@ -104,6 +104,13 @@ config SPL_MMC_UHS_SUPPORT
 	  cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
 	  frequency can go up to 208MHz (SDR104)
+config MMC_HS400_SUPPORT
+	bool "enable HS400 support"
+	select MMC_HS200_SUPPORT

I'd use "depends on" instead of select or maybe use the same option for both HS200 and HS400

Quoted 104 lines
drivers/mmc/Kconfig +4 -0
+	help
+	  The HS400 mode is support by some eMMC. The bus frequency is up to
+	  200MHz. This mode requires tuning the IO.
+
 config MMC_HS200_SUPPORT
 	bool "enable HS200 support"
 	help
drivers/mmc/mmc.c +47 -1
index 92ea78b8af..eef229c8b4 100644
@@ -169,6 +169,7 @@ const char *mmc_mode_name(enum bus_mode mode)
 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
 	      [MMC_HS_200]	= "HS200 (200MHz)",
+	      [MMC_HS_400]	= "HS400 (200MHz)",
 	};
 	if (mode >= MMC_MODES_END)
@@ -193,6 +194,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
 	      [UHS_DDR50]	= 50000000,
 	      [UHS_SDR104]	= 208000000,
 	      [MMC_HS_200]	= 200000000,
+	      [MMC_HS_400]	= 200000000,
 	};
 	if (mode == MMC_LEGACY)
@@ -790,6 +792,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
 	case MMC_HS_200:
 		speed_bits = EXT_CSD_TIMING_HS200;
 		break;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	case MMC_HS_400:
+		speed_bits = EXT_CSD_TIMING_HS400;
+		break;
 #endif
 	case MMC_LEGACY:
 		speed_bits = EXT_CSD_TIMING_LEGACY;
@@ -837,7 +844,7 @@ static int mmc_get_capabilities(struct mmc *mmc)
 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
-	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
+	cardtype = ext_csd[EXT_CSD_CARD_TYPE];
 	mmc->cardtype = cardtype;
 #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
@@ -845,6 +852,12 @@ static int mmc_get_capabilities(struct mmc *mmc)
 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
 		mmc->card_caps |= MMC_MODE_HS200;
 	}
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V |
+			EXT_CSD_CARD_TYPE_HS400_1_8V)) {
+		mmc->card_caps |= MMC_MODE_HS400;
+	}
 #endif
 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
@@ -1748,6 +1761,12 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
 	u32 card_mask = 0;
 	switch (mode) {
+	case MMC_HS_400:
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_8V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_180;
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_2V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_120;
+		break;
 	case MMC_HS_200:
 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
 			card_mask |= MMC_SIGNAL_VOLTAGE_180;
@@ -1787,6 +1806,13 @@ static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
 #endif
 static const struct mode_width_tuning mmc_modes_by_pref[] = {
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	{
+		.mode = MMC_HS_400,
+		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
+		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
+	},
+#endif
 #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
 	{
 		.mode = MMC_HS_200,
@@ -1830,6 +1856,54 @@ static const struct ext_csd_bus_width {
 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
 };
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+static int mmc_select_hs400(struct mmc *mmc)
+{
+	int err;
+
+	/* Set timing to HS200 for tuning */
+	err = mmc_set_card_speed(mmc, MMC_HS_200);
+	if (err)
+		return err;
+
+	/* configure the bus mode (host) */
+	mmc_select_mode(mmc, MMC_HS_200);
+	mmc_set_clock(mmc, mmc->tran_speed, false);
+
+	/* execute tuning if needed */
+	err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200);
+	if (err) {
+		debug("tuning failed\n");
+		return err;
+	}
Quoted 8 lines

drivers/mmc/mmc.c static const struct ext_csd_bus_width { · line 1885

Quoted 7 lines
drivers/mmc/mmc.c +7 -0
+
+	/* Set back to HS */
+	mmc_set_card_speed(mmc, MMC_HS);
+	mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
+
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG);

What happens if only 4 wires are used. It is a legit mode, isn't it ?

According to spec, HS400 only supports 8bits mode, see "5.3.6 HS400 Bus Speed Mode".

Quoted 41 lines
Quoted 41 lines
drivers/mmc/mmc.c +22 -13
+	if (err)
+		return err;
+
+	err = mmc_set_card_speed(mmc, MMC_HS_400);
+	if (err)
+		return err;
+
+	mmc_select_mode(mmc, MMC_HS_400);
+	err = mmc_set_clock(mmc, mmc->tran_speed, false);
+	if (err)
+		return err;
+
+	return 0;
+}
+#else
+static int mmc_select_hs400(struct mmc *mmc)
+{
+	return -ENOTSUPP;
+}
+#endif
+
 #define for_each_supported_width(caps, ddr, ecbv) \
 	for (ecbv = ext_csd_bus_width;\
 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
@@ -1883,37 +1957,46 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
 				goto error;
 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
-			/* configure the bus speed (card) */
-			err = mmc_set_card_speed(mmc, mwt->mode);
-			if (err)
-				goto error;
-
-			/*
-			 * configure the bus width AND the ddr mode (card)
-			 * The host side will be taken care of in the next step
-			 */
-			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
-				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
-						 EXT_CSD_BUS_WIDTH,
-						 ecbw->ext_csd_bits);
+			if (mwt->mode == MMC_HS_400) {
Quoted 8 lines

drivers/mmc/mmc.c static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) · line 1966

Quoted 6 lines
drivers/mmc/mmc.c +6 -0
+				err = mmc_select_hs400(mmc);
+				if (err)
+					goto error;
+			} else {
+				/* configure the bus speed (card) */
+				err = mmc_set_card_speed(mmc, mwt->mode);

Instead of having?? a separate mmc_select_hs400() is not possible to leverage the existing code ?

hs400 requires first runs into HS200 mode, after tuning finished, need switch back to HS mode to configure bus. It's not that straightforward to use the existing code. Use a dedicated mmc_select_hs400 will make it clearer compared with adding more logic in the existing flow.

Thanks,
Peng.

Quoted 99 lines

JJ

Quoted 81 lines
drivers/mmc/mmc.c +26 -11
 				if (err)
 					goto error;
-			}
-			/* configure the bus mode (host) */
-			mmc_select_mode(mmc, mwt->mode);
-			mmc_set_clock(mmc, mmc->tran_speed, false);
+				/*
+				 * configure the bus width AND the ddr mode
+				 * (card). The host side will be taken care
+				 * of in the next step
+				 */
+				if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
+					err = mmc_switch(mmc,
+							 EXT_CSD_CMD_SET_NORMAL,
+							 EXT_CSD_BUS_WIDTH,
+							 ecbw->ext_csd_bits);
+					if (err)
+						goto error;
+				}
+
+				/* configure the bus mode (host) */
+				mmc_select_mode(mmc, mwt->mode);
+				mmc_set_clock(mmc, mmc->tran_speed, false);
 #ifdef MMC_SUPPORTS_TUNING
-			/* execute tuning if needed */
-			if (mwt->tuning) {
-				err = mmc_execute_tuning(mmc, mwt->tuning);
-				if (err) {
-					pr_debug("tuning failed\n");
-					goto error;
+				/* execute tuning if needed */
+				if (mwt->tuning) {
+					err = mmc_execute_tuning(mmc,
+								 mwt->tuning);
+					if (err) {
+						pr_debug("tuning failed\n");
+						goto error;
+					}
 				}
-			}
 #endif
+			}
 			/* do a transfer to check the configuration */
 			err = mmc_read_and_compare_ext_csd(mmc);
include/mmc.h +8 -0
index 86f885b504..8c01c6a530 100644
@@ -65,6 +65,7 @@
 #define MMC_MODE_HS_52MHz	MMC_CAP(MMC_HS_52)
 #define MMC_MODE_DDR_52MHz	MMC_CAP(MMC_DDR_52)
 #define MMC_MODE_HS200		MMC_CAP(MMC_HS_200)
+#define MMC_MODE_HS400		MMC_CAP(MMC_HS_400)
 #define MMC_MODE_8BIT		BIT(30)
 #define MMC_MODE_4BIT		BIT(29)
@@ -250,6 +251,11 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
 #define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
 					 EXT_CSD_CARD_TYPE_HS200_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	BIT(6)
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	BIT(7)
+#define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
@@ -260,6 +266,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
 #define EXT_CSD_TIMING_LEGACY	0	/* no high speed */
 #define EXT_CSD_TIMING_HS	1	/* HS */
 #define EXT_CSD_TIMING_HS200	2	/* HS200 */
+#define EXT_CSD_TIMING_HS400	3	/* HS400 */
 #define EXT_CSD_BOOT_ACK_ENABLE			(1 << 6)
 #define EXT_CSD_BOOT_PARTITION_ENABLE		(1 << 3)
@@ -520,6 +527,7 @@ enum bus_mode {
 	UHS_DDR50,
 	UHS_SDR104,
 	MMC_HS_200,
+	MMC_HS_400,
 	MMC_MODES_END
 };

include/mmc.h static inline bool mmc_is_mode_ddr(enum bus_mode mode) · line 550

Quoted 10 lines
include/mmc.h +4 -0
@@ -533,6 +541,10 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode)
 #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
 	else if (mode == UHS_DDR50)
 		return true;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	else if (mode == MMC_HS_400)
+		return true;
 #endif
 	else
 		return false;

_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
https://lists.denx.de/listinfo/u-boot

#5 lore raw

PATCH 1/2 mmc: add HS400 support

Quoted 152 lines · Peng Fan

Hi,

Quoted 142 lines · Jean-Jacques Hiblot

Hi Peng,

I'm glad you are adding HS400 support. Thanks.

Quoted 25 lines · Peng Fan

Add HS400 support.
Selecting HS400 needs first select HS199 according to spec, so use a dedicated function for HS400.
Add HS400 related macros.
Remove the restriction of only using the low 6 bits of EXT_CSD_CARD_TYPE, using all the 8 bits.

Cc Jaehoon Chung <[email protected]>
Cc Jean-Jacques Hiblot <[email protected]>
Cc Stefano Babic <[email protected]>
Cc Simon Glass <[email protected]>
Cc Kishon Vijay Abraham I <[email protected]>
Cc Bin Meng <[email protected]>
---
  drivers/mmc/Kconfig |   7 +++
  drivers/mmc/mmc.c   | 133 ++++++++++++++++++++++++++++++++++++++++++----------
  include/mmc.h       |  12 +++++
  3 files changed, 127 insertions(+), 25 deletions(-)
drivers/mmc/Kconfig +0 -0
index 5f67e336db..e9be18b333 100644

drivers/mmc/Kconfig config SPL_MMC_UHS_SUPPORT · line 108

Quoted 5 lines
drivers/mmc/Kconfig +3 -0
@@ -104,6 +104,13 @@ config SPL_MMC_UHS_SUPPORT
  	  cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
  	  frequency can go up to 208MHz (SDR104)
+config MMC_HS400_SUPPORT
+	bool "enable HS400 support"
+	select MMC_HS200_SUPPORT

I'd use "depends on" instead of select or maybe use the same option for both HS200 and HS400

Quoted 104 lines
drivers/mmc/Kconfig +4 -0
+	help
+	  The HS400 mode is support by some eMMC. The bus frequency is up to
+	  200MHz. This mode requires tuning the IO.
+
  config MMC_HS200_SUPPORT
  	bool "enable HS200 support"
  	help
drivers/mmc/mmc.c +47 -1
index 92ea78b8af..eef229c8b4 100644
@@ -169,6 +169,7 @@ const char *mmc_mode_name(enum bus_mode mode)
  	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
  	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
  	      [MMC_HS_200]	= "HS200 (200MHz)",
+	      [MMC_HS_400]	= "HS400 (200MHz)",
  	};
  	if (mode >= MMC_MODES_END)
@@ -193,6 +194,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
  	      [UHS_DDR50]	= 50000000,
  	      [UHS_SDR104]	= 208000000,
  	      [MMC_HS_200]	= 200000000,
+	      [MMC_HS_400]	= 200000000,
  	};
  	if (mode == MMC_LEGACY)
@@ -790,6 +792,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
  	case MMC_HS_200:
  		speed_bits = EXT_CSD_TIMING_HS200;
  		break;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	case MMC_HS_400:
+		speed_bits = EXT_CSD_TIMING_HS400;
+		break;
  #endif
  	case MMC_LEGACY:
  		speed_bits = EXT_CSD_TIMING_LEGACY;
@@ -837,7 +844,7 @@ static int mmc_get_capabilities(struct mmc *mmc)
  	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
-	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
+	cardtype = ext_csd[EXT_CSD_CARD_TYPE];
  	mmc->cardtype = cardtype;
  #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
@@ -845,6 +852,12 @@ static int mmc_get_capabilities(struct mmc *mmc)
  			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
  		mmc->card_caps |= MMC_MODE_HS200;
  	}
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V |
+			EXT_CSD_CARD_TYPE_HS400_1_8V)) {
+		mmc->card_caps |= MMC_MODE_HS400;
+	}
  #endif
  	if (cardtype & EXT_CSD_CARD_TYPE_52) {
  		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
@@ -1748,6 +1761,12 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
  	u32 card_mask = 0;
  	switch (mode) {
+	case MMC_HS_400:
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_8V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_180;
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_2V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_120;
+		break;
  	case MMC_HS_200:
  		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
  			card_mask |= MMC_SIGNAL_VOLTAGE_180;
@@ -1787,6 +1806,13 @@ static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
  #endif
  static const struct mode_width_tuning mmc_modes_by_pref[] = {
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	{
+		.mode = MMC_HS_400,
+		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
+		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
+	},
+#endif
  #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
  	{
  		.mode = MMC_HS_200,
@@ -1830,6 +1856,54 @@ static const struct ext_csd_bus_width {
  	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
  };
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+static int mmc_select_hs400(struct mmc *mmc)
+{
+	int err;
+
+	/* Set timing to HS200 for tuning */
+	err = mmc_set_card_speed(mmc, MMC_HS_200);
+	if (err)
+		return err;
+
+	/* configure the bus mode (host) */
+	mmc_select_mode(mmc, MMC_HS_200);
+	mmc_set_clock(mmc, mmc->tran_speed, false);
+
+	/* execute tuning if needed */
+	err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200);
+	if (err) {
+		debug("tuning failed\n");
+		return err;
+	}
Quoted 8 lines

drivers/mmc/mmc.c static const struct ext_csd_bus_width { · line 1885

Quoted 7 lines
drivers/mmc/mmc.c +7 -0
+
+	/* Set back to HS */
+	mmc_set_card_speed(mmc, MMC_HS);
+	mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
+
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG);

What happens if only 4 wires are used. It is a legit mode, isn't it ?

Quoted 1 line

According to spec, HS400 only supports 8bits mode, see "5.3.6 HS400 Bus Speed Mode".

Good. That makes it easier.
Can you add something to remove HS400 from the host capabilities if the 8-wires configuration is not available ?

Quoted 50 lines
Quoted 42 lines
Quoted 42 lines
drivers/mmc/mmc.c +22 -13
+	if (err)
+		return err;
+
+	err = mmc_set_card_speed(mmc, MMC_HS_400);
+	if (err)
+		return err;
+
+	mmc_select_mode(mmc, MMC_HS_400);
+	err = mmc_set_clock(mmc, mmc->tran_speed, false);
+	if (err)
+		return err;
+
+	return 0;
+}
+#else
+static int mmc_select_hs400(struct mmc *mmc)
+{
+	return -ENOTSUPP;
+}
+#endif
+
  #define for_each_supported_width(caps, ddr, ecbv) \
  	for (ecbv = ext_csd_bus_width;\
  	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
@@ -1883,37 +1957,46 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
  				goto error;
  			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
-			/* configure the bus speed (card) */
-			err = mmc_set_card_speed(mmc, mwt->mode);
-			if (err)
-				goto error;
-
-			/*
-			 * configure the bus width AND the ddr mode (card)
-			 * The host side will be taken care of in the next step
-			 */
-			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
-				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
-						 EXT_CSD_BUS_WIDTH,
-						 ecbw->ext_csd_bits);
+			if (mwt->mode == MMC_HS_400) {
Quoted 8 lines

drivers/mmc/mmc.c static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) · line 1966

Quoted 6 lines
drivers/mmc/mmc.c +6 -0
+				err = mmc_select_hs400(mmc);
+				if (err)
+					goto error;
+			} else {
+				/* configure the bus speed (card) */
+				err = mmc_set_card_speed(mmc, mwt->mode);

Instead of having?? a separate mmc_select_hs400() is not possible to leverage the existing code ?

Quoted 4 lines

hs400 requires first runs into HS200 mode, after tuning finished, need switch back to HS mode to configure bus. It's not that straightforward to use the existing code. Use a dedicated mmc_select_hs400 will make it clearer compared with adding more logic in the existing flow.

OK

Quoted 101 lines

Thanks,
Peng.

Quoted 97 lines

JJ

Quoted 81 lines
drivers/mmc/mmc.c +26 -11
  				if (err)
  					goto error;
-			}
-			/* configure the bus mode (host) */
-			mmc_select_mode(mmc, mwt->mode);
-			mmc_set_clock(mmc, mmc->tran_speed, false);
+				/*
+				 * configure the bus width AND the ddr mode
+				 * (card). The host side will be taken care
+				 * of in the next step
+				 */
+				if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
+					err = mmc_switch(mmc,
+							 EXT_CSD_CMD_SET_NORMAL,
+							 EXT_CSD_BUS_WIDTH,
+							 ecbw->ext_csd_bits);
+					if (err)
+						goto error;
+				}
+
+				/* configure the bus mode (host) */
+				mmc_select_mode(mmc, mwt->mode);
+				mmc_set_clock(mmc, mmc->tran_speed, false);
  #ifdef MMC_SUPPORTS_TUNING
-			/* execute tuning if needed */
-			if (mwt->tuning) {
-				err = mmc_execute_tuning(mmc, mwt->tuning);
-				if (err) {
-					pr_debug("tuning failed\n");
-					goto error;
+				/* execute tuning if needed */
+				if (mwt->tuning) {
+					err = mmc_execute_tuning(mmc,
+								 mwt->tuning);
+					if (err) {
+						pr_debug("tuning failed\n");
+						goto error;
+					}
  				}
-			}
  #endif
+			}
  			/* do a transfer to check the configuration */
  			err = mmc_read_and_compare_ext_csd(mmc);
include/mmc.h +8 -0
index 86f885b504..8c01c6a530 100644
@@ -65,6 +65,7 @@
  #define MMC_MODE_HS_52MHz	MMC_CAP(MMC_HS_52)
  #define MMC_MODE_DDR_52MHz	MMC_CAP(MMC_DDR_52)
  #define MMC_MODE_HS200		MMC_CAP(MMC_HS_200)
+#define MMC_MODE_HS400		MMC_CAP(MMC_HS_400)
  #define MMC_MODE_8BIT		BIT(30)
  #define MMC_MODE_4BIT		BIT(29)
@@ -250,6 +251,11 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
  #define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
  					 EXT_CSD_CARD_TYPE_HS200_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	BIT(6)
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	BIT(7)
+#define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+
  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
@@ -260,6 +266,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
  #define EXT_CSD_TIMING_LEGACY	0	/* no high speed */
  #define EXT_CSD_TIMING_HS	1	/* HS */
  #define EXT_CSD_TIMING_HS200	2	/* HS200 */
+#define EXT_CSD_TIMING_HS400	3	/* HS400 */
  #define EXT_CSD_BOOT_ACK_ENABLE			(1 << 6)
  #define EXT_CSD_BOOT_PARTITION_ENABLE		(1 << 3)
@@ -520,6 +527,7 @@ enum bus_mode {
  	UHS_DDR50,
  	UHS_SDR104,
  	MMC_HS_200,
+	MMC_HS_400,
  	MMC_MODES_END
  };

include/mmc.h static inline bool mmc_is_mode_ddr(enum bus_mode mode) · line 550

Quoted 10 lines
include/mmc.h +4 -0
@@ -533,6 +541,10 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode)
  #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
  	else if (mode == UHS_DDR50)
  		return true;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	else if (mode == MMC_HS_400)
+		return true;
  #endif
  	else
  		return false;

_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
https://lists.denx.de/listinfo/u-boot

author
#6 lore raw

PATCH 1/2 mmc: add HS400 support

Quoted 175 lines

-----Original Message-----
From: Jean-Jacques Hiblot [mailto:jjhiblot at ti.com]
Sent: 2018年3月6日 22:35
To: Peng Fan <[email protected]>
Cc: Peng Fan <[email protected]>; jh80.chung at samsung.com;
sbabic at denx.de; u-boot at lists.denx.de; Kishon Vijay Abraham I <[email protected]>
Subject: Re: [U-Boot] [PATCH 1/2] mmc: add HS400 support

Quoted 25 lines · Peng Fan

Hi,

Quoted 23 lines · Jean-Jacques Hiblot

Hi Peng,

I'm glad you are adding HS400 support. Thanks.

Quoted 17 lines · Peng Fan

Add HS400 support.
Selecting HS400 needs first select HS199 according to spec, so use a dedicated function for HS400.
Add HS400 related macros.
Remove the restriction of only using the low 6 bits of EXT_CSD_CARD_TYPE, using all the 8 bits.

Cc Jaehoon Chung <[email protected]>
Cc Jean-Jacques Hiblot <[email protected]>
Cc Stefano Babic <[email protected]>
Cc Simon Glass <[email protected]>
Cc Kishon Vijay Abraham I <[email protected]>
Cc Bin Meng <[email protected]>
---
  drivers/mmc/Kconfig |   7 +++
  drivers/mmc/mmc.c   | 133

++++++++++++++++++++++++++++++++++++++++++----------

Quoted 15 lines
Quoted 15 lines

drivers/mmc/Kconfig config SPL_MMC_UHS_SUPPORT · line 108

Quoted 13 lines
  include/mmc.h       |  12 +++++
  3 files changed, 127 insertions(+), 25 deletions(-)
drivers/mmc/Kconfig index renamed from drivers/mmc/Kconfig +0 -0

5f67e336db..e9be18b333 100644

drivers/mmc/Kconfig +3 -0
@@ -104,6 +104,13 @@ config SPL_MMC_UHS_SUPPORT
  	  cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
  	  frequency can go up to 208MHz (SDR104)
+config MMC_HS400_SUPPORT
+	bool "enable HS400 support"
+	select MMC_HS200_SUPPORT

I'd use "depends on" instead of select or maybe use the same option for both HS200 and HS400

Quoted 2 lines
Quoted 2 lines

drivers/mmc/Kconfig config SPL_MMC_UHS_SUPPORT · line 110

Quoted 2 lines
drivers/mmc/Kconfig +2 -0
+	help
+	  The HS400 mode is support by some eMMC. The bus frequency is up

to

Quoted 10 lines
Quoted 10 lines

drivers/mmc/mmc.c const char *mmc_mode_name(enum bus_mode

Quoted 10 lines
drivers/mmc/Kconfig +2 -0
+	  200MHz. This mode requires tuning the IO.
+
  config MMC_HS200_SUPPORT
  	bool "enable HS200 support"
  	help
drivers/mmc/mmc.c index renamed from drivers/mmc/mmc.c +0 -0

92ea78b8af..eef229c8b4 100644

drivers/mmc/mmc.c +0 -0
@@ -169,6 +169,7 @@ const char *mmc_mode_name(enum bus_mode

mode)

Quoted 7 lines
Quoted 7 lines

drivers/mmc/mmc.c static uint mmc_mode2freq(struct mmc *mmc,

Quoted 7 lines
drivers/mmc/mmc.c +1 -0
  	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
  	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
  	      [MMC_HS_200]	= "HS200 (200MHz)",
+	      [MMC_HS_400]	= "HS400 (200MHz)",
  	};
  	if (mode >= MMC_MODES_END)
@@ -193,6 +194,7 @@ static uint mmc_mode2freq(struct mmc *mmc,

enum bus_mode mode)

Quoted 7 lines
Quoted 7 lines

drivers/mmc/mmc.c static int mmc_set_card_speed(struct mmc

Quoted 7 lines
drivers/mmc/mmc.c +1 -0
  	      [UHS_DDR50]	= 50000000,
  	      [UHS_SDR104]	= 208000000,
  	      [MMC_HS_200]	= 200000000,
+	      [MMC_HS_400]	= 200000000,
  	};
  	if (mode == MMC_LEGACY)
@@ -790,6 +792,11 @@ static int mmc_set_card_speed(struct mmc

*mmc, enum bus_mode mode)

Quoted 11 lines
Quoted 11 lines

drivers/mmc/mmc.c static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)

Quoted 11 lines
drivers/mmc/mmc.c +5 -0
  	case MMC_HS_200:
  		speed_bits = EXT_CSD_TIMING_HS200;
  		break;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	case MMC_HS_400:
+		speed_bits = EXT_CSD_TIMING_HS400;
+		break;
  #endif
  	case MMC_LEGACY:
  		speed_bits = EXT_CSD_TIMING_LEGACY; @@ -837,7 +844,7

@@ static

Quoted 7 lines
Quoted 7 lines

drivers/mmc/mmc.c static int mmc_get_capabilities(struct mmc

Quoted 7 lines

int mmc_get_capabilities(struct mmc *mmc)
mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;

drivers/mmc/mmc.c +1 -1
-	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
+	cardtype = ext_csd[EXT_CSD_CARD_TYPE];
  	mmc->cardtype = cardtype;
  #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
@@ -845,6 +852,12 @@ static int mmc_get_capabilities(struct mmc

*mmc)

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/mmc/mmc.c +1 -0
  			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
  		mmc->card_caps |= MMC_MODE_HS200;
  	}
+#endif
Quoted 8 lines
Quoted 8 lines

drivers/mmc/mmc.c static int mmc_get_capabilities(struct mmc *mmc)

Quoted 8 lines
drivers/mmc/mmc.c +5 -0
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V |
+			EXT_CSD_CARD_TYPE_HS400_1_8V)) {
+		mmc->card_caps |= MMC_MODE_HS400;
+	}
  #endif
  	if (cardtype & EXT_CSD_CARD_TYPE_52) {
  		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) @@ -1748,6

+1761,12 @@

Quoted 1 line
Quoted 1 line
Quoted 1 line

static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode

mode,

Quoted 11 lines
Quoted 11 lines

drivers/mmc/mmc.c static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,

Quoted 11 lines
  	u32 card_mask = 0;
  	switch (mode) {
drivers/mmc/mmc.c +6 -0
+	case MMC_HS_400:
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_8V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_180;
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_2V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_120;
+		break;
  	case MMC_HS_200:
  		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
  			card_mask |= MMC_SIGNAL_VOLTAGE_180; @@ -1787,6

+1806,13 @@

Quoted 1 line
Quoted 1 line
Quoted 1 line

static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum

bus_mode mode,

Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
  #endif
  static const struct mode_width_tuning mmc_modes_by_pref[] = {
drivers/mmc/mmc.c +14 -0
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	{
+		.mode = MMC_HS_400,
+		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
+		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
+	},
+#endif
  #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
  	{
  		.mode = MMC_HS_200,
@@ -1830,6 +1856,54 @@ static const struct ext_csd_bus_width {
  	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
  };
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+static int mmc_select_hs400(struct mmc *mmc) {
+	int err;
+
+	/* Set timing to HS200 for tuning */
+	err = mmc_set_card_speed(mmc, MMC_HS_200);
+	if (err)
Quoted 8 lines
Quoted 8 lines

drivers/mmc/mmc.c static const struct ext_csd_bus_width {

Quoted 8 lines
drivers/mmc/mmc.c +8 -0
+		return err;
+
+	/* configure the bus mode (host) */
+	mmc_select_mode(mmc, MMC_HS_200);
+	mmc_set_clock(mmc, mmc->tran_speed, false);
+
+	/* execute tuning if needed */
+	err = mmc_execute_tuning(mmc,

MMC_CMD_SEND_TUNING_BLOCK_HS200);

Quoted 10 lines
Quoted 10 lines

drivers/mmc/mmc.c static const struct ext_csd_bus_width {

Quoted 10 lines
drivers/mmc/mmc.c +10 -0
+	if (err) {
+		debug("tuning failed\n");
+		return err;
+	}
+
+	/* Set back to HS */
+	mmc_set_card_speed(mmc, MMC_HS);
+	mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
+
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,

EXT_CSD_BUS_WIDTH,

Quoted 7 lines
Quoted 3 lines
Quoted 2 lines

drivers/mmc/mmc.c static const struct ext_csd_bus_width { · line 1885

Quoted 1 line
drivers/mmc/mmc.c +1 -0
+			 EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG);

What happens if only 4 wires are used. It is a legit mode, isn't it ?

According to spec, HS400 only supports 8bits mode, see "5.3.6 HS400 Bus

Speed Mode".
Good. That makes it easier.
Can you add something to remove HS400 from the host capabilities if the 8-wires configuration is not available ?

In mmc_select_mode_and_width:
"card_caps &= mmc->host_caps;" I think this line has already done that. When host_caps does not support 8-wires, the card_caps will be set not Supporting 8-wires and HS400 mode will be selected.

I think I need remove the MMC_MODE_4BIT from HS400 mode in the mmc_modes_by_pref array.

Thanks,
Peng.

Quoted 173 lines
Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
drivers/mmc/mmc.c +15 -0
+	if (err)
+		return err;
+
+	err = mmc_set_card_speed(mmc, MMC_HS_400);
+	if (err)
+		return err;
+
+	mmc_select_mode(mmc, MMC_HS_400);
+	err = mmc_set_clock(mmc, mmc->tran_speed, false);
+	if (err)
+		return err;
+
+	return 0;
+}
+#else
Quoted 8 lines
Quoted 8 lines

drivers/mmc/mmc.c static const struct ext_csd_bus_width { · line 1909

Quoted 8 lines
drivers/mmc/mmc.c +5 -0
+static int mmc_select_hs400(struct mmc *mmc) {
+	return -ENOTSUPP;
+}
+#endif
+
  #define for_each_supported_width(caps, ddr, ecbv) \
  	for (ecbv = ext_csd_bus_width;\
  	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\

@@

Quoted 1 line
Quoted 1 line

drivers/mmc/mmc.c static const struct ext_csd_bus_width { · line 1835

Quoted 1 line
drivers/mmc/mmc.c +0 -1
-1883,37 +1957,46 @@ static int mmc_select_mode_and_width(struct

mmc *mmc, uint card_caps)

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
drivers/mmc/mmc.c +0 -3
  				goto error;
  			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
-			/* configure the bus speed (card) */
-			err = mmc_set_card_speed(mmc, mwt->mode);
-			if (err)
Quoted 8 lines
Quoted 8 lines

drivers/mmc/mmc.c static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)

Quoted 8 lines
drivers/mmc/mmc.c +0 -8
-				goto error;
-
-			/*
-			 * configure the bus width AND the ddr mode (card)
-			 * The host side will be taken care of in the next step
-			 */
-			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
-				err = mmc_switch(mmc,

EXT_CSD_CMD_SET_NORMAL,

Quoted 11 lines
Quoted 11 lines

drivers/mmc/mmc.c static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) · line 1966

Quoted 9 lines
drivers/mmc/mmc.c +7 -2
-						 EXT_CSD_BUS_WIDTH,
-						 ecbw->ext_csd_bits);
+			if (mwt->mode == MMC_HS_400) {
+				err = mmc_select_hs400(mmc);
+				if (err)
+					goto error;
+			} else {
+				/* configure the bus speed (card) */
+				err = mmc_set_card_speed(mmc, mwt->mode);

Instead of having?? a separate mmc_select_hs400() is not possible to leverage the existing code ?

Quoted 4 lines

hs400 requires first runs into HS200 mode, after tuning finished, need switch back to HS mode to configure bus. It's not that straightforward to use the existing code. Use a dedicated mmc_select_hs400 will make it clearer compared with adding more logic in the existing flow.

OK

Quoted 54 lines

Thanks,
Peng.

Quoted 50 lines

JJ

Quoted 48 lines

if (err)
goto error;

drivers/mmc/mmc.c +26 -11
-			}
-			/* configure the bus mode (host) */
-			mmc_select_mode(mmc, mwt->mode);
-			mmc_set_clock(mmc, mmc->tran_speed, false);
+				/*
+				 * configure the bus width AND the ddr mode
+				 * (card). The host side will be taken care
+				 * of in the next step
+				 */
+				if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
+					err = mmc_switch(mmc,
+							 EXT_CSD_CMD_SET_NORMAL,
+							 EXT_CSD_BUS_WIDTH,
+							 ecbw->ext_csd_bits);
+					if (err)
+						goto error;
+				}
+
+				/* configure the bus mode (host) */
+				mmc_select_mode(mmc, mwt->mode);
+				mmc_set_clock(mmc, mmc->tran_speed, false);
  #ifdef MMC_SUPPORTS_TUNING
-			/* execute tuning if needed */
-			if (mwt->tuning) {
-				err = mmc_execute_tuning(mmc, mwt->tuning);
-				if (err) {
-					pr_debug("tuning failed\n");
-					goto error;
+				/* execute tuning if needed */
+				if (mwt->tuning) {
+					err = mmc_execute_tuning(mmc,
+								 mwt->tuning);
+					if (err) {
+						pr_debug("tuning failed\n");
+						goto error;
+					}
  				}
-			}
  #endif
+			}
  			/* do a transfer to check the configuration */
  			err = mmc_read_and_compare_ext_csd(mmc);
include/mmc.h index renamed from include/mmc.h +0 -0

86f885b504..8c01c6a530 100644

include/mmc.h +0 -0
Quoted 8 lines
Quoted 8 lines

include/mmc.h static inline bool mmc_is_tuning_cmd(uint

Quoted 8 lines
include/mmc.h +1 -0
@@ -65,6 +65,7 @@
  #define MMC_MODE_HS_52MHz	MMC_CAP(MMC_HS_52)
  #define MMC_MODE_DDR_52MHz	MMC_CAP(MMC_DDR_52)
  #define MMC_MODE_HS200		MMC_CAP(MMC_HS_200)
+#define MMC_MODE_HS400		MMC_CAP(MMC_HS_400)
  #define MMC_MODE_8BIT		BIT(30)
  #define MMC_MODE_4BIT		BIT(29)
@@ -250,6 +251,11 @@ static inline bool mmc_is_tuning_cmd(uint

cmdidx)

Quoted 1 line
Quoted 1 line

include/mmc.h static inline bool mmc_is_tuning_cmd(uint · line 251

Quoted 1 line
include/mmc.h +0 -0
  #define EXT_CSD_CARD_TYPE_HS200
	(EXT_CSD_CARD_TYPE_HS200_1_8V | \
Quoted 4 lines
Quoted 4 lines

include/mmc.h static inline bool mmc_is_tuning_cmd(uint cmdidx)

Quoted 4 lines
include/mmc.h +3 -0
  					 EXT_CSD_CARD_TYPE_HS200_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	BIT(6)
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	BIT(7)
+#define EXT_CSD_CARD_TYPE_HS400
	(EXT_CSD_CARD_TYPE_HS400_1_8V | \
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
include/mmc.h +3 -0
+					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+
  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
@@ -260,6 +266,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
  #define EXT_CSD_TIMING_LEGACY	0	/* no high speed */
  #define EXT_CSD_TIMING_HS	1	/* HS */
  #define EXT_CSD_TIMING_HS200	2	/* HS200 */
+#define EXT_CSD_TIMING_HS400	3	/* HS400 */
  #define EXT_CSD_BOOT_ACK_ENABLE			(1 << 6)
  #define EXT_CSD_BOOT_PARTITION_ENABLE		(1 << 3)
Quoted 8 lines
Quoted 8 lines

include/mmc.h static inline bool mmc_is_mode_ddr(enum

Quoted 8 lines
include/mmc.h +1 -0
@@ -520,6 +527,7 @@ enum bus_mode {
  	UHS_DDR50,
  	UHS_SDR104,
  	MMC_HS_200,
+	MMC_HS_400,
  	MMC_MODES_END
  };
@@ -533,6 +541,10 @@ static inline bool mmc_is_mode_ddr(enum

bus_mode mode)

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
include/mmc.h +4 -0
  #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
  	else if (mode == UHS_DDR50)
  		return true;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	else if (mode == MMC_HS_400)
+		return true;
Quoted 8 lines
Quoted 8 lines

include/mmc.h static inline bool mmc_is_mode_ddr(enum bus_mode mode) · line 550

Quoted 3 lines
include/mmc.h +0 -0
  #endif
  	else
  		return false;

_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fli

sts.denx.de%2Flistinfo%2Fu-boot&data=02%7C01%7Cpeng.fan%40nxp.com%7C c

Quoted 1 line
Quoted 1 line

1f326580e3a487c2b4f08d5836f7587%7C686ea1d3bc2b4c6fa92cd99c5c301635 %7C

Quoted 1 line
Quoted 1 line

0%7C0%7C636559437115011742&sdata=l%2BuDMMe8ZWIi2uM7hIIVgAIezjm stIuZ66

Quoted 1 line
Quoted 1 line

6dewGYSjc%3D&reserved=0

#7 lore raw

PATCH 1/2 mmc: add HS400 support

In reply to Peng Fan

Hi Peng,

Quoted 80 lines · Peng Fan

Add HS400 support.
Selecting HS400 needs first select HS199 according to spec, so use a dedicated function for HS400.
Add HS400 related macros.
Remove the restriction of only using the low 6 bits of EXT_CSD_CARD_TYPE, using all the 8 bits.

Cc Jaehoon Chung <[email protected]>
Cc Jean-Jacques Hiblot <[email protected]>
Cc Stefano Babic <[email protected]>
Cc Simon Glass <[email protected]>
Cc Kishon Vijay Abraham I <[email protected]>
Cc Bin Meng <[email protected]>
---
 drivers/mmc/Kconfig |   7 +++
 drivers/mmc/mmc.c   | 133 ++++++++++++++++++++++++++++++++++++++++++----------
 include/mmc.h       |  12 +++++
 3 files changed, 127 insertions(+), 25 deletions(-)
drivers/mmc/Kconfig +7 -0
index 5f67e336db..e9be18b333 100644
@@ -104,6 +104,13 @@ config SPL_MMC_UHS_SUPPORT
          cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
          frequency can go up to 208MHz (SDR104)
 
+config MMC_HS400_SUPPORT
+       bool "enable HS400 support"
+       select MMC_HS200_SUPPORT
+       help
+         The HS400 mode is support by some eMMC. The bus frequency is up to
+         200MHz. This mode requires tuning the IO.
+
 config MMC_HS200_SUPPORT
        bool "enable HS200 support"
        help
drivers/mmc/mmc.c +8 -1
index 92ea78b8af..eef229c8b4 100644
@@ -169,6 +169,7 @@ const char *mmc_mode_name(enum bus_mode mode)
              [MMC_HS_52]       = "MMC High Speed (52MHz)",
              [MMC_DDR_52]      = "MMC DDR52 (52MHz)",
              [MMC_HS_200]      = "HS200 (200MHz)",
+             [MMC_HS_400]      = "HS400 (200MHz)",
        };
 
        if (mode >= MMC_MODES_END)
@@ -193,6 +194,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
              [UHS_DDR50]       = 50000000,
              [UHS_SDR104]      = 208000000,
              [MMC_HS_200]      = 200000000,
+             [MMC_HS_400]      = 200000000,
        };
 
        if (mode == MMC_LEGACY)
@@ -790,6 +792,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
        case MMC_HS_200:
                speed_bits = EXT_CSD_TIMING_HS200;
                break;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+       case MMC_HS_400:
+               speed_bits = EXT_CSD_TIMING_HS400;
+               break;
 #endif
        case MMC_LEGACY:
                speed_bits = EXT_CSD_TIMING_LEGACY;
@@ -837,7 +844,7 @@ static int mmc_get_capabilities(struct mmc *mmc)
 
        mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
 
-       cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
+       cardtype = ext_csd[EXT_CSD_CARD_TYPE];
        mmc->cardtype = cardtype;
 
 #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)

drivers/mmc/mmc.c static int mmc_get_capabilities(struct mmc *mmc) · line 856

Quoted 5 lines
drivers/mmc/mmc.c +2 -0
@@ -845,6 +852,12 @@ static int mmc_get_capabilities(struct mmc *mmc)
                        EXT_CSD_CARD_TYPE_HS200_1_8V)) {
                mmc->card_caps |= MMC_MODE_HS200;
        }
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)

Is it possible to use if () instead of #if

Regards,
Simon

author
#8 lore raw

PATCH 1/2 mmc: add HS400 support

Hi Simon,

Quoted 98 lines

-----Original Message-----
From: sjg at google.com [mailto:sjg at google.com] On Behalf Of Simon Glass
Sent: 2018年3月7日 1:42
To: Peng Fan <[email protected]>
Cc: Jaehoon Chung <[email protected]>; Stefano Babic <[email protected]>; U-Boot Mailing List <[email protected]>; Jean-Jacques Hiblot <[email protected]>; Kishon Vijay Abraham I <[email protected]>; Bin Meng <[email protected]>
Subject: Re: [PATCH 1/2] mmc: add HS400 support

Hi Peng,

Quoted 14 lines · Peng Fan

Add HS400 support.
Selecting HS400 needs first select HS199 according to spec, so use a dedicated function for HS400.
Add HS400 related macros.
Remove the restriction of only using the low 6 bits of EXT_CSD_CARD_TYPE, using all the 8 bits.

Cc Jaehoon Chung <[email protected]>
Cc Jean-Jacques Hiblot <[email protected]>
Cc Stefano Babic <[email protected]>
Cc Simon Glass <[email protected]>
Cc Kishon Vijay Abraham I <[email protected]>
Cc Bin Meng <[email protected]>
Quoted 3 lines
---
 drivers/mmc/Kconfig |   7 +++
 drivers/mmc/mmc.c   | 133

++++++++++++++++++++++++++++++++++++++++++----------

drivers/mmc/Kconfig config SPL_MMC_UHS_SUPPORT · line 104

Quoted 9 lines
 include/mmc.h       |  12 +++++
 3 files changed, 127 insertions(+), 25 deletions(-)
drivers/mmc/Kconfig index renamed from drivers/mmc/Kconfig +0 -0

5f67e336db..e9be18b333 100644

drivers/mmc/Kconfig +0 -0
@@ -104,6 +104,13 @@ config SPL_MMC_UHS_SUPPORT
          cards. The IO voltage must be switchable from 3.3v to 1.8v. The

bus

drivers/mmc/Kconfig config SPL_MMC_UHS_SUPPORT

Quoted 7 lines
drivers/mmc/Kconfig +5 -0
          frequency can go up to 208MHz (SDR104)
 
+config MMC_HS400_SUPPORT
+       bool "enable HS400 support"
+       select MMC_HS200_SUPPORT
+       help
+         The HS400 mode is support by some eMMC. The bus frequency is

up to

drivers/mmc/mmc.c const char *mmc_mode_name(enum bus_mode

Quoted 10 lines
drivers/mmc/Kconfig +2 -0
+         200MHz. This mode requires tuning the IO.
+
 config MMC_HS200_SUPPORT
        bool "enable HS200 support"
        help
drivers/mmc/mmc.c index renamed from drivers/mmc/mmc.c +0 -0

92ea78b8af..eef229c8b4 100644

drivers/mmc/mmc.c +0 -0
@@ -169,6 +169,7 @@ const char *mmc_mode_name(enum bus_mode

mode)

drivers/mmc/mmc.c static uint mmc_mode2freq(struct mmc *mmc, enum

Quoted 8 lines
drivers/mmc/mmc.c +1 -0
              [MMC_HS_52]       = "MMC High Speed (52MHz)",
              [MMC_DDR_52]      = "MMC DDR52 (52MHz)",
              [MMC_HS_200]      = "HS200 (200MHz)",
+             [MMC_HS_400]      = "HS400 (200MHz)",
        };
 
        if (mode >= MMC_MODES_END)
@@ -193,6 +194,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum

bus_mode mode)

drivers/mmc/mmc.c static int mmc_set_card_speed(struct mmc *mmc,

Quoted 8 lines
drivers/mmc/mmc.c +1 -0
              [UHS_DDR50]       = 50000000,
              [UHS_SDR104]      = 208000000,
              [MMC_HS_200]      = 200000000,
+             [MMC_HS_400]      = 200000000,
        };
 
        if (mode == MMC_LEGACY)
@@ -790,6 +792,11 @@ static int mmc_set_card_speed(struct mmc *mmc,

enum bus_mode mode)

drivers/mmc/mmc.c static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)

Quoted 11 lines
drivers/mmc/mmc.c +5 -0
        case MMC_HS_200:
                speed_bits = EXT_CSD_TIMING_HS200;
                break;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+       case MMC_HS_400:
+               speed_bits = EXT_CSD_TIMING_HS400;
+               break;
 #endif
        case MMC_LEGACY:
                speed_bits = EXT_CSD_TIMING_LEGACY; @@ -837,7

+844,7

Quoted 8 lines

@@ static int mmc_get_capabilities(struct mmc *mmc)

        mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
drivers/mmc/mmc.c +1 -1
-       cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
+       cardtype = ext_csd[EXT_CSD_CARD_TYPE];
        mmc->cardtype = cardtype;
Quoted 9 lines

drivers/mmc/mmc.c static int mmc_get_capabilities(struct mmc *mmc) · line 856

Quoted 7 lines

#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)

drivers/mmc/mmc.c +2 -0
@@ -845,6 +852,12 @@ static int mmc_get_capabilities(struct mmc *mmc)
                        EXT_CSD_CARD_TYPE_HS200_1_8V)) {
                mmc->card_caps |= MMC_MODE_HS200;
        }
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)

Is it possible to use if () instead of #if

Just want to keep the same code style in the file. How about use a dedicated patch to cleanup the file after this patch?
Thanks,
Peng.

Quoted 3 lines

Regards,
Simon

#9 lore raw

PATCH 1/2 mmc: add HS400 support

In reply to Peng Fan

Hi,

Quoted 6 lines · Peng Fan

Add HS400 support.
Selecting HS400 needs first select HS199 according to spec, so use a dedicated function for HS400.
Add HS400 related macros.
Remove the restriction of only using the low 6 bits of EXT_CSD_CARD_TYPE, using all the 8 bits.

Sorry for late.

Quoted 86 lines
Cc Jaehoon Chung <[email protected]>
Cc Jean-Jacques Hiblot <[email protected]>
Cc Stefano Babic <[email protected]>
Cc Simon Glass <[email protected]>
Cc Kishon Vijay Abraham I <[email protected]>
Cc Bin Meng <[email protected]>
---
 drivers/mmc/Kconfig |   7 +++
 drivers/mmc/mmc.c   | 133 ++++++++++++++++++++++++++++++++++++++++++----------
 include/mmc.h       |  12 +++++
 3 files changed, 127 insertions(+), 25 deletions(-)
drivers/mmc/Kconfig +7 -0
index 5f67e336db..e9be18b333 100644
@@ -104,6 +104,13 @@ config SPL_MMC_UHS_SUPPORT
 	  cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
 	  frequency can go up to 208MHz (SDR104)
 
+config MMC_HS400_SUPPORT
+	bool "enable HS400 support"
+	select MMC_HS200_SUPPORT
+	help
+	  The HS400 mode is support by some eMMC. The bus frequency is up to
+	  200MHz. This mode requires tuning the IO.
+
 config MMC_HS200_SUPPORT
 	bool "enable HS200 support"
 	help
drivers/mmc/mmc.c +14 -1
index 92ea78b8af..eef229c8b4 100644
@@ -169,6 +169,7 @@ const char *mmc_mode_name(enum bus_mode mode)
 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
 	      [MMC_HS_200]	= "HS200 (200MHz)",
+	      [MMC_HS_400]	= "HS400 (200MHz)",
 	};
 
 	if (mode >= MMC_MODES_END)
@@ -193,6 +194,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
 	      [UHS_DDR50]	= 50000000,
 	      [UHS_SDR104]	= 208000000,
 	      [MMC_HS_200]	= 200000000,
+	      [MMC_HS_400]	= 200000000,
 	};
 
 	if (mode == MMC_LEGACY)
@@ -790,6 +792,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
 	case MMC_HS_200:
 		speed_bits = EXT_CSD_TIMING_HS200;
 		break;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	case MMC_HS_400:
+		speed_bits = EXT_CSD_TIMING_HS400;
+		break;>  #endif
 	case MMC_LEGACY:
 		speed_bits = EXT_CSD_TIMING_LEGACY;
@@ -837,7 +844,7 @@ static int mmc_get_capabilities(struct mmc *mmc)
 
 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
 
-	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
+	cardtype = ext_csd[EXT_CSD_CARD_TYPE];
 	mmc->cardtype = cardtype;
 
 #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
@@ -845,6 +852,12 @@ static int mmc_get_capabilities(struct mmc *mmc)
 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
 		mmc->card_caps |= MMC_MODE_HS200;
 	}
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V |
+			EXT_CSD_CARD_TYPE_HS400_1_8V)) {
+		mmc->card_caps |= MMC_MODE_HS400;
+	}
 #endif
 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)

drivers/mmc/mmc.c static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, · line 1769

Quoted 9 lines
drivers/mmc/mmc.c +6 -0
@@ -1748,6 +1761,12 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
 	u32 card_mask = 0;
 
 	switch (mode) {
+	case MMC_HS_400:
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_8V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_180;
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_2V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_120;
+		break;

I think that it's possible to use the below.

case MMS_HS_400:
case MMC_HS_200:

	if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V | EXT_CSD_CARD_TYPE_HS400_1_8V)
		....

Isn't it?

drivers/mmc/mmc.c static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, · line 1812

Quoted 11 lines
drivers/mmc/mmc.c +4 -0
 	case MMC_HS_200:
 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
 			card_mask |= MMC_SIGNAL_VOLTAGE_180;
@@ -1787,6 +1806,13 @@ static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
 #endif
 
 static const struct mode_width_tuning mmc_modes_by_pref[] = {
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	{
+		.mode = MMC_HS_400,
+		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,

4BIT? As i know, HS400 mode doesn't support the 4BIT mode.

Quoted 38 lines
drivers/mmc/mmc.c +31 -0
+		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
+	},
+#endif
 #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
 	{
 		.mode = MMC_HS_200,
@@ -1830,6 +1856,54 @@ static const struct ext_csd_bus_width {
 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
 };
 
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+static int mmc_select_hs400(struct mmc *mmc)
+{
+	int err;
+
+	/* Set timing to HS200 for tuning */
+	err = mmc_set_card_speed(mmc, MMC_HS_200);
+	if (err)
+		return err;
+
+	/* configure the bus mode (host) */
+	mmc_select_mode(mmc, MMC_HS_200);
+	mmc_set_clock(mmc, mmc->tran_speed, false);
+
+	/* execute tuning if needed */
+	err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200);
+	if (err) {
+		debug("tuning failed\n");
+		return err;
+	}
+
+	/* Set back to HS */
+	mmc_set_card_speed(mmc, MMC_HS);
+	mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
+
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG);
+	if (err)

drivers/mmc/mmc.c static const struct ext_csd_bus_width { · line 1896

Quoted 10 lines
drivers/mmc/mmc.c +10 -0
+		return err;
+
+	err = mmc_set_card_speed(mmc, MMC_HS_400);
+	if (err)
+		return err;
+
+	mmc_select_mode(mmc, MMC_HS_400);
+	err = mmc_set_clock(mmc, mmc->tran_speed, false);
+	if (err)
+		return err;

Hmm. I didn't test this patch.. but i guess if it's failed, isn't it possible to use the other bus mode?

Quoted 22 lines
drivers/mmc/mmc.c +10 -5
+
+	return 0;
+}
+#else
+static int mmc_select_hs400(struct mmc *mmc)
+{
+	return -ENOTSUPP;
+}
+#endif
+
 #define for_each_supported_width(caps, ddr, ecbv) \
 	for (ecbv = ext_csd_bus_width;\
 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
@@ -1883,37 +1957,46 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
 				goto error;
 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
 
-			/* configure the bus speed (card) */
-			err = mmc_set_card_speed(mmc, mwt->mode);
-			if (err)
-				goto error;
-

drivers/mmc/mmc.c static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) · line 1961

Quoted 10 lines
drivers/mmc/mmc.c +2 -8
-			/*
-			 * configure the bus width AND the ddr mode (card)
-			 * The host side will be taken care of in the next step
-			 */
-			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
-				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
-						 EXT_CSD_BUS_WIDTH,
-						 ecbw->ext_csd_bits);
+			if (mwt->mode == MMC_HS_400) {
+				err = mmc_select_hs400(mmc);

doesn't need to add some error message? It's useful to notice to user.

Quoted 104 lines
drivers/mmc/mmc.c +31 -11
+				if (err)
+					goto error;
+			} else {
+				/* configure the bus speed (card) */
+				err = mmc_set_card_speed(mmc, mwt->mode);
 				if (err)
 					goto error;
-			}
 
-			/* configure the bus mode (host) */
-			mmc_select_mode(mmc, mwt->mode);
-			mmc_set_clock(mmc, mmc->tran_speed, false);
+				/*
+				 * configure the bus width AND the ddr mode
+				 * (card). The host side will be taken care
+				 * of in the next step
+				 */
+				if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
+					err = mmc_switch(mmc,
+							 EXT_CSD_CMD_SET_NORMAL,
+							 EXT_CSD_BUS_WIDTH,
+							 ecbw->ext_csd_bits);
+					if (err)
+						goto error;
+				}
+
+				/* configure the bus mode (host) */
+				mmc_select_mode(mmc, mwt->mode);
+				mmc_set_clock(mmc, mmc->tran_speed, false);
 #ifdef MMC_SUPPORTS_TUNING
 
-			/* execute tuning if needed */
-			if (mwt->tuning) {
-				err = mmc_execute_tuning(mmc, mwt->tuning);
-				if (err) {
-					pr_debug("tuning failed\n");
-					goto error;
+				/* execute tuning if needed */
+				if (mwt->tuning) {
+					err = mmc_execute_tuning(mmc,
+								 mwt->tuning);
+					if (err) {
+						pr_debug("tuning failed\n");
+						goto error;
+					}
 				}
-			}
 #endif
+			}
 
 			/* do a transfer to check the configuration */
 			err = mmc_read_and_compare_ext_csd(mmc);
include/mmc.h +12 -0
index 86f885b504..8c01c6a530 100644
@@ -65,6 +65,7 @@
 #define MMC_MODE_HS_52MHz	MMC_CAP(MMC_HS_52)
 #define MMC_MODE_DDR_52MHz	MMC_CAP(MMC_DDR_52)
 #define MMC_MODE_HS200		MMC_CAP(MMC_HS_200)
+#define MMC_MODE_HS400		MMC_CAP(MMC_HS_400)
 
 #define MMC_MODE_8BIT		BIT(30)
 #define MMC_MODE_4BIT		BIT(29)
@@ -250,6 +251,11 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
 #define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
 					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	BIT(6)
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	BIT(7)
+#define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
@@ -260,6 +266,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
 #define EXT_CSD_TIMING_LEGACY	0	/* no high speed */
 #define EXT_CSD_TIMING_HS	1	/* HS */
 #define EXT_CSD_TIMING_HS200	2	/* HS200 */
+#define EXT_CSD_TIMING_HS400	3	/* HS400 */
 
 #define EXT_CSD_BOOT_ACK_ENABLE			(1 << 6)
 #define EXT_CSD_BOOT_PARTITION_ENABLE		(1 << 3)
@@ -520,6 +527,7 @@ enum bus_mode {
 	UHS_DDR50,
 	UHS_SDR104,
 	MMC_HS_200,
+	MMC_HS_400,
 	MMC_MODES_END
 };
 
@@ -533,6 +541,10 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode)
 #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
 	else if (mode == UHS_DDR50)
 		return true;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	else if (mode == MMC_HS_400)
+		return true;
 #endif
 	else
 		return false;