+ goto fail;
+
+ /*
+ * During a signal voltage level switch, the clock must be gated
+ * for 5 ms according to the SD spec
+ */
+ mmc_set_clock(mmc, mmc->clock, true);
+
+ err = mmc_set_signal_voltage(mmc, signal_voltage);
+ if (err)
+ goto fail;
+
+ /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
+ udelay(10000);
+ mmc_set_clock(mmc, mmc->clock, false);
+
+ /* Wait for at least 1 ms according to spec */
+ udelay(1000);
+
+ /*
+ * Failure to switch is indicated by the card holding
+ * dat[0:3] low
+ */
+ if (mmc_card_busy(mmc))
+ goto fail;
+
+ return 0;
+
+fail:
+ return -EIO;
+}
+
+static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
{
int timeout = 1000;
int err;
@@ -435,6 +497,9 @@ static int sd_send_op_cond(struct mmc *mmc)
if (mmc->version == SD_VERSION_2)
cmd.cmdarg |= OCR_HCS;
+ if (uhs_en)
+ cmd.cmdarg |= OCR_S18R;
+
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
@@ -465,6 +530,13 @@ static int sd_send_op_cond(struct mmc *mmc)
mmc->ocr = cmd.response[0];
+ if (!(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
+ == 0x41000000) {
+ err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
+ if (err)
+ return err;
+ }
+
mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
mmc->rca = 0;
@@ -977,6 +1049,7 @@ static int sd_get_capabilities(struct mmc *mmc)
ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
struct mmc_data data;
int timeout;
+ u32 sd3_bus_mode;
mmc->card_caps = MMC_MODE_1BIT;
@@ -1058,6 +1131,22 @@ retry_scr:
if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
mmc->card_caps |= MMC_CAP(SD_HS);
+ /* Version before 3.0 don't support UHS modes */
+ if (mmc->version < SD_VERSION_3)
+ return 0;
+
+ sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
+ if (sd3_bus_mode & SD_MODE_UHS_SDR104)
+ mmc->card_caps |= MMC_CAP(UHS_SDR104);
+ if (sd3_bus_mode & SD_MODE_UHS_SDR50)
+ mmc->card_caps |= MMC_CAP(UHS_SDR50);
+ if (sd3_bus_mode & SD_MODE_UHS_SDR25)
+ mmc->card_caps |= MMC_CAP(UHS_SDR25);
+ if (sd3_bus_mode & SD_MODE_UHS_SDR12)
+ mmc->card_caps |= MMC_CAP(UHS_SDR12);
+ if (sd3_bus_mode & SD_MODE_UHS_DDR50)
+ mmc->card_caps |= MMC_CAP(UHS_DDR50);
+
return 0;
}
@@ -1065,13 +1154,36 @@ static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
{
int err;
ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
+ int speed;
+
+ switch (mode) {
+ case SD_LEGACY:
+ case UHS_SDR12:
+ speed = UHS_SDR12_BUS_SPEED;
+ break;
+ case SD_HS:
+ case UHS_SDR25:
+ speed = UHS_SDR25_BUS_SPEED;
+ break;
+ case UHS_SDR50:
+ speed = UHS_SDR50_BUS_SPEED;
+ break;
+ case UHS_DDR50:
+ speed = UHS_DDR50_BUS_SPEED;
+ break;
+ case UHS_SDR104:
+ speed = UHS_SDR104_BUS_SPEED;
+ break;
+ default:
+ return -EINVAL;
+ }
- err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
+ err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
if (err)
return err;
- if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) != 0x01000000)
+ if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
return -ENOTSUPP;
return 0;
@@ -1291,10 +1403,31 @@ static int mmc_set_signal_voltage(struct mmc *mmc, uint
signal_voltage)
static const struct mode_width_tuning sd_modes_by_pref[] = {
{
+ .mode = UHS_SDR104,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ .tuning = MMC_SEND_TUNING_BLOCK
+ },
+ {
+ .mode = UHS_SDR50,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+ {
+ .mode = UHS_DDR50,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+ {
+ .mode = UHS_SDR25,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+ {
.mode = SD_HS,
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
},
{
+ .mode = UHS_SDR12,
+ .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
+ },
+ {
.mode = SD_LEGACY,
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
}
@@ -1310,18 +1443,24 @@ static int sd_select_mode_and_width(struct mmc *mmc)
int err;
uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
const struct mode_width_tuning *mwt;
+ bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
+ uint caps;
+
err = sd_get_capabilities(mmc);
if (err)
return err;
/* Restrict card's capabilities by what the host can do */
- mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
+ caps = mmc->card_caps & (mmc->cfg->host_caps | MMC_MODE_1BIT);
- for_each_sd_mode_by_pref(mmc->card_caps, mwt) {
+ if (!uhs_en)
+ caps &= ~UHS_CAPS;
+
+ for_each_sd_mode_by_pref(caps, mwt) {
uint *w;
for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
- if (*w & mmc->card_caps & mwt->widths) {
+ if (*w & caps & mwt->widths) {
debug("trying mode %s width %d (at %d MHz)\n",
mmc_mode_name(mwt->mode),
bus_width(*w),
@@ -1342,6 +1481,16 @@ static int sd_select_mode_and_width(struct mmc *mmc)
mmc_select_mode(mmc, mwt->mode);
mmc_set_clock(mmc, mmc->tran_speed, false);
+ /* execute tuning if needed */
+ if (mwt->tuning && !mmc_host_is_spi(mmc)) {
+ err = mmc_execute_tuning(mmc,
+ mwt->tuning);
+ if (err) {
+ debug("tuning failed\n");
+ goto error;
+ }
+ }
+
err = sd_read_ssr(mmc);
if (!err)
return 0;
@@ -1993,6 +2142,7 @@ static void mmc_power_cycle(struct mmc *mmc)
int mmc_start_init(struct mmc *mmc)
{
bool no_card;
+ bool uhs_en = supports_uhs(mmc->cfg->host_caps);
int err;
/* we pretend there's no card when init is NULL */
@@ -2028,6 +2178,7 @@ int mmc_start_init(struct mmc *mmc)
#endif
mmc->ddr_mode = 0;
+retry:
mmc_power_cycle(mmc);
/* Reset the Card */
@@ -2043,7 +2194,11 @@ int mmc_start_init(struct mmc *mmc)
err = mmc_send_if_cond(mmc);
/* Now try to get the SD card's operating condition */
- err = sd_send_op_cond(mmc);
+ err = sd_send_op_cond(mmc, uhs_en);
+ if (err && uhs_en) {
+ uhs_en = false;
+ goto retry;
+ }
/* If the command timed out, we check for an MMC card */
if (err == -ETIMEDOUT) {
diff --git a/include/mmc.h b/include/mmc.h
index b42f686..775c47e 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -87,6 +87,7 @@
#define MMC_CMD_SET_BLOCKLEN 16
#define MMC_CMD_READ_SINGLE_BLOCK 17
#define MMC_CMD_READ_MULTIPLE_BLOCK 18
+#define MMC_SEND_TUNING_BLOCK 19
#define MMC_SEND_TUNING_BLOCK_HS200 21
#define MMC_CMD_SET_BLOCK_COUNT 23
#define MMC_CMD_WRITE_SINGLE_BLOCK 24
@@ -117,7 +118,8 @@
static inline bool mmc_is_tuning_cmd(uint cmdidx)
{
- if (cmdidx == MMC_SEND_TUNING_BLOCK_HS200)
+ if ((cmdidx == MMC_SEND_TUNING_BLOCK_HS200) ||
+ (cmdidx == MMC_SEND_TUNING_BLOCK))
return true;
return false;
}
@@ -126,8 +128,22 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
#define SD_HIGHSPEED_BUSY 0x00020000
#define SD_HIGHSPEED_SUPPORTED 0x00020000
+#define UHS_SDR12_BUS_SPEED 0
+#define HIGH_SPEED_BUS_SPEED 1
+#define UHS_SDR25_BUS_SPEED 1
+#define UHS_SDR50_BUS_SPEED 2
+#define UHS_SDR104_BUS_SPEED 3
+#define UHS_DDR50_BUS_SPEED 4
+
+#define SD_MODE_UHS_SDR12 (1 << UHS_SDR12_BUS_SPEED)
+#define SD_MODE_UHS_SDR25 (1 << UHS_SDR25_BUS_SPEED)
+#define SD_MODE_UHS_SDR50 (1 << UHS_SDR50_BUS_SPEED)
+#define SD_MODE_UHS_SDR104 (1 << UHS_SDR104_BUS_SPEED)
+#define SD_MODE_UHS_DDR50 (1 << UHS_DDR50_BUS_SPEED)
+
#define OCR_BUSY 0x80000000
#define OCR_HCS 0x40000000
+#define OCR_S18R 0x1000000
#define OCR_VOLTAGE_MASK 0x007FFF80
#define OCR_ACCESS_MODE 0x60000000
@@ -490,6 +506,15 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode)
return false;
}
+#define UHS_CAPS (MMC_CAP(UHS_SDR12) | MMC_CAP(UHS_SDR25) | \
+ MMC_CAP(UHS_SDR50) | MMC_CAP(UHS_SDR104) | \
+ MMC_CAP(UHS_DDR50))
+
+static inline bool supports_uhs(uint caps)
+{
+ return (caps & UHS_CAPS) ? true : false;
+}
+
/*
* With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device