summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorYe Li <ye.li@nxp.com>2017-09-20 04:22:40 -0500
committerYe Li <ye.li@nxp.com>2017-09-21 20:39:31 -0500
commit0d224a38f12ee6d01c6aa09df7700645ba0c7eae (patch)
tree3eff8bbbb2bb99573a19433de43a5f0bb92b962f /drivers
parentaa49bce19a5aa71a98756f30d9b5da130fdae496 (diff)
MLK-16499-1 mmc: Add support for HS400
The HS400 ES (Enhanced Strobe) has been added. This patch addes support for HS400 for eMMC 5.0 devices. It needs tuning at HS200 to synchronize command response. Signed-off-by: Ye Li <ye.li@nxp.com> Reviewed-by: Peng Fan <peng.fan@nxp.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/mmc.c56
1 files changed, 55 insertions, 1 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index f659751948..a0c804e4b5 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -779,6 +779,12 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
case MMC_HS_200:
speed_bits = EXT_CSD_TIMING_HS200;
break;
+ case MMC_HS_400:
+ speed_bits = EXT_CSD_TIMING_HS400;
+ break;
+ case MMC_HS_400_ES:
+ speed_bits = EXT_CSD_TIMING_HS400;
+ break;
case MMC_LEGACY:
speed_bits = EXT_CSD_TIMING_LEGACY;
break;
@@ -1659,6 +1665,11 @@ static const struct mode_width_tuning mmc_modes_by_pref[] = {
.widths = MMC_MODE_8BIT,
},
{
+ .mode = MMC_HS_400,
+ .widths = MMC_MODE_8BIT,
+ .tuning = MMC_SEND_TUNING_BLOCK_HS200
+ },
+ {
.mode = MMC_HS_200,
.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
.tuning = MMC_SEND_TUNING_BLOCK_HS200
@@ -1737,6 +1748,45 @@ static int mmc_select_hs400es(struct mmc *mmc)
return 0;
}
+static int mmc_select_hs400(struct mmc *mmc)
+{
+ int err;
+
+ /* Set timing to HS200 for tuning */
+ err = mmc_set_card_speed(mmc, MMC_HS_200);
+ if (err)
+ return err;
+
+ /* configure the bus mode (host) */
+ mmc_select_mode(mmc, MMC_HS_200);
+ mmc_set_clock(mmc, mmc->tran_speed, false);
+
+ /* execute tuning if needed */
+ err = mmc_execute_tuning(mmc, MMC_SEND_TUNING_BLOCK_HS200);
+ if (err) {
+ debug("tuning failed\n");
+ return err;
+ }
+
+ /* Set back to HS */
+ mmc_set_card_speed(mmc, MMC_HS);
+ mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
+
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR);
+ if (err)
+ return err;
+
+ err = mmc_set_card_speed(mmc, MMC_HS_400);
+ if (err)
+ return err;
+
+ mmc_select_mode(mmc, MMC_HS_400);
+ mmc_set_clock(mmc, mmc->tran_speed, false);
+
+ return 0;
+}
+
static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
{
int err;
@@ -1775,7 +1825,11 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
goto error;
mmc_set_bus_width(mmc, bus_width(ecbw->cap));
- if (mwt->mode == MMC_HS_400_ES) {
+ if (mwt->mode == MMC_HS_400) {
+ 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;