summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZiyuan Xu <xzy.xu@rock-chips.com>2017-05-15 09:07:25 +0300
committerKever Yang <kever.yang@rock-chips.com>2017-07-18 17:08:31 +0300
commitd6c8dc9aa2caef539109d6ea4a3918269977008a (patch)
tree6fce0bb0ad248a1ca00ad1d2e1aa07c78d14c4ab
parent482e448330733534f42a58b75770c4dd23d3b5be (diff)
downloadu-boot-d6c8dc9aa2caef539109d6ea4a3918269977008a.tar.xz
mmc: add support for HS400 mode of eMMC5.0
This patch adds HS400 mode support for eMMC5.0 device. HS400 mode is high speed DDR interface timing from HS200. Clock frequency is up to 200MHz and only 8-bit bus width is supported. In addition, tuning process of HS200 is required to synchronize the command response on the CMD line because CMD input timing for HS400 mode is the same as HS200 mode. Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
-rw-r--r--drivers/mmc/mmc.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index c5bb334725..3261a1242e 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -855,6 +855,45 @@ static int mmc_select_hs200(struct mmc *mmc)
}
#endif
+static int mmc_select_hs400(struct mmc *mmc)
+{
+ int ret;
+
+ /* Switch card to HS mode */
+ ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false);
+ if (ret)
+ return ret;
+
+ /* Set host controller to HS timing */
+ mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
+
+ /* Reduce frequency to HS frequency */
+ mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR);
+
+ ret = mmc_send_status(mmc, 1000);
+ if (ret)
+ return ret;
+
+ /* Switch card to DDR */
+ ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ EXT_CSD_DDR_BUS_WIDTH_8);
+ if (ret)
+ return ret;
+
+ /* Switch card to HS400 */
+ ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false);
+ if (ret)
+ return ret;
+
+ /* Set host controller to HS400 timing and frequency */
+ mmc_set_timing(mmc, MMC_TIMING_MMC_HS400);
+
+ return ret;
+}
+
static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
{
u8 card_type;
@@ -960,9 +999,14 @@ static int mmc_change_freq(struct mmc *mmc)
mmc_set_bus_speed(mmc, avail_type);
- if (mmc_card_hs200(mmc))
+ if (mmc_card_hs200(mmc)) {
err = mmc_hs200_tuning(mmc);
- else if (!mmc_card_hs400es(mmc)) {
+ if (avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+ mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
+ err = mmc_select_hs400(mmc);
+ mmc_set_bus_speed(mmc, avail_type);
+ }
+ } else if (!mmc_card_hs400es(mmc)) {
err = mmc_select_bus_width(mmc) > 0 ? 0 : err;
if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52)
err = mmc_select_hs_ddr(mmc);