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 <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? > 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(). >>> >> > > > > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot