[U-Boot] [PATCH 10/22] mmc: refactor MMC startup to make it easier to support new modes

Jean-Jacques Hiblot jjhiblot at ti.com
Thu May 25 14:40:33 UTC 2017


Hi,


On 25/05/2017 14:25, Jaehoon Chung wrote:
> On 05/13/2017 03:16 AM, Jean-Jacques Hiblot wrote:
>> The MMC startup process currently handles 4 modes. To make it easier to
>> add support for more modes, let's make the process more generic and use a
>> list of the modes to try.
>> The major functional change is that when a mode fails we try the next one.
>> Not all modes are tried, only those supported by the card and the host.
>>
>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot at ti.com>
>> ---
>>   drivers/mmc/mmc.c | 238 +++++++++++++++++++++++++++++++++---------------------
>>   include/mmc.h     |  15 +++-
>>   2 files changed, 157 insertions(+), 96 deletions(-)
>>
>> diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
>> index f42a0fe..2931871 100644
>> --- a/drivers/mmc/mmc.c
>> +++ b/drivers/mmc/mmc.c
>> @@ -200,6 +200,7 @@ static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
>>   {
>>   	mmc->selected_mode = mode;
>>   	mmc->tran_speed = mmc_mode2freq(mmc, mode);
>> +	mmc->ddr_mode = mmc_is_mode_ddr(mode);
>>   	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
>>   	      mmc->tran_speed / 1000000);
>>   	return 0;
>> @@ -602,11 +603,46 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
>>   
>>   }
>>   
>> -static int mmc_change_freq(struct mmc *mmc)
>> +static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
>>   {
>> -	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
>> -	char cardtype;
>>   	int err;
>> +	int speed_bits;
>> +	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
>> +
>> +	switch (mode) {
>> +	case MMC_HS:
>> +	case MMC_HS_52:
>> +	case MMC_DDR_52:
>> +		  speed_bits = EXT_CSD_TIMING_HS;
>> +	case MMC_LEGACY:
>> +		  speed_bits = EXT_CSD_TIMING_LEGACY;
>> +		  break;
>> +	default:
>> +		  return -EINVAL;
>> +	}
>> +	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
>> +			 speed_bits);
>> +	if (err)
>> +		return err;
>> +
>> +	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
>> +		/* Now check to see that it worked */
>> +		err = mmc_send_ext_csd(mmc, test_csd);
>> +		if (err)
>> +			return err;
>> +
>> +		/* No high-speed support */
>> +		if (!test_csd[EXT_CSD_HS_TIMING])
>> +			return -ENOTSUPP;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int mmc_get_capabilities(struct mmc *mmc)
>> +{
>> +	u8 *ext_csd = mmc->ext_csd;
>> +	char cardtype;
>>   
>>   	mmc->card_caps = MMC_MODE_1BIT;
>>   
>> @@ -617,38 +653,23 @@ static int mmc_change_freq(struct mmc *mmc)
>>   	if (mmc->version < MMC_VERSION_4)
>>   		return 0;
>>   
>> -	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
>> -
>> -	err = mmc_send_ext_csd(mmc, ext_csd);
>> +	if (!ext_csd) {
>> +		error("No ext_csd found!\n"); /* this should enver happen */
>> +		return -ENOTSUPP;
>> +	}
>>   
>> -	if (err)
>> -		return err;
>> +	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
>>   
>>   	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
>>   
>> -	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
>> -
>> -	if (err)
>> -		return err;
>> -
>> -	/* Now check to see that it worked */
>> -	err = mmc_send_ext_csd(mmc, ext_csd);
>> -
>> -	if (err)
>> -		return err;
>> -
>> -	/* No high-speed support */
>> -	if (!ext_csd[EXT_CSD_HS_TIMING])
>> -		return 0;
>> -
>>   	/* High Speed is set, there are two types: 52MHz and 26MHz */
>>   	if (cardtype & EXT_CSD_CARD_TYPE_52) {
>> -		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
>> +		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
>>   			mmc->card_caps |= MMC_MODE_DDR_52MHz;
>> -		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
>> -	} else {
>> -		mmc->card_caps |= MMC_MODE_HS;
>> +		mmc->card_caps |= MMC_MODE_HS_52MHz;
>>   	}
>> +	if (cardtype & EXT_CSD_CARD_TYPE_26)
>> +		mmc->card_caps |= MMC_MODE_HS;
>>   
>>   	return 0;
>>   }
>> @@ -1320,33 +1341,58 @@ static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
>>   }
>>   
>>   
>> -static int mmc_select_bus_freq_width(struct mmc *mmc)
>> +static const struct mode_width_tuning mmc_modes_by_pref[] = {
>> +	{
>> +		.mode = MMC_HS_200,
>> +		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
>> +	},
>> +	{
>> +		.mode = MMC_DDR_52,
>> +		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
>> +	},
>> +	{
>> +		.mode = MMC_HS_52,
>> +		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
>> +	},
>> +	{
>> +		.mode = MMC_HS,
>> +		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
>> +	},
>> +	{
>> +		.mode = MMC_LEGACY,
>> +		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
>> +	}
>> +};
>> +#define for_each_mmc_mode_by_pref(caps, mwt) \
>> +	for (mwt = mmc_modes_by_pref;\
>> +	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
>> +	    mwt++) \
>> +		if (caps & MMC_CAP(mwt->mode))
>> +
>> +static const struct ext_csd_bus_width {
>> +	uint cap;
>> +	bool is_ddr;
>> +	uint ext_csd_bits;
>> +} ext_csd_bus_width[] = {
>> +	{MMC_MODE_8BIT, true, EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR},
>> +	{MMC_MODE_4BIT, true, EXT_CSD_BUS_WIDTH_4 | EXT_CSD_DDR},
>> +	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
>> +	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
>> +	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
>> +};
>> +#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);\
>> +	    ecbv++) \
>> +		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
>> +
>> +static int mmc_select_mode_and_width(struct mmc *mmc)
>>   {
>> -	/* An array of possible bus widths in order of preference */
>> -	static const unsigned ext_csd_bits[] = {
>> -		EXT_CSD_DDR_BUS_WIDTH_8,
>> -		EXT_CSD_DDR_BUS_WIDTH_4,
>> -		EXT_CSD_BUS_WIDTH_8,
>> -		EXT_CSD_BUS_WIDTH_4,
>> -		EXT_CSD_BUS_WIDTH_1,
>> -	};
>> -	/* An array to map CSD bus widths to host cap bits */
>> -	static const unsigned ext_to_hostcaps[] = {
>> -		[EXT_CSD_DDR_BUS_WIDTH_4] =
>> -			MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
>> -		[EXT_CSD_DDR_BUS_WIDTH_8] =
>> -			MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
>> -		[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
>> -		[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
>> -	};
>> -	/* An array to map chosen bus width to an integer */
>> -	static const unsigned widths[] = {
>> -		8, 4, 8, 4, 1,
>> -	};
>>   	int err;
>> -	int idx;
>> +	const struct mode_width_tuning *mwt;
>> +	const struct ext_csd_bus_width *ecbw;
>>   
>> -	err = mmc_change_freq(mmc);
>> +	err = mmc_get_capabilities(mmc);
>>   	if (err)
>>   		return err;
>>   
>> @@ -1357,60 +1403,64 @@ static int mmc_select_bus_freq_width(struct mmc *mmc)
>>   	if (mmc->version < MMC_VERSION_4)
>>   		return 0;
>>   
>> +
>>   	if (!mmc->ext_csd) {
>>   		error("No ext_csd found!\n"); /* this should enver happen */
>>   		return -ENOTSUPP;
>>   	}
>>   
>> -	for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
>> -		unsigned int extw = ext_csd_bits[idx];
>> -		unsigned int caps = ext_to_hostcaps[extw];
>> +	for_each_mmc_mode_by_pref(mmc->card_caps, mwt) {
>> +		for_each_supported_width(mmc->card_caps & mwt->widths,
>> +					 mmc_is_mode_ddr(mwt->mode), ecbw) {
>> +			debug("trying mode %s width %d (at %d MHz)\n",
>> +			      mmc_mode_name(mwt->mode),
>> +			      bus_width(ecbw->cap),
>> +			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
>>   
>> -		/*
>> -		  * If the bus width is still not changed,
>> -		  * don't try to set the default again.
>> -		  * Otherwise, recover from switch attempts
>> -		  * by switching to 1-bit bus width.
>> -		  */
>> -		if (extw == EXT_CSD_BUS_WIDTH_1 &&
>> -		    mmc->bus_width == 1) {
>> -			err = 0;
>> -			break;
>> -		}
>> -
>> -		/*
>> -		  * Check to make sure the card and controller support
>> -		  * these capabilities
>> -		  */
>> -		if ((mmc->card_caps & caps) != caps)
>> -			continue;
>> -
>> -		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
>> -				EXT_CSD_BUS_WIDTH, extw);
>> +			/* configure the bus width (card + host) */
>> +			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
>> +				EXT_CSD_BUS_WIDTH,
>> +				ecbw->ext_csd_bits & ~EXT_CSD_DDR);
>> +			if (err)
>> +				goto error;
>> +			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
>>   
>> -		if (err)
>> -			continue;
>> +			/* 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) {
>> +				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
>> +					EXT_CSD_BUS_WIDTH, ecbw->ext_csd_bits);
>> +				if (err)
>> +					goto error;
>> +			}
>>   
>> -		mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
>> -		mmc_set_bus_width(mmc, widths[idx]);
>> +			/* configure the bus mode (host) */
>> +			mmc_select_mode(mmc, mwt->mode);
>> +			mmc_set_clock(mmc, mmc->tran_speed);
>>   
>> -		err = mmc_read_and_compare_ext_csd(mmc);
>> -		if (!err)
>> -			break;
>> +			/* do a transfer to check the configuration */
>> +			err = mmc_read_and_compare_ext_csd(mmc);
>> +			if (!err)
>> +				return 0;
>> +error:
>> +			/* if an error occured, revert to a safer bus mode */
>> +			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
>> +				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
>> +			mmc_select_mode(mmc, MMC_LEGACY);
>> +			mmc_set_bus_width(mmc, 1);
>> +		}
>>   	}
>>   
>> -	if (err)
>> -		return err;
>> -
>> -	if (mmc->card_caps & MMC_MODE_HS_52MHz) {
>> -		if (mmc->ddr_mode)
>> -			mmc_select_mode(mmc, MMC_DDR_52);
>> -		else
>> -			mmc_select_mode(mmc, MMC_HS_52);
>> -	} else if (mmc->card_caps & MMC_MODE_HS)
>> -		mmc_select_mode(mmc, MMC_HS);
>> +	error("unable to select a mode\n");
>>   
>> -	return err;
>> +	return -ENOTSUPP;
>>   }
>>   
>>   static int mmc_startup_v4(struct mmc *mmc)
>> @@ -1747,7 +1797,7 @@ static int mmc_startup(struct mmc *mmc)
>>   	if (IS_SD(mmc))
>>   		err = sd_select_mode_and_width(mmc);
>>   	else
>> -		err = mmc_select_bus_freq_width(mmc);
>> +		err = mmc_select_mode_and_width(mmc);
>>   
>>   	if (err)
>>   		return err;
>> diff --git a/include/mmc.h b/include/mmc.h
>> index 1ffa7ec..3c6971d 100644
>> --- a/include/mmc.h
>> +++ b/include/mmc.h
>> @@ -213,9 +213,10 @@
>>   #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 */
>> -#define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>> -#define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
>> +#define EXT_CSD_DDR		4	/* Card is in DDR mode */
> Why do you change to 4 as DDR mode?
It's a flag to add to EXT_CSD_BUS_WIDTH_x. for example 
EXT_CSD_BUS_WIDTH_4 | EXT_CSD_DDR = 1 | 4 = 5

JJ
>
>>   
>> +#define EXT_CSD_TIMING_LEGACY	0	/* no high speed */
>> +#define EXT_CSD_TIMING_HS	1	/* HS */
>>   #define EXT_CSD_BOOT_ACK_ENABLE			(1 << 6)
>>   #define EXT_CSD_BOOT_PARTITION_ENABLE		(1 << 3)
>>   #define EXT_CSD_PARTITION_ACCESS_ENABLE		(1 << 0)
>> @@ -424,6 +425,16 @@ enum bus_mode {
>>   
>>   const char *mmc_mode_name(enum bus_mode mode);
>>   void mmc_dump_capabilities(const char *text, uint caps);
>> +
>> +static inline bool mmc_is_mode_ddr(enum bus_mode mode)
>> +{
>> +	if ((mode == MMC_DDR_52) || (mode == UHS_DDR50))
>> +		return true;
>> +	else
>> +		return false;
>> +}
>> +
>> +
>>   /*
>>    * With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device
>>    * with mmc_get_mmc_dev().
>>
>



More information about the U-Boot mailing list