
Hi,
On 25/05/2017 14:25, Jaehoon Chung wrote:
On 05/13/2017 03:16 AM, Jean-Jacques Hiblot wrote:
The MMC startup process currently handles 4 modes. To make it easier to add support for more modes, let's make the process more generic and use a list of the modes to try. The major functional change is that when a mode fails we try the next one. Not all modes are tried, only those supported by the card and the host.
Signed-off-by: Jean-Jacques Hiblot jjhiblot@ti.com
drivers/mmc/mmc.c | 238 +++++++++++++++++++++++++++++++++--------------------- include/mmc.h | 15 +++- 2 files changed, 157 insertions(+), 96 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index f42a0fe..2931871 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -200,6 +200,7 @@ static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) { mmc->selected_mode = mode; mmc->tran_speed = mmc_mode2freq(mmc, mode);
- mmc->ddr_mode = mmc_is_mode_ddr(mode); debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), mmc->tran_speed / 1000000); return 0;
@@ -602,11 +603,46 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
}
-static int mmc_change_freq(struct mmc *mmc) +static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) {
- ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
- char cardtype; int err;
- int speed_bits;
- ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
- switch (mode) {
- case MMC_HS:
- case MMC_HS_52:
- case MMC_DDR_52:
speed_bits = EXT_CSD_TIMING_HS;
- case MMC_LEGACY:
speed_bits = EXT_CSD_TIMING_LEGACY;
break;
- default:
return -EINVAL;
- }
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
speed_bits);
- if (err)
return err;
- if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
/* Now check to see that it worked */
err = mmc_send_ext_csd(mmc, test_csd);
if (err)
return err;
/* No high-speed support */
if (!test_csd[EXT_CSD_HS_TIMING])
return -ENOTSUPP;
- }
- return 0;
+}
+static int mmc_get_capabilities(struct mmc *mmc) +{
u8 *ext_csd = mmc->ext_csd;
char cardtype;
mmc->card_caps = MMC_MODE_1BIT;
@@ -617,38 +653,23 @@ static int mmc_change_freq(struct mmc *mmc) if (mmc->version < MMC_VERSION_4) return 0;
- mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
- err = mmc_send_ext_csd(mmc, ext_csd);
- if (!ext_csd) {
error("No ext_csd found!\n"); /* this should enver happen */
return -ENOTSUPP;
- }
- if (err)
return err;
mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
- if (err)
return err;
- /* Now check to see that it worked */
- err = mmc_send_ext_csd(mmc, ext_csd);
- if (err)
return err;
- /* No high-speed support */
- if (!ext_csd[EXT_CSD_HS_TIMING])
return 0;
- /* High Speed is set, there are two types: 52MHz and 26MHz */ if (cardtype & EXT_CSD_CARD_TYPE_52) {
if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) mmc->card_caps |= MMC_MODE_DDR_52MHz;
mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
- } else {
mmc->card_caps |= MMC_MODE_HS;
mmc->card_caps |= MMC_MODE_HS_52MHz;
}
if (cardtype & EXT_CSD_CARD_TYPE_26)
mmc->card_caps |= MMC_MODE_HS;
return 0; }
@@ -1320,33 +1341,58 @@ static int mmc_read_and_compare_ext_csd(struct mmc *mmc) }
-static int mmc_select_bus_freq_width(struct mmc *mmc) +static const struct mode_width_tuning mmc_modes_by_pref[] = {
- {
.mode = MMC_HS_200,
.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
- },
- {
.mode = MMC_DDR_52,
.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
- },
- {
.mode = MMC_HS_52,
.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
- },
- {
.mode = MMC_HS,
.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
- },
- {
.mode = MMC_LEGACY,
.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
- }
+}; +#define for_each_mmc_mode_by_pref(caps, mwt) \
- for (mwt = mmc_modes_by_pref;\
mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
mwt++) \
if (caps & MMC_CAP(mwt->mode))
+static const struct ext_csd_bus_width {
- uint cap;
- bool is_ddr;
- uint ext_csd_bits;
+} ext_csd_bus_width[] = {
- {MMC_MODE_8BIT, true, EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR},
- {MMC_MODE_4BIT, true, EXT_CSD_BUS_WIDTH_4 | EXT_CSD_DDR},
- {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
- {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
- {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
+}; +#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);\
ecbv++) \
if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
+static int mmc_select_mode_and_width(struct mmc *mmc) {
- /* An array of possible bus widths in order of preference */
- static const unsigned ext_csd_bits[] = {
EXT_CSD_DDR_BUS_WIDTH_8,
EXT_CSD_DDR_BUS_WIDTH_4,
EXT_CSD_BUS_WIDTH_8,
EXT_CSD_BUS_WIDTH_4,
EXT_CSD_BUS_WIDTH_1,
- };
- /* An array to map CSD bus widths to host cap bits */
- static const unsigned ext_to_hostcaps[] = {
[EXT_CSD_DDR_BUS_WIDTH_4] =
MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
[EXT_CSD_DDR_BUS_WIDTH_8] =
MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
- };
- /* An array to map chosen bus width to an integer */
- static const unsigned widths[] = {
8, 4, 8, 4, 1,
- }; int err;
- int idx;
- const struct mode_width_tuning *mwt;
- const struct ext_csd_bus_width *ecbw;
- err = mmc_change_freq(mmc);
- err = mmc_get_capabilities(mmc); if (err) return err;
@@ -1357,60 +1403,64 @@ static int mmc_select_bus_freq_width(struct mmc *mmc) if (mmc->version < MMC_VERSION_4) return 0;
- if (!mmc->ext_csd) { error("No ext_csd found!\n"); /* this should enver happen */ return -ENOTSUPP; }
- for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
unsigned int extw = ext_csd_bits[idx];
unsigned int caps = ext_to_hostcaps[extw];
- for_each_mmc_mode_by_pref(mmc->card_caps, mwt) {
for_each_supported_width(mmc->card_caps & mwt->widths,
mmc_is_mode_ddr(mwt->mode), ecbw) {
debug("trying mode %s width %d (at %d MHz)\n",
mmc_mode_name(mwt->mode),
bus_width(ecbw->cap),
mmc_mode2freq(mmc, mwt->mode) / 1000000);
/*
* If the bus width is still not changed,
* don't try to set the default again.
* Otherwise, recover from switch attempts
* by switching to 1-bit bus width.
*/
if (extw == EXT_CSD_BUS_WIDTH_1 &&
mmc->bus_width == 1) {
err = 0;
break;
}
/*
* Check to make sure the card and controller support
* these capabilities
*/
if ((mmc->card_caps & caps) != caps)
continue;
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH, extw);
/* configure the bus width (card + host) */
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ecbw->ext_csd_bits & ~EXT_CSD_DDR);
if (err)
goto error;
mmc_set_bus_width(mmc, bus_width(ecbw->cap));
if (err)
continue;
/* 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) {
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH, ecbw->ext_csd_bits);
if (err)
goto error;
}
mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
mmc_set_bus_width(mmc, widths[idx]);
/* configure the bus mode (host) */
mmc_select_mode(mmc, mwt->mode);
mmc_set_clock(mmc, mmc->tran_speed);
err = mmc_read_and_compare_ext_csd(mmc);
if (!err)
break;
/* do a transfer to check the configuration */
err = mmc_read_and_compare_ext_csd(mmc);
if (!err)
return 0;
+error:
/* if an error occured, revert to a safer bus mode */
mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
mmc_select_mode(mmc, MMC_LEGACY);
mmc_set_bus_width(mmc, 1);
}}
- if (err)
return err;
- if (mmc->card_caps & MMC_MODE_HS_52MHz) {
if (mmc->ddr_mode)
mmc_select_mode(mmc, MMC_DDR_52);
else
mmc_select_mode(mmc, MMC_HS_52);
- } else if (mmc->card_caps & MMC_MODE_HS)
mmc_select_mode(mmc, MMC_HS);
- error("unable to select a mode\n");
- return err;
return -ENOTSUPP; }
static int mmc_startup_v4(struct mmc *mmc)
@@ -1747,7 +1797,7 @@ static int mmc_startup(struct mmc *mmc) if (IS_SD(mmc)) err = sd_select_mode_and_width(mmc); else
err = mmc_select_bus_freq_width(mmc);
err = mmc_select_mode_and_width(mmc);
if (err) return err;
diff --git a/include/mmc.h b/include/mmc.h index 1ffa7ec..3c6971d 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -213,9 +213,10 @@ #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_8 2 /* Card is in 8 bit mode */ -#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 4 /* Card is in DDR mode */
Why do you change to 4 as DDR mode?
It's a flag to add to EXT_CSD_BUS_WIDTH_x. for example EXT_CSD_BUS_WIDTH_4 | EXT_CSD_DDR = 1 | 4 = 5
JJ
+#define EXT_CSD_TIMING_LEGACY 0 /* no high speed */ +#define EXT_CSD_TIMING_HS 1 /* HS */ #define EXT_CSD_BOOT_ACK_ENABLE (1 << 6) #define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3) #define EXT_CSD_PARTITION_ACCESS_ENABLE (1 << 0) @@ -424,6 +425,16 @@ enum bus_mode {
const char *mmc_mode_name(enum bus_mode mode); void mmc_dump_capabilities(const char *text, uint caps);
+static inline bool mmc_is_mode_ddr(enum bus_mode mode) +{
- if ((mode == MMC_DDR_52) || (mode == UHS_DDR50))
return true;
- else
return false;
+}
- /*
- With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device
- with mmc_get_mmc_dev().