summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorYe Li <ye.li@nxp.com>2018-04-19 02:18:17 -0700
committerYe Li <ye.li@nxp.com>2018-04-27 06:14:45 -0700
commit0972a7219faefcae27e7c39a9c84f46145148913 (patch)
treeb60ed6e104d8f5e61d0619bd41ec15a9753f8620 /drivers/mmc
parentd39cfdeb0e156e135533bc12df275cfd3c4de0b2 (diff)
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>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/Kconfig6
-rw-r--r--drivers/mmc/mmc-uclass.c15
-rw-r--r--drivers/mmc/mmc.c74
3 files changed, 94 insertions, 1 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index e9be18b333f..c4df67d511d 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -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
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index a3536b15ae6..cf628a8b254 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -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;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index eef229c8b4b..4a80f556a0b 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -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)
@@ -798,6 +800,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
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;
break;
@@ -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);