On 05/16/2017 11:20 PM, Jean-Jacques Hiblot wrote: > > > On 12/05/2017 20:16, Jean-Jacques Hiblot wrote: >> Add UHS modes to the list of supported modes, get the UHS capabilites of >> the SDcard and implement the procedure to switch the voltage (UHS modes >> use 1v8 IO lines) >> During the voltage switch procedure, DAT0 is used by the card to signal >> when it's ready. The optional card_busy() callback can be used to get this >> information from the host driver. >> >> Signed-off-by: Jean-Jacques Hiblot <jjhib...@ti.com> >> --- >> drivers/mmc/mmc.c | 169 >> +++++++++++++++++++++++++++++++++++++++++++++++++++--- >> include/mmc.h | 27 ++++++++- >> 2 files changed, 188 insertions(+), 8 deletions(-) >> >> diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c >> index f6509f1..074d286 100644 >> --- a/drivers/mmc/mmc.c >> +++ b/drivers/mmc/mmc.c >> @@ -31,6 +31,7 @@ static const unsigned int sd_au_size[] = { >> }; >> static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); >> static void mmc_power_cycle(struct mmc *mmc); >> +static int mmc_card_busy(struct mmc *mmc); >> #if CONFIG_IS_ENABLED(MMC_TINY) >> static struct mmc mmc_static; >> @@ -403,7 +404,68 @@ 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) >> + goto fail; >> + >> + if (!mmc_host_is_spi(host) && (cmd.response[0] & MMC_STATUS_ERROR)) >> + goto fail; >> + >> + /* >> + * The card should drive cmd and dat[0:3] low immediately >> + * after the response of cmd11, but wait 1 ms to be sure >> + */ >> + udelay(1000); >> + if (mmc_card_busy(mmc)) > Hi all, > > there is an error her that I let through while cleaning the code before > posting. > The line above should be: if (!mmc_card_busy(mmc)). > I'll fix this in the v2. > > Jaehoon, if you're testing the patches you might want to fix this first (you > can just remove the calls to mmc_card_busy() for the moment). I hope it did > not impede you.
Thanks for noticing. :) Best Regards, Jaehoon Chung > > Jean-Jacques >> + 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 > > > > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot