[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