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

Jaehoon Chung jh80.chung at samsung.com
Fri May 26 01:12:05 UTC 2017


On 05/25/2017 11:40 PM, Jean-Jacques Hiblot wrote:
> 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

I want to maintain the original flag values..because it's specified value at spec.
Someone can confuse about value 4 when just see this define.
(According to spec, value 4 is reserved.)

Best Regards,
Jaehoon Chung

> 
> 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