From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 14:30:11 +0000 (+0200) Subject: mmc: use the right voltage level for MMC DDR and HS200 modes X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=bc1e3272ff3437f7cfc5e8bf1d1f2767f6d78262;p=u-boot.git mmc: use the right voltage level for MMC DDR and HS200 modes HS200 only supports 1.2v and 1.8v signal voltages. DDR52 supports 3.3v/1.8v or 1.2v signal voltages. Select the lowest voltage available when using those modes. Signed-off-by: Jean-Jacques Hiblot --- diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 26589b8771..877ce1757d 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -767,6 +767,7 @@ static int mmc_get_capabilities(struct mmc *mmc) mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f; + mmc->cardtype = cardtype; if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | EXT_CSD_CARD_TYPE_HS200_1_8V)) { @@ -1441,10 +1442,30 @@ struct mode_width_tuning { uint tuning; }; +int mmc_voltage_to_mv(enum mmc_voltage voltage) +{ + switch (voltage) { + case MMC_SIGNAL_VOLTAGE_000: return 0; + case MMC_SIGNAL_VOLTAGE_330: return 3300; + case MMC_SIGNAL_VOLTAGE_180: return 1800; + case MMC_SIGNAL_VOLTAGE_120: return 1200; + } + return -EINVAL; +} + static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) { + int err; + + if (mmc->signal_voltage == signal_voltage) + return 0; + mmc->signal_voltage = signal_voltage; - return mmc_set_ios(mmc); + err = mmc_set_ios(mmc); + if (err) + debug("unable to set voltage (err %d)\n", err); + + return err; } static const struct mode_width_tuning sd_modes_by_pref[] = { @@ -1584,6 +1605,43 @@ static int mmc_read_and_compare_ext_csd(struct mmc *mmc) return -EBADMSG; } +static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, + uint32_t allowed_mask) +{ + u32 card_mask = 0; + + switch (mode) { + case MMC_HS_200: + if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V) + card_mask |= MMC_SIGNAL_VOLTAGE_180; + if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V) + card_mask |= MMC_SIGNAL_VOLTAGE_120; + break; + case MMC_DDR_52: + if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) + card_mask |= MMC_SIGNAL_VOLTAGE_330 | + MMC_SIGNAL_VOLTAGE_180; + if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V) + card_mask |= MMC_SIGNAL_VOLTAGE_120; + break; + default: + card_mask |= MMC_SIGNAL_VOLTAGE_330; + break; + } + + while (card_mask & allowed_mask) { + enum mmc_voltage best_match; + + best_match = 1 << (ffs(card_mask & allowed_mask) - 1); + if (!mmc_set_signal_voltage(mmc, best_match)) + return 0; + + allowed_mask &= ~best_match; + } + + return -ENOTSUPP; +} + static const struct mode_width_tuning mmc_modes_by_pref[] = { { .mode = MMC_HS_200, @@ -1655,10 +1713,17 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) for_each_mmc_mode_by_pref(card_caps, mwt) { for_each_supported_width(card_caps & mwt->widths, mmc_is_mode_ddr(mwt->mode), ecbw) { + enum mmc_voltage old_voltage; 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); + old_voltage = mmc->signal_voltage; + err = mmc_set_lowest_voltage(mmc, mwt->mode, + MMC_ALL_SIGNAL_VOLTAGE); + if (err) + continue; + /* configure the bus width (card + host) */ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, @@ -1702,6 +1767,7 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) if (!err) return 0; error: + mmc_set_signal_voltage(mmc, old_voltage); /* 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); diff --git a/include/mmc.h b/include/mmc.h index a9ebc880cb..c11f69859e 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -311,11 +311,15 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) enum mmc_voltage { MMC_SIGNAL_VOLTAGE_000 = 0, - MMC_SIGNAL_VOLTAGE_120, - MMC_SIGNAL_VOLTAGE_180, - MMC_SIGNAL_VOLTAGE_330 + MMC_SIGNAL_VOLTAGE_120 = 1, + MMC_SIGNAL_VOLTAGE_180 = 2, + MMC_SIGNAL_VOLTAGE_330 = 4, }; +#define MMC_ALL_SIGNAL_VOLTAGE (MMC_SIGNAL_VOLTAGE_120 |\ + MMC_SIGNAL_VOLTAGE_180 |\ + MMC_SIGNAL_VOLTAGE_330) + /* Maximum block size for MMC */ #define MMC_MAX_BLOCK_LEN 512 @@ -588,6 +592,8 @@ struct mmc { #endif #endif u8 *ext_csd; + u32 cardtype; /* cardtype read from the MMC */ + enum mmc_voltage current_voltage; enum bus_mode selected_mode; /* mode currently used */ enum bus_mode best_mode; /* best mode is the supported mode with the * highest bandwidth. It may not always be the @@ -646,6 +652,14 @@ int mmc_initialize(bd_t *bis); int mmc_init(struct mmc *mmc); int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size); +/** + * mmc_voltage_to_mv() - Convert a mmc_voltage in mV + * + * @voltage: The mmc_voltage to convert + * @return the value in mV if OK, -EINVAL on error (invalid mmc_voltage value) + */ +int mmc_voltage_to_mv(enum mmc_voltage voltage); + /** * mmc_set_clock() - change the bus clock * @mmc: MMC struct