MLK-18161-15 mmc: Add HS400 Enhanced Strobe mode support

The eMMC 5.1 supports the HS400 Enhanced Strobe mode, add this
support to mmc.

Signed-off-by: Ye Li <ye.li@nxp.com>
This commit is contained in:
Ye Li 2018-04-19 02:18:17 -07:00
parent d39cfdeb0e
commit 0972a7219f
4 changed files with 109 additions and 1 deletions

View File

@ -104,6 +104,12 @@ 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_ES_SUPPORT
bool "enable HS400 Enhanced Strobe support"
help
The HS400 Enhanced Strobe mode is support by some eMMC. The bus frequency is up to
200MHz. This mode does not tune the IO.
config MMC_HS400_SUPPORT
bool "enable HS400 support"
select MMC_HS200_SUPPORT

View File

@ -123,6 +123,21 @@ int mmc_execute_tuning(struct mmc *mmc, uint opcode)
}
#endif
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
void dm_mmc_set_enhanced_strobe(struct udevice *dev)
{
struct dm_mmc_ops *ops = mmc_get_ops(dev);
if (ops->set_enhanced_strobe)
ops->set_enhanced_strobe(dev);
}
void mmc_set_enhanced_strobe(struct mmc *mmc)
{
dm_mmc_set_enhanced_strobe(mmc->dev);
}
#endif
int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg)
{
int val;

View File

@ -170,6 +170,7 @@ const char *mmc_mode_name(enum bus_mode mode)
[MMC_DDR_52] = "MMC DDR52 (52MHz)",
[MMC_HS_200] = "HS200 (200MHz)",
[MMC_HS_400] = "HS400 (200MHz)",
[MMC_HS_400_ES] = "HS400ES (200MHz)",
};
if (mode >= MMC_MODES_END)
@ -195,6 +196,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
[UHS_SDR104] = 208000000,
[MMC_HS_200] = 200000000,
[MMC_HS_400] = 200000000,
[MMC_HS_400_ES] = 200000000,
};
if (mode == MMC_LEGACY)
@ -797,6 +799,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
case MMC_HS_400:
speed_bits = EXT_CSD_TIMING_HS400;
break;
#endif
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
case MMC_HS_400_ES:
speed_bits = EXT_CSD_TIMING_HS400;
break;
#endif
case MMC_LEGACY:
speed_bits = EXT_CSD_TIMING_LEGACY;
@ -853,7 +860,7 @@ static int mmc_get_capabilities(struct mmc *mmc)
mmc->card_caps |= MMC_MODE_HS200;
}
#endif
#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
#if (CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) || CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT))
if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V |
EXT_CSD_CARD_TYPE_HS400_1_8V)) {
mmc->card_caps |= MMC_MODE_HS400;
@ -867,6 +874,11 @@ static int mmc_get_capabilities(struct mmc *mmc)
if (cardtype & EXT_CSD_CARD_TYPE_26)
mmc->card_caps |= MMC_MODE_HS;
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
if (ext_csd[EXT_CSD_STROBE_SUPPORT] && (mmc->card_caps & MMC_MODE_HS400))
mmc->card_caps |= MMC_MODE_HS400_ES;
#endif
return 0;
}
@ -1761,6 +1773,7 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
u32 card_mask = 0;
switch (mode) {
case MMC_HS_400_ES:
case MMC_HS_400:
if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS400_1_8V)
card_mask |= MMC_SIGNAL_VOLTAGE_180;
@ -1806,6 +1819,12 @@ 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_ES_SUPPORT)
{
.mode = MMC_HS_400_ES,
.widths = MMC_MODE_8BIT,
},
#endif
#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
{
.mode = MMC_HS_400,
@ -1904,6 +1923,55 @@ static int mmc_select_hs400(struct mmc *mmc)
}
#endif
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
#if !CONFIG_IS_ENABLED(DM_MMC)
static void mmc_set_enhanced_strobe(struct mmc *mmc)
{
return;
}
#endif
static int mmc_select_hs400es(struct mmc *mmc)
{
int err;
err = mmc_set_card_speed(mmc, MMC_HS);
if (err)
return err;
/* configure the bus mode (host) */
mmc_select_mode(mmc, MMC_HS);
mmc_set_clock(mmc, mmc->tran_speed, false);
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8 |
EXT_CSD_DDR_FLAG | EXT_CSD_BUS_WIDTH_STROBE);
if (err) {
printf("switch to bus width for hs400 failed\n");
return err;
}
/* TODO: driver strength */
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400 | (0 << EXT_CSD_DRV_STR_SHIFT));
if (err) {
printf("switch to hs400 failed\n");
return err;
}
mmc_select_mode(mmc, MMC_HS_400_ES);
mmc_set_clock(mmc, mmc->tran_speed, false);
mmc_set_enhanced_strobe(mmc);
return 0;
}
#else
static int mmc_select_hs400es(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);\
@ -1961,6 +2029,10 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
err = mmc_select_hs400(mmc);
if (err)
goto error;
} else if (mwt->mode == MMC_HS_400_ES) {
err = mmc_select_hs400es(mmc);
if (err)
goto error;
} else {
/* configure the bus speed (card) */
err = mmc_set_card_speed(mmc, mwt->mode);

View File

@ -66,6 +66,7 @@
#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_HS400_ES MMC_CAP(MMC_HS_400_ES)
#define MMC_MODE_8BIT BIT(30)
#define MMC_MODE_4BIT BIT(29)
@ -220,6 +221,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
#define EXT_CSD_BOOT_BUS_WIDTH 177
#define EXT_CSD_PART_CONF 179 /* R/W */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_STROBE_SUPPORT 184 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
@ -262,11 +264,13 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
#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_FLAG BIT(2) /* Flag for DDR mode */
#define EXT_CSD_BUS_WIDTH_STROBE (1 << 7) /* Enhanced strobe mode */
#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_DRV_STR_SHIFT 4 /* Driver Strength shift */
#define EXT_CSD_BOOT_ACK_ENABLE (1 << 6)
#define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3)
@ -463,6 +467,11 @@ struct dm_mmc_ops {
*/
int (*wait_dat0)(struct udevice *dev, int state, int timeout);
#endif
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
/* set_enhanced_strobe() - set HS400 enhanced strobe */
void (*set_enhanced_strobe)(struct udevice *dev);
#endif
};
#define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops)
@ -483,6 +492,7 @@ int mmc_getcd(struct mmc *mmc);
int mmc_getwp(struct mmc *mmc);
int mmc_execute_tuning(struct mmc *mmc, uint opcode);
int mmc_wait_dat0(struct mmc *mmc, int state, int timeout);
void mmc_set_enhanced_strobe(struct mmc *mmc);
#else
struct mmc_ops {
@ -528,6 +538,7 @@ enum bus_mode {
UHS_SDR104,
MMC_HS_200,
MMC_HS_400,
MMC_HS_400_ES,
MMC_MODES_END
};
@ -545,6 +556,10 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode)
#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
else if (mode == MMC_HS_400)
return true;
#endif
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
else if (mode == MMC_HS_400_ES)
return true;
#endif
else
return false;