[U-Boot] [PATCH] 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 is actually a resend of https://patchwork.ozlabs.org/patch/1018188/ which got no response. Rebased on master.
drivers/mmc/Kconfig | 12 ++++++++ drivers/mmc/mmc-uclass.c | 15 +++++++++ drivers/mmc/mmc.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++- include/mmc.h | 15 +++++++++ 4 files changed, 120 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 04a4e7716f..3ef7580a43 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -111,6 +111,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 diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index a9c8f335c1..5d04fc6f0a 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -120,6 +120,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; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 456c1b4cc9..1a7194ff73 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -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) @@ -788,6 +790,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; @@ -859,7 +866,8 @@ static int mmc_get_capabilities(struct mmc *mmc) mmc->card_caps |= MMC_MODE_HS200; } #endif -#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) +#if (IS_ENABLED(CONFIG_MMC_HS400_SUPPORT) || \ + IS_ENABLED(CONFIG_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; @@ -873,6 +881,13 @@ static int mmc_get_capabilities(struct mmc *mmc) if (cardtype & EXT_CSD_CARD_TYPE_26) mmc->card_caps |= MMC_MODE_HS;
+#if IS_ENABLED(CONFIG_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 @@ -1778,6 +1793,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 | @@ -1820,6 +1836,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, @@ -1917,6 +1939,54 @@ 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) +{ +} +#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);\ @@ -1988,6 +2058,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); diff --git a/include/mmc.h b/include/mmc.h index 1f30f71d25..0d480b56a9 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -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_MODE_8BIT BIT(30) #define MMC_MODE_4BIT BIT(29) @@ -219,6 +220,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 */ @@ -260,11 +262,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) @@ -461,6 +465,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) @@ -481,6 +490,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 { @@ -526,6 +536,7 @@ enum bus_mode { UHS_SDR104, MMC_HS_200, MMC_HS_400, + MMC_HS_400_ES, MMC_MODES_END };
@@ -543,6 +554,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;

Hi Peng,
On Mon, Apr 15, 2019 at 10:33 PM Peng Fan peng.fan@nxp.com wrote:
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 is actually a resend of https://patchwork.ozlabs.org/patch/1018188/ which got no response. Rebased on master.
drivers/mmc/Kconfig | 12 ++++++++ drivers/mmc/mmc-uclass.c | 15 +++++++++ drivers/mmc/mmc.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++- include/mmc.h | 15 +++++++++ 4 files changed, 120 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 04a4e7716f..3ef7580a43 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -111,6 +111,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.
Is there any board that can select this option?
Otherwise it will be just dead code.
Thanks
participants (2)
-
Fabio Estevam
-
Peng Fan