mmc: support hs400 enhanced strobe mode
eMMC 5.1+ supports HS400 Enhances Strobe mode without the need for tuning procedure. The flow is as following: - set HS_TIMIMG (Highspeed) - Host change freq to <= 52Mhz - set the bus width to Enhanced strobe and DDR8Bit(CMD6), EXT_CSD[183] = 0x86 instead of 0x80 - set HS_TIMING to 0x3 (HS400) - Host change freq to <= 200Mhz - Host select HS400 enhanced strobe complete Signed-off-by: Peng Fan <peng.fan@nxp.com>
This commit is contained in:
parent
8277171663
commit
44acd49248
|
@ -135,6 +135,18 @@ 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 SPL_MMC_HS400_ES_SUPPORT
|
||||
bool "enable HS400 Enhanced Strobe support in SPL"
|
||||
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
|
||||
|
|
|
@ -105,6 +105,23 @@ int mmc_execute_tuning(struct mmc *mmc, uint opcode)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
|
||||
int dm_mmc_set_enhanced_strobe(struct udevice *dev)
|
||||
{
|
||||
struct dm_mmc_ops *ops = mmc_get_ops(dev);
|
||||
|
||||
if (ops->set_enhanced_strobe)
|
||||
return ops->set_enhanced_strobe(dev);
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
int mmc_set_enhanced_strobe(struct mmc *mmc)
|
||||
{
|
||||
return dm_mmc_set_enhanced_strobe(mmc->dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg)
|
||||
{
|
||||
int val;
|
||||
|
|
|
@ -148,6 +148,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)
|
||||
|
@ -173,6 +174,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)
|
||||
|
@ -838,6 +840,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;
|
||||
|
@ -909,7 +916,8 @@ 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;
|
||||
|
@ -923,6 +931,13 @@ 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;
|
||||
}
|
||||
#endif
|
||||
|
@ -1799,6 +1814,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:
|
||||
case MMC_HS_200:
|
||||
if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V |
|
||||
|
@ -1841,6 +1857,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,
|
||||
|
@ -1938,6 +1960,47 @@ static int mmc_select_hs400(struct mmc *mmc)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
|
||||
#if !CONFIG_IS_ENABLED(DM_MMC)
|
||||
static int mmc_set_enhanced_strobe(struct mmc *mmc)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
#endif
|
||||
static int mmc_select_hs400es(struct mmc *mmc)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mmc_set_card_speed(mmc, MMC_HS, true);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
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_set_card_speed(mmc, MMC_HS_400_ES, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mmc_select_mode(mmc, MMC_HS_400_ES);
|
||||
err = mmc_set_clock(mmc, mmc->tran_speed, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return mmc_set_enhanced_strobe(mmc);
|
||||
}
|
||||
#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);\
|
||||
|
@ -2016,6 +2079,13 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
|
|||
printf("Select HS400 failed %d\n", err);
|
||||
goto error;
|
||||
}
|
||||
} else if (mwt->mode == MMC_HS_400_ES) {
|
||||
err = mmc_select_hs400es(mmc);
|
||||
if (err) {
|
||||
printf("Select HS400ES failed %d\n",
|
||||
err);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
/* configure the bus speed (card) */
|
||||
err = mmc_set_card_speed(mmc, mwt->mode, false);
|
||||
|
|
|
@ -65,6 +65,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_CAP_NONREMOVABLE BIT(14)
|
||||
#define MMC_CAP_NEEDS_POLL BIT(15)
|
||||
|
@ -223,6 +224,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 */
|
||||
|
@ -266,11 +268,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 BIT(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)
|
||||
|
@ -457,6 +461,11 @@ struct dm_mmc_ops {
|
|||
* @return 0 if dat0 is in the target state, -ve on error
|
||||
*/
|
||||
int (*wait_dat0)(struct udevice *dev, int state, int timeout);
|
||||
|
||||
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
|
||||
/* set_enhanced_strobe() - set HS400 enhanced strobe */
|
||||
int (*set_enhanced_strobe)(struct udevice *dev);
|
||||
#endif
|
||||
};
|
||||
|
||||
#define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops)
|
||||
|
@ -475,6 +484,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);
|
||||
int mmc_set_enhanced_strobe(struct mmc *mmc);
|
||||
|
||||
#else
|
||||
struct mmc_ops {
|
||||
|
@ -520,6 +530,7 @@ enum bus_mode {
|
|||
UHS_SDR104,
|
||||
MMC_HS_200,
|
||||
MMC_HS_400,
|
||||
MMC_HS_400_ES,
|
||||
MMC_MODES_END
|
||||
};
|
||||
|
||||
|
@ -537,6 +548,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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user