diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 7aa01372412d..449514bae4f3 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -61,6 +61,7 @@ static const unsigned int tacc_mant[] = { __res & __mask; \ }) +static int mmc_switch_status(struct mmc_card *card, bool ignore_crc); /* * Given the decoded CSD structure, decode the raw CID to our CID structure. */ @@ -1064,9 +1065,11 @@ static int mmc_select_hs(struct mmc_card *card) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, card->ext_csd.generic_cmd6_time, - true, true, true); - if (!err) + true, false, true); + if (!err) { mmc_set_timing(card->host, MMC_TIMING_MMC_HS); + err = mmc_switch_status(card, false); + } return err; } @@ -1090,10 +1093,11 @@ static int mmc_select_hs_ddr(struct mmc_card *card) ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4; - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, ext_csd_bits, - card->ext_csd.generic_cmd6_time); + card->ext_csd.generic_cmd6_time, + true, false, false); if (err) { pr_err("%s: switch to bus width %d ddr failed\n", mmc_hostname(host), 1 << bus_width); @@ -1136,19 +1140,21 @@ static int mmc_select_hs_ddr(struct mmc_card *card) if (err) err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330); - if (!err) + if (!err) { mmc_set_timing(host, MMC_TIMING_MMC_DDR52); + err = mmc_switch_status(card, false); + } return err; } /* Caller must hold re-tuning */ -static int mmc_switch_status(struct mmc_card *card) +static int mmc_switch_status(struct mmc_card *card, bool ignore_crc) { u32 status; int err; - err = mmc_send_status(card, &status); + err = __mmc_send_status(card, &status, ignore_crc); if (err) return err; @@ -1212,7 +1218,7 @@ static int mmc_select_hs400(struct mmc_card *card) mmc_set_clock(host, max_dtr); if (!send_status) { - err = mmc_switch_status(card); + err = mmc_switch_status(card, false); if (err) goto out_err; } @@ -1253,12 +1259,6 @@ static int mmc_select_hs400(struct mmc_card *card) mmc_set_timing(host, MMC_TIMING_MMC_HS400); mmc_set_bus_speed(card); - if (!send_status) { - err = mmc_switch_status(card); - if (err) - goto out_err; - } - if (card->ext_csd.strobe_support && host->ops->enhanced_strobe) { mmc_host_clk_hold(host); err = host->ops->enhanced_strobe(host); @@ -1275,6 +1275,17 @@ static int mmc_select_hs400(struct mmc_card *card) mmc_hostname(host)); } + /* + * Sending of CMD13 should be done after the host calibration + * for enhanced_strobe or HS400 mode is completed. + * Otherwise may see CMD13 timeouts or CRC errors. + */ + if (!send_status) { + err = mmc_switch_status(card, false); + if (err) + goto out_err; + } + return 0; out_err: @@ -1314,7 +1325,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) mmc_set_timing(host, MMC_TIMING_MMC_DDR52); if (!send_status) { - err = mmc_switch_status(card); + err = mmc_switch_status(card, false); if (err) goto out_err; } @@ -1329,7 +1340,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) mmc_set_timing(host, MMC_TIMING_MMC_HS); if (!send_status) { - err = mmc_switch_status(card); + err = mmc_switch_status(card, false); if (err) goto out_err; } @@ -1346,7 +1357,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) mmc_set_timing(host, MMC_TIMING_MMC_HS200); if (!send_status) { - err = mmc_switch_status(card); + err = mmc_switch_status(card, false); if (err) goto out_err; } @@ -1425,7 +1436,12 @@ static int mmc_select_hs200(struct mmc_card *card) old_timing = host->ios.timing; mmc_set_timing(host, MMC_TIMING_MMC_HS200); if (!send_status) { - err = mmc_switch_status(card); + /* + * Since after switching to hs200, crc errors might + * occur for commands send before tuning. + * So ignore crc error for cmd13. + */ + err = mmc_switch_status(card, true); /* * mmc_select_timing() assumes timing has not changed if * it is a switch error. diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 4a978898af84..de406431e5a4 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -54,7 +54,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline int __mmc_send_status(struct mmc_card *card, u32 *status, +int __mmc_send_status(struct mmc_card *card, u32 *status, bool ignore_crc) { int err; diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 1eea7bd51367..ad1058c1adfd 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -32,6 +32,7 @@ int mmc_switch_status_error(struct mmc_host *host, u32 status); int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms, bool use_busy_signal, bool send_status, bool ignore_crc); - +int __mmc_send_status(struct mmc_card *card, u32 *status, + bool ignore_crc); #endif