[U-Boot] [PATCH V4 1/2] mmc: add HS400 support

Marek Vasut marex at denx.de
Wed Aug 29 10:35:05 UTC 2018


On 08/29/2018 07:32 AM, Peng Fan wrote:
> Hi,

Hi,

> Would anyone pick up this patchset? Tom, I delegated the patchset to you, would you mind pick it up? 

I've been nagging Tom about this for a while , he said he will pick it
for next release, but having it in this one would be IMO fine, since it
doesn't interfere with anything and it's been posted way before the RC
cycle started.

> Thanks,
> Peng.
> 
> -----Original Message-----
> From: Peng Fan 
> Sent: 2018年8月10日 14:08
> To: jh80.chung at samsung.com; sbabic at denx.de
> Cc: u-boot at lists.denx.de; dl-linux-imx <linux-imx at nxp.com>; Peng Fan <peng.fan at nxp.com>; Jean-Jacques Hiblot <jjhiblot at ti.com>; Kishon Vijay Abraham I <kishon at ti.com>; Faiz Abbas <faiz_abbas at ti.com>; Marek Vasut <marex at denx.de>
> Subject: [PATCH V4 1/2] mmc: add HS400 support
> 
> Add HS400 support.
> Selecting HS400 needs first select HS200 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.
> 
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> Cc: Jaehoon Chung <jh80.chung at samsung.com>
> Cc: Jean-Jacques Hiblot <jjhiblot at ti.com>
> Cc: Stefano Babic <sbabic at denx.de>
> Cc: Kishon Vijay Abraham I <kishon at ti.com>
> Cc: Faiz Abbas <faiz_abbas at ti.com>
> Cc: Marek Vasut <marex at denx.de>
> ---
> 
> V4:
>  Add SPL_MMC_HS400_SUPPORT Kconfig entry  typo fix, HS199->HS200 in commit log.
> 
> V3:
>  Simplify code
>  add error msg
> 
> V2:
>  remove 4bits support from HS400, as HS400 does not support 4bits per spec.
> 
>  drivers/mmc/Kconfig |  13 +++++
>  drivers/mmc/mmc.c   | 137 +++++++++++++++++++++++++++++++++++++++++-----------
>  include/mmc.h       |  11 +++++
>  3 files changed, 134 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 377b1c4b3b..1616022b91 100644
> --- a/drivers/mmc/Kconfig
> +++ b/drivers/mmc/Kconfig
> @@ -111,6 +111,19 @@ 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 SPL_MMC_HS400_SUPPORT
> +	bool "enable HS400 support in SPL"
> +	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
> diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index ad429f49c9..585951cd78 100644
> --- a/drivers/mmc/mmc.c
> +++ b/drivers/mmc/mmc.c
> @@ -147,6 +147,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)
> @@ -171,6 +172,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)
> @@ -769,6 +771,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;
> @@ -816,7 +823,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)
> @@ -824,6 +831,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) @@ -1734,10 +1747,13 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
>  	u32 card_mask = 0;
>  
>  	switch (mode) {
> +	case MMC_HS_400:
>  	case MMC_HS_200:
> -		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
> +		if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V |
> +		    EXT_CSD_CARD_TYPE_HS400_1_8V))
>  			card_mask |= MMC_SIGNAL_VOLTAGE_180;
> -		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
> +		if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
> +		    EXT_CSD_CARD_TYPE_HS400_1_2V))
>  			card_mask |= MMC_SIGNAL_VOLTAGE_120;
>  		break;
>  	case MMC_DDR_52:
> @@ -1773,6 +1789,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,
> +		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
> +	},
> +#endif
>  #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
>  	{
>  		.mode = MMC_HS_200,
> @@ -1816,6 +1839,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)
> +		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);\ @@ -1869,37 +1940,49 @@ 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) {
> +				err = mmc_select_hs400(mmc);
> +				if (err) {
> +					printf("Select HS400 failed %d\n", 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, MMC_CLK_ENABLE);
> +				/*
> +				 * 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,
> +					      MMC_CLK_ENABLE);
>  #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);
> diff --git a/include/mmc.h b/include/mmc.h index df4255b828..9b9cbedadc 100644
> --- a/include/mmc.h
> +++ b/include/mmc.h
> @@ -64,6 +64,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)
> @@ -248,6 +249,10 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
>  						/* SDR mode @1.2V I/O */
>  #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 */
> @@ -259,6 +264,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)
> @@ -519,6 +525,7 @@ enum bus_mode {
>  	UHS_DDR50,
>  	UHS_SDR104,
>  	MMC_HS_200,
> +	MMC_HS_400,
>  	MMC_MODES_END
>  };
>  
> @@ -532,6 +539,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;
> --
> 2.14.1
> 


-- 
Best regards,
Marek Vasut


More information about the U-Boot mailing list