diff options
-rw-r--r-- | drivers/mmc/mmc-uclass.c | 14 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 176 | ||||
-rw-r--r-- | include/mmc.h | 40 |
3 files changed, 221 insertions, 9 deletions
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 60cc0ac4cc8..7856e0ad084 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -64,6 +64,20 @@ void mmc_send_init_stream(struct mmc *mmc) dm_mmc_send_init_stream(mmc->dev); } +int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (!ops->wait_dat0) + return -ENOSYS; + return ops->wait_dat0(dev, state, timeout); +} + +int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) +{ + return dm_mmc_wait_dat0(mmc->dev, state, timeout); +} + int dm_mmc_get_wp(struct udevice *dev) { struct dm_mmc_ops *ops = mmc_get_ops(dev); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index d59cce611e4..fe31540ba29 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -57,6 +57,12 @@ struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) #endif #if !CONFIG_IS_ENABLED(DM_MMC) + +static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) +{ + return -ENOSYS; +} + __weak int board_mmc_getwp(struct mmc *mmc) { return -1; @@ -402,7 +408,67 @@ static int mmc_go_idle(struct mmc *mmc) return 0; } -static int sd_send_op_cond(struct mmc *mmc) +static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage) +{ + struct mmc_cmd cmd; + int err = 0; + + /* + * Send CMD11 only if the request is to switch the card to + * 1.8V signalling. + */ + if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) + return mmc_set_signal_voltage(mmc, signal_voltage); + + cmd.cmdidx = SD_CMD_SWITCH_UHS18V; + cmd.cmdarg = 0; + cmd.resp_type = MMC_RSP_R1; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + return err; + + if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR)) + return -EIO; + + /* + * The card should drive cmd and dat[0:3] low immediately + * after the response of cmd11, but wait 100 us to be sure + */ + err = mmc_wait_dat0(mmc, 0, 100); + if (err == -ENOSYS) + udelay(100); + else if (err) + return -ETIMEDOUT; + + /* + * 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) + return err; + + /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ + mdelay(10); + mmc_set_clock(mmc, mmc->clock, false); + + /* + * Failure to switch is indicated by the card holding + * dat[0:3] low. Wait for at least 1 ms according to spec + */ + err = mmc_wait_dat0(mmc, 1, 1000); + if (err == -ENOSYS) + udelay(1000); + else if (err) + return -ETIMEDOUT; + + return 0; +} + +static int sd_send_op_cond(struct mmc *mmc, bool uhs_en) { int timeout = 1000; int err; @@ -434,6 +500,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) @@ -464,6 +533,13 @@ static int sd_send_op_cond(struct mmc *mmc) mmc->ocr = cmd.response[0]; + if (uhs_en && !(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 +1053,7 @@ static int sd_get_capabilities(struct mmc *mmc) ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); struct mmc_data data; int timeout; + u32 sd3_bus_mode; mmc->card_caps = MMC_MODE_1BIT; @@ -1058,6 +1135,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; } @@ -1066,12 +1159,35 @@ 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; - err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); + 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, 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; @@ -1286,10 +1402,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_CMD_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, } @@ -1306,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), @@ -1338,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; @@ -2000,7 +2153,7 @@ static int mmc_power_off(struct mmc *mmc) int ret = regulator_set_enable(mmc->vmmc_supply, false); if (ret) { - puts("Error disabling VMMC supply\n"); + debug("Error disabling VMMC supply\n"); return ret; } } @@ -2026,6 +2179,7 @@ static int 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 */ @@ -2065,6 +2219,7 @@ int mmc_start_init(struct mmc *mmc) #endif mmc->ddr_mode = 0; +retry: mmc_set_initial_state(mmc); mmc_send_init_stream(mmc); @@ -2081,7 +2236,12 @@ 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; + mmc_power_cycle(mmc); + 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 407fddf94c3..ba4a13e8617 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_CMD_SEND_TUNING_BLOCK 19 #define MMC_CMD_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_CMD_SEND_TUNING_BLOCK_HS200) + if ((cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) || + (cmdidx == MMC_CMD_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 BIT(UHS_SDR12_BUS_SPEED) +#define SD_MODE_UHS_SDR25 BIT(UHS_SDR25_BUS_SPEED) +#define SD_MODE_UHS_SDR50 BIT(UHS_SDR50_BUS_SPEED) +#define SD_MODE_UHS_SDR104 BIT(UHS_SDR104_BUS_SPEED) +#define SD_MODE_UHS_DDR50 BIT(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 @@ -410,6 +426,17 @@ struct dm_mmc_ops { * @return 0 if OK, -ve on error */ int (*execute_tuning)(struct udevice *dev, uint opcode); + + /** + * wait_dat0() - wait until dat0 is in the target state + * (CLK must be running during the wait) + * + * @dev: Device to check + * @state: target state + * @timeout: timeout in us + * @return 0 if dat0 is in the target state, -ve on error + */ + int (*wait_dat0)(struct udevice *dev, int state, int timeout); }; #define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops) @@ -421,6 +448,7 @@ void dm_mmc_send_init_stream(struct udevice *dev); int dm_mmc_get_cd(struct udevice *dev); int dm_mmc_get_wp(struct udevice *dev); int dm_mmc_execute_tuning(struct udevice *dev, uint opcode); +int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout); /* Transition functions for compatibility */ int mmc_set_ios(struct mmc *mmc); @@ -428,6 +456,7 @@ void mmc_send_init_stream(struct mmc *mmc); int mmc_getcd(struct mmc *mmc); int mmc_getwp(struct mmc *mmc); int mmc_execute_tuning(struct mmc *mmc, uint opcode); +int mmc_wait_dat0(struct mmc *mmc, int state, int timeout); #else struct mmc_ops { @@ -486,6 +515,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 * with mmc_get_mmc_dev(). |