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 <jjhib...@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?

>  
> +#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().
> 

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to