mmc: add HS400 support
Add HS400 support. Selecting HS400 needs first select HS200 according to spec, so use a dedicated function for HS400. Add HS400 related macros. Remove the restriction of only using the low 6 bits of EXT_CSD_CARD_TYPE, using all the 8 bits. Signed-off-by: Peng Fan <peng.fan@nxp.com> Cc: Jaehoon Chung <jh80.chung@samsung.com> Cc: Jean-Jacques Hiblot <jjhiblot@ti.com> Cc: Stefano Babic <sbabic@denx.de> Cc: Kishon Vijay Abraham I <kishon@ti.com> Cc: Faiz Abbas <faiz_abbas@ti.com> Cc: Marek Vasut <marex@denx.de> Signed-off-by: Peng Fan <peng.fan@nxp.com>
This commit is contained in:
parent
51330c72f0
commit
3dd2626f48
@ -111,6 +111,19 @@ config SPL_MMC_UHS_SUPPORT
|
|||||||
cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
|
cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
|
||||||
frequency can go up to 208MHz (SDR104)
|
frequency can go up to 208MHz (SDR104)
|
||||||
|
|
||||||
|
config MMC_HS400_SUPPORT
|
||||||
|
bool "enable HS400 support"
|
||||||
|
select MMC_HS200_SUPPORT
|
||||||
|
help
|
||||||
|
The HS400 mode is support by some eMMC. The bus frequency is up to
|
||||||
|
200MHz. This mode requires tuning the IO.
|
||||||
|
|
||||||
|
config SPL_MMC_HS400_SUPPORT
|
||||||
|
bool "enable HS400 support in SPL"
|
||||||
|
help
|
||||||
|
The HS400 mode is support by some eMMC. The bus frequency is up to
|
||||||
|
200MHz. This mode requires tuning the IO.
|
||||||
|
|
||||||
config MMC_HS200_SUPPORT
|
config MMC_HS200_SUPPORT
|
||||||
bool "enable HS200 support"
|
bool "enable HS200 support"
|
||||||
help
|
help
|
||||||
|
@ -147,6 +147,7 @@ const char *mmc_mode_name(enum bus_mode mode)
|
|||||||
[MMC_HS_52] = "MMC High Speed (52MHz)",
|
[MMC_HS_52] = "MMC High Speed (52MHz)",
|
||||||
[MMC_DDR_52] = "MMC DDR52 (52MHz)",
|
[MMC_DDR_52] = "MMC DDR52 (52MHz)",
|
||||||
[MMC_HS_200] = "HS200 (200MHz)",
|
[MMC_HS_200] = "HS200 (200MHz)",
|
||||||
|
[MMC_HS_400] = "HS400 (200MHz)",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mode >= MMC_MODES_END)
|
if (mode >= MMC_MODES_END)
|
||||||
@ -171,6 +172,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
|
|||||||
[UHS_DDR50] = 50000000,
|
[UHS_DDR50] = 50000000,
|
||||||
[UHS_SDR104] = 208000000,
|
[UHS_SDR104] = 208000000,
|
||||||
[MMC_HS_200] = 200000000,
|
[MMC_HS_200] = 200000000,
|
||||||
|
[MMC_HS_400] = 200000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mode == MMC_LEGACY)
|
if (mode == MMC_LEGACY)
|
||||||
@ -769,6 +771,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
|
|||||||
case MMC_HS_200:
|
case MMC_HS_200:
|
||||||
speed_bits = EXT_CSD_TIMING_HS200;
|
speed_bits = EXT_CSD_TIMING_HS200;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
|
||||||
|
case MMC_HS_400:
|
||||||
|
speed_bits = EXT_CSD_TIMING_HS400;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case MMC_LEGACY:
|
case MMC_LEGACY:
|
||||||
speed_bits = EXT_CSD_TIMING_LEGACY;
|
speed_bits = EXT_CSD_TIMING_LEGACY;
|
||||||
@ -816,7 +823,7 @@ static int mmc_get_capabilities(struct mmc *mmc)
|
|||||||
|
|
||||||
mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
|
mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
|
||||||
|
|
||||||
cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
|
cardtype = ext_csd[EXT_CSD_CARD_TYPE];
|
||||||
mmc->cardtype = cardtype;
|
mmc->cardtype = cardtype;
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
|
#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
|
||||||
@ -824,6 +831,12 @@ static int mmc_get_capabilities(struct mmc *mmc)
|
|||||||
EXT_CSD_CARD_TYPE_HS200_1_8V)) {
|
EXT_CSD_CARD_TYPE_HS200_1_8V)) {
|
||||||
mmc->card_caps |= MMC_MODE_HS200;
|
mmc->card_caps |= MMC_MODE_HS200;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
|
||||||
|
if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V |
|
||||||
|
EXT_CSD_CARD_TYPE_HS400_1_8V)) {
|
||||||
|
mmc->card_caps |= MMC_MODE_HS400;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (cardtype & EXT_CSD_CARD_TYPE_52) {
|
if (cardtype & EXT_CSD_CARD_TYPE_52) {
|
||||||
if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
|
if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
|
||||||
@ -1734,10 +1747,13 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
|
|||||||
u32 card_mask = 0;
|
u32 card_mask = 0;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
case MMC_HS_400:
|
||||||
case MMC_HS_200:
|
case MMC_HS_200:
|
||||||
if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
|
if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V |
|
||||||
|
EXT_CSD_CARD_TYPE_HS400_1_8V))
|
||||||
card_mask |= MMC_SIGNAL_VOLTAGE_180;
|
card_mask |= MMC_SIGNAL_VOLTAGE_180;
|
||||||
if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
|
if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
|
||||||
|
EXT_CSD_CARD_TYPE_HS400_1_2V))
|
||||||
card_mask |= MMC_SIGNAL_VOLTAGE_120;
|
card_mask |= MMC_SIGNAL_VOLTAGE_120;
|
||||||
break;
|
break;
|
||||||
case MMC_DDR_52:
|
case MMC_DDR_52:
|
||||||
@ -1773,6 +1789,13 @@ static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const struct mode_width_tuning mmc_modes_by_pref[] = {
|
static const struct mode_width_tuning mmc_modes_by_pref[] = {
|
||||||
|
#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
|
||||||
|
{
|
||||||
|
.mode = MMC_HS_400,
|
||||||
|
.widths = MMC_MODE_8BIT,
|
||||||
|
.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
|
||||||
|
},
|
||||||
|
#endif
|
||||||
#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
|
#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
|
||||||
{
|
{
|
||||||
.mode = MMC_HS_200,
|
.mode = MMC_HS_200,
|
||||||
@ -1816,6 +1839,54 @@ static const struct ext_csd_bus_width {
|
|||||||
{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
|
{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
|
||||||
|
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_CMD_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_FLAG);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = mmc_set_card_speed(mmc, MMC_HS_400);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
mmc_select_mode(mmc, MMC_HS_400);
|
||||||
|
err = mmc_set_clock(mmc, mmc->tran_speed, false);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int mmc_select_hs400(struct mmc *mmc)
|
||||||
|
{
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#define for_each_supported_width(caps, ddr, ecbv) \
|
#define for_each_supported_width(caps, ddr, ecbv) \
|
||||||
for (ecbv = ext_csd_bus_width;\
|
for (ecbv = ext_csd_bus_width;\
|
||||||
ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
|
ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
|
||||||
@ -1869,37 +1940,49 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
|
|||||||
goto error;
|
goto error;
|
||||||
mmc_set_bus_width(mmc, bus_width(ecbw->cap));
|
mmc_set_bus_width(mmc, bus_width(ecbw->cap));
|
||||||
|
|
||||||
/* configure the bus speed (card) */
|
if (mwt->mode == MMC_HS_400) {
|
||||||
err = mmc_set_card_speed(mmc, mwt->mode);
|
err = mmc_select_hs400(mmc);
|
||||||
if (err)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* configure the bus width AND the ddr mode (card)
|
|
||||||
* The host side will be taken care of in the next step
|
|
||||||
*/
|
|
||||||
if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
|
|
||||||
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
|
|
||||||
EXT_CSD_BUS_WIDTH,
|
|
||||||
ecbw->ext_csd_bits);
|
|
||||||
if (err)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* configure the bus mode (host) */
|
|
||||||
mmc_select_mode(mmc, mwt->mode);
|
|
||||||
mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE);
|
|
||||||
#ifdef MMC_SUPPORTS_TUNING
|
|
||||||
|
|
||||||
/* execute tuning if needed */
|
|
||||||
if (mwt->tuning) {
|
|
||||||
err = mmc_execute_tuning(mmc, mwt->tuning);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_debug("tuning failed\n");
|
printf("Select HS400 failed %d\n", err);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
/* configure the bus speed (card) */
|
||||||
|
err = mmc_set_card_speed(mmc, mwt->mode);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* configure the bus width AND the ddr mode
|
||||||
|
* (card). The host side will be taken care
|
||||||
|
* of in the next step
|
||||||
|
*/
|
||||||
|
if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
|
||||||
|
err = mmc_switch(mmc,
|
||||||
|
EXT_CSD_CMD_SET_NORMAL,
|
||||||
|
EXT_CSD_BUS_WIDTH,
|
||||||
|
ecbw->ext_csd_bits);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* configure the bus mode (host) */
|
||||||
|
mmc_select_mode(mmc, mwt->mode);
|
||||||
|
mmc_set_clock(mmc, mmc->tran_speed,
|
||||||
|
MMC_CLK_ENABLE);
|
||||||
|
#ifdef MMC_SUPPORTS_TUNING
|
||||||
|
|
||||||
|
/* execute tuning if needed */
|
||||||
|
if (mwt->tuning) {
|
||||||
|
err = mmc_execute_tuning(mmc,
|
||||||
|
mwt->tuning);
|
||||||
|
if (err) {
|
||||||
|
pr_debug("tuning failed\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* do a transfer to check the configuration */
|
/* do a transfer to check the configuration */
|
||||||
err = mmc_read_and_compare_ext_csd(mmc);
|
err = mmc_read_and_compare_ext_csd(mmc);
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
#define MMC_MODE_HS_52MHz MMC_CAP(MMC_HS_52)
|
#define MMC_MODE_HS_52MHz MMC_CAP(MMC_HS_52)
|
||||||
#define MMC_MODE_DDR_52MHz MMC_CAP(MMC_DDR_52)
|
#define MMC_MODE_DDR_52MHz MMC_CAP(MMC_DDR_52)
|
||||||
#define MMC_MODE_HS200 MMC_CAP(MMC_HS_200)
|
#define MMC_MODE_HS200 MMC_CAP(MMC_HS_200)
|
||||||
|
#define MMC_MODE_HS400 MMC_CAP(MMC_HS_400)
|
||||||
|
|
||||||
#define MMC_MODE_8BIT BIT(30)
|
#define MMC_MODE_8BIT BIT(30)
|
||||||
#define MMC_MODE_4BIT BIT(29)
|
#define MMC_MODE_4BIT BIT(29)
|
||||||
@ -248,6 +249,10 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
|
|||||||
/* SDR mode @1.2V I/O */
|
/* SDR mode @1.2V I/O */
|
||||||
#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
|
#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
|
||||||
EXT_CSD_CARD_TYPE_HS200_1_2V)
|
EXT_CSD_CARD_TYPE_HS200_1_2V)
|
||||||
|
#define EXT_CSD_CARD_TYPE_HS400_1_8V BIT(6)
|
||||||
|
#define EXT_CSD_CARD_TYPE_HS400_1_2V BIT(7)
|
||||||
|
#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \
|
||||||
|
EXT_CSD_CARD_TYPE_HS400_1_2V)
|
||||||
|
|
||||||
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
|
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
|
||||||
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
|
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
|
||||||
@ -259,6 +264,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
|
|||||||
#define EXT_CSD_TIMING_LEGACY 0 /* no high speed */
|
#define EXT_CSD_TIMING_LEGACY 0 /* no high speed */
|
||||||
#define EXT_CSD_TIMING_HS 1 /* HS */
|
#define EXT_CSD_TIMING_HS 1 /* HS */
|
||||||
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
|
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
|
||||||
|
#define EXT_CSD_TIMING_HS400 3 /* HS400 */
|
||||||
|
|
||||||
#define EXT_CSD_BOOT_ACK_ENABLE (1 << 6)
|
#define EXT_CSD_BOOT_ACK_ENABLE (1 << 6)
|
||||||
#define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3)
|
#define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3)
|
||||||
@ -519,6 +525,7 @@ enum bus_mode {
|
|||||||
UHS_DDR50,
|
UHS_DDR50,
|
||||||
UHS_SDR104,
|
UHS_SDR104,
|
||||||
MMC_HS_200,
|
MMC_HS_200,
|
||||||
|
MMC_HS_400,
|
||||||
MMC_MODES_END
|
MMC_MODES_END
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -532,6 +539,10 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode)
|
|||||||
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
|
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
|
||||||
else if (mode == UHS_DDR50)
|
else if (mode == UHS_DDR50)
|
||||||
return true;
|
return true;
|
||||||
|
#endif
|
||||||
|
#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
|
||||||
|
else if (mode == MMC_HS_400)
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user