Hi, On 03/05/2018 06:11 PM, Peng Fan wrote: > Add HS400 support. > Selecting HS400 needs first select HS199 according to spec, so use > a dedicated function for HS400. > Add HS400 related macros. > Remove the restriction of only using the low 6 bits of > EXT_CSD_CARD_TYPE, using all the 8 bits.
Sorry for late. > > Signed-off-by: Peng Fan <[email protected]> > Cc: Jaehoon Chung <[email protected]> > Cc: Jean-Jacques Hiblot <[email protected]> > Cc: Stefano Babic <[email protected]> > Cc: Simon Glass <[email protected]> > Cc: Kishon Vijay Abraham I <[email protected]> > Cc: Bin Meng <[email protected]> > --- > drivers/mmc/Kconfig | 7 +++ > drivers/mmc/mmc.c | 133 > ++++++++++++++++++++++++++++++++++++++++++---------- > include/mmc.h | 12 +++++ > 3 files changed, 127 insertions(+), 25 deletions(-) > > diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig > index 5f67e336db..e9be18b333 100644 > --- a/drivers/mmc/Kconfig > +++ b/drivers/mmc/Kconfig > @@ -104,6 +104,13 @@ config SPL_MMC_UHS_SUPPORT > cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus > frequency can go up to 208MHz (SDR104) > > +config MMC_HS400_SUPPORT > + bool "enable HS400 support" > + select MMC_HS200_SUPPORT > + help > + The HS400 mode is support by some eMMC. The bus frequency is up to > + 200MHz. This mode requires tuning the IO. > + > config MMC_HS200_SUPPORT > bool "enable HS200 support" > help > diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c > index 92ea78b8af..eef229c8b4 100644 > --- a/drivers/mmc/mmc.c > +++ b/drivers/mmc/mmc.c > @@ -169,6 +169,7 @@ const char *mmc_mode_name(enum bus_mode mode) > [MMC_HS_52] = "MMC High Speed (52MHz)", > [MMC_DDR_52] = "MMC DDR52 (52MHz)", > [MMC_HS_200] = "HS200 (200MHz)", > + [MMC_HS_400] = "HS400 (200MHz)", > }; > > if (mode >= MMC_MODES_END) > @@ -193,6 +194,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode > mode) > [UHS_DDR50] = 50000000, > [UHS_SDR104] = 208000000, > [MMC_HS_200] = 200000000, > + [MMC_HS_400] = 200000000, > }; > > if (mode == MMC_LEGACY) > @@ -790,6 +792,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum > bus_mode mode) > case MMC_HS_200: > speed_bits = EXT_CSD_TIMING_HS200; > break; > +#endif > +#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) > + case MMC_HS_400: > + speed_bits = EXT_CSD_TIMING_HS400; > + break;> #endif > case MMC_LEGACY: > speed_bits = EXT_CSD_TIMING_LEGACY; > @@ -837,7 +844,7 @@ static int mmc_get_capabilities(struct mmc *mmc) > > mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; > > - cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f; > + cardtype = ext_csd[EXT_CSD_CARD_TYPE]; > mmc->cardtype = cardtype; > > #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) > @@ -845,6 +852,12 @@ static int mmc_get_capabilities(struct mmc *mmc) > EXT_CSD_CARD_TYPE_HS200_1_8V)) { > mmc->card_caps |= MMC_MODE_HS200; > } > +#endif > +#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) > + if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V | > + EXT_CSD_CARD_TYPE_HS400_1_8V)) { > + mmc->card_caps |= MMC_MODE_HS400; > + } > #endif > if (cardtype & EXT_CSD_CARD_TYPE_52) { > if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) > @@ -1748,6 +1761,12 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, > enum bus_mode mode, > u32 card_mask = 0; > > switch (mode) { > + case MMC_HS_400: > + if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_8V) > + card_mask |= MMC_SIGNAL_VOLTAGE_180; > + if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_2V) > + card_mask |= MMC_SIGNAL_VOLTAGE_120; > + break; I think that it's possible to use the below. case MMS_HS_400: case MMC_HS_200: if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V | EXT_CSD_CARD_TYPE_HS400_1_8V) .... Isn't it? > case MMC_HS_200: > if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V) > card_mask |= MMC_SIGNAL_VOLTAGE_180; > @@ -1787,6 +1806,13 @@ static inline int mmc_set_lowest_voltage(struct mmc > *mmc, enum bus_mode mode, > #endif > > static const struct mode_width_tuning mmc_modes_by_pref[] = { > +#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) > + { > + .mode = MMC_HS_400, > + .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 4BIT? As i know, HS400 mode doesn't support the 4BIT mode. > + .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 > + }, > +#endif > #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) > { > .mode = MMC_HS_200, > @@ -1830,6 +1856,54 @@ static const struct ext_csd_bus_width { > {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, > }; > > +#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) > +static int mmc_select_hs400(struct mmc *mmc) > +{ > + int err; > + > + /* Set timing to HS200 for tuning */ > + err = mmc_set_card_speed(mmc, MMC_HS_200); > + if (err) > + return err; > + > + /* configure the bus mode (host) */ > + mmc_select_mode(mmc, MMC_HS_200); > + mmc_set_clock(mmc, mmc->tran_speed, false); > + > + /* execute tuning if needed */ > + err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200); > + if (err) { > + debug("tuning failed\n"); > + return err; > + } > + > + /* Set back to HS */ > + mmc_set_card_speed(mmc, MMC_HS); > + mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false); > + > + err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, > + EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG); > + if (err) > + return err; > + > + err = mmc_set_card_speed(mmc, MMC_HS_400); > + if (err) > + return err; > + > + mmc_select_mode(mmc, MMC_HS_400); > + err = mmc_set_clock(mmc, mmc->tran_speed, false); > + if (err) > + return err; Hmm. I didn't test this patch.. but i guess if it's failed, isn't it possible to use the other bus mode? > + > + return 0; > +} > +#else > +static int mmc_select_hs400(struct mmc *mmc) > +{ > + return -ENOTSUPP; > +} > +#endif > + > #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);\ > @@ -1883,37 +1957,46 @@ static int mmc_select_mode_and_width(struct mmc *mmc, > uint card_caps) > goto error; > mmc_set_bus_width(mmc, bus_width(ecbw->cap)); > > - /* 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_FLAG) { > - err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, > - EXT_CSD_BUS_WIDTH, > - ecbw->ext_csd_bits); > + if (mwt->mode == MMC_HS_400) { > + err = mmc_select_hs400(mmc); doesn't need to add some error message? It's useful to notice to user. > + if (err) > + goto error; > + } else { > + /* configure the bus speed (card) */ > + err = mmc_set_card_speed(mmc, mwt->mode); > if (err) > goto error; > - } > > - /* configure the bus mode (host) */ > - mmc_select_mode(mmc, mwt->mode); > - mmc_set_clock(mmc, mmc->tran_speed, false); > + /* > + * 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_FLAG) { > + err = mmc_switch(mmc, > + EXT_CSD_CMD_SET_NORMAL, > + EXT_CSD_BUS_WIDTH, > + ecbw->ext_csd_bits); > + if (err) > + goto error; > + } > + > + /* configure the bus mode (host) */ > + mmc_select_mode(mmc, mwt->mode); > + mmc_set_clock(mmc, mmc->tran_speed, false); > #ifdef MMC_SUPPORTS_TUNING > > - /* execute tuning if needed */ > - if (mwt->tuning) { > - err = mmc_execute_tuning(mmc, mwt->tuning); > - if (err) { > - pr_debug("tuning failed\n"); > - goto error; > + /* execute tuning if needed */ > + if (mwt->tuning) { > + err = mmc_execute_tuning(mmc, > + mwt->tuning); > + if (err) { > + pr_debug("tuning failed\n"); > + goto error; > + } > } > - } > #endif > + } > > /* do a transfer to check the configuration */ > err = mmc_read_and_compare_ext_csd(mmc); > diff --git a/include/mmc.h b/include/mmc.h > index 86f885b504..8c01c6a530 100644 > --- a/include/mmc.h > +++ b/include/mmc.h > @@ -65,6 +65,7 @@ > #define MMC_MODE_HS_52MHz MMC_CAP(MMC_HS_52) > #define MMC_MODE_DDR_52MHz MMC_CAP(MMC_DDR_52) > #define MMC_MODE_HS200 MMC_CAP(MMC_HS_200) > +#define MMC_MODE_HS400 MMC_CAP(MMC_HS_400) > > #define MMC_MODE_8BIT BIT(30) > #define MMC_MODE_4BIT BIT(29) > @@ -250,6 +251,11 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) > #define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | > \ > EXT_CSD_CARD_TYPE_HS200_1_2V) > > +#define EXT_CSD_CARD_TYPE_HS400_1_8V BIT(6) > +#define EXT_CSD_CARD_TYPE_HS400_1_2V BIT(7) > +#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | > \ > + EXT_CSD_CARD_TYPE_HS400_1_2V) > + > #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 */ > @@ -260,6 +266,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) > #define EXT_CSD_TIMING_LEGACY 0 /* no high speed */ > #define EXT_CSD_TIMING_HS 1 /* HS */ > #define EXT_CSD_TIMING_HS200 2 /* HS200 */ > +#define EXT_CSD_TIMING_HS400 3 /* HS400 */ > > #define EXT_CSD_BOOT_ACK_ENABLE (1 << 6) > #define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3) > @@ -520,6 +527,7 @@ enum bus_mode { > UHS_DDR50, > UHS_SDR104, > MMC_HS_200, > + MMC_HS_400, > MMC_MODES_END > }; > > @@ -533,6 +541,10 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode) > #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) > else if (mode == UHS_DDR50) > return true; > +#endif > +#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) > + else if (mode == MMC_HS_400) > + return true; > #endif > else > return false; > _______________________________________________ U-Boot mailing list [email protected] https://lists.denx.de/listinfo/u-boot

