mmc: add HS400 support
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.
--- 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
@@ -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
@@ -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
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. "
--- drivers/mmc/fsl_esdhc.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-)
drivers/mmc/fsl_esdhc.c +34 -1
@@ -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 , ®s->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, ®s->strobe_dllctrl); +/* wait 1us to make sure strobe dll status register stable */ +mdelay (1 ); + v =readl (®s->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, ®s->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
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 adata_strobeline. 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_strobeline. Due to the time delay between CLK line anddata_strobeline, if the delay time is larger than one clock cycle, then CLK anddata_strobeline 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
Signed-off-by Peng Fan <[email protected]>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@@ -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 , ®s->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, ®s->strobe_dllctrl); +/* wait 1us to make sure strobe dll status register stable */ +mdelay (1 ); + v =readl (®s->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, ®s->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:
PATCH 1/2 mmc: add HS400 support
In reply to Peng FanHi 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 ofEXT_CSD_CARD_TYPE, using all the 8 bits.Signed-off-by Peng Fan <[email protected]>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
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" helpdrivers/mmc/mmc.c +44
-1@@ -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
-11if (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@@ -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;
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 ofEXT_CSD_CARD_TYPE, using all the 8 bits.Signed-off-by Peng Fan <[email protected]>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
-0drivers/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_SUPPORTI'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" helpdrivers/mmc/mmc.c +47
-1@@ -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
-11if (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@@ -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
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 ofEXT_CSD_CARD_TYPE, using all the 8 bits.Signed-off-by Peng Fan <[email protected]>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
-0drivers/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_SUPPORTI'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" helpdrivers/mmc/mmc.c +47
-1@@ -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_hs400will 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
-11if (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@@ -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
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 supportQuoted 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 ofEXT_CSD_CARD_TYPE, using all the 8 bits.Signed-off-by Peng Fan <[email protected]>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..e9be18b333100644drivers/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_SUPPORTI'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 upto
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" helpdrivers/mmc/mmc.c index renamed from drivers/mmc/mmc.c +0
-0
92ea78b8af..eef229c8b4100644drivers/mmc/mmc.c +0
-0@@ -169,6 +169,7 @@ const char *mmc_mode_name(enum bus_modemode)
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_modemode)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_modemode)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
-0case 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
-0EXT_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_modemode,
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_modemode,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(structmmc *mmc, uint
card_caps)Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
drivers/mmc/mmc.c +0
-3goto 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_hs400will 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..8c01c6a530100644include/mmc.h +0
-0Quoted 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(uintcmdidx)
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
-0EXT_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_modemode)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%2Flists.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
PATCH 1/2 mmc: add HS400 support
In reply to Peng FanHi 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 ofEXT_CSD_CARD_TYPE, using all the 8 bits.Signed-off-by Peng Fan <[email protected]>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@@ -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" helpdrivers/mmc/mmc.c +8
-1@@ -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
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 supportHi 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 ofEXT_CSD_CARD_TYPE, using all the 8 bits.Signed-off-by Peng Fan <[email protected]>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..e9be18b333100644drivers/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. Thebus
drivers/mmc/Kconfig config SPL_MMC_UHS_SUPPORT
Quoted 7 lines
drivers/mmc/Kconfig +5
-0frequency 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 isup 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" helpdrivers/mmc/mmc.c index renamed from drivers/mmc/mmc.c +0
-0
92ea78b8af..eef229c8b4100644drivers/mmc/mmc.c +0
-0@@ -169,6 +169,7 @@ const char *mmc_mode_name(enum bus_modemode)
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_modemode)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_modemode)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
-0case 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
PATCH 1/2 mmc: add HS400 support
In reply to Peng FanHi,
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 ofEXT_CSD_CARD_TYPE, using all the 8 bits.
Sorry for late.
Quoted 86 lines
Signed-off-by Peng Fan <[email protected]>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@@ -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" helpdrivers/mmc/mmc.c +14
-1@@ -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;> #endifcase 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
-0case 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@@ -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;