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)) {
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[] = {
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,
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,
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);
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
#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
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