summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZiyuan Xu <xzy.xu@rock-chips.com>2017-05-15 09:07:03 +0300
committerKever Yang <kever.yang@rock-chips.com>2017-07-18 17:02:27 +0300
commitfaf0cd416f652eeef30f31d84b92856747c6a165 (patch)
tree2f918ad8ee8b3bc7fb97ff92f437f0a0f7550aed
parentc212b2bf6b59bf6d015ae1b288b7e352d797357b (diff)
downloadu-boot-faf0cd416f652eeef30f31d84b92856747c6a165.tar.xz
mmc: rework mmc_switch for non-send_status scenario
Per JEDEC spec, it is not recommended to use cmd13 to get card status after speed mode switch. CMD13 can't be guaranteed due to the asynchronous operation. Besieds, if the host controller supports busy detection in HW, we use it instead of cmd13. Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
-rw-r--r--drivers/mmc/mmc.c55
1 files changed, 45 insertions, 10 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 2ce795d5db..ba34ec427e 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -523,10 +523,46 @@ static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
return err;
}
-int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
+static int mmc_poll_for_busy(struct mmc *mmc)
{
struct mmc_cmd cmd;
+ u8 busy = true;
+ uint start;
+ int ret;
int timeout = 1000;
+
+ cmd.cmdidx = MMC_CMD_SEND_STATUS;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.cmdarg = mmc->rca << 16;
+
+ start = get_timer(0);
+
+ do {
+ if (mmc_can_card_busy(mmc)) {
+ busy = mmc_card_busy(mmc);
+ } else {
+ ret = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (ret)
+ return ret;
+
+ if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
+ return -EBADMSG;
+ busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) ==
+ MMC_STATE_PRG;
+ }
+
+ if (get_timer(start) > timeout && busy)
+ return -ETIMEDOUT;
+ } while (busy);
+
+ return 0;
+}
+
+static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
+ u8 send_status)
+{
+ struct mmc_cmd cmd;
int retries = 3;
int ret;
@@ -536,20 +572,19 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
(index << 16) |
(value << 8);
- while (retries > 0) {
+ do {
ret = mmc_send_cmd(mmc, &cmd, NULL);
- /* Waiting for the ready status */
- if (!ret) {
- ret = mmc_send_status(mmc, timeout);
- return ret;
- }
-
- retries--;
- }
+ if (!ret && send_status)
+ return mmc_poll_for_busy(mmc);
+ } while (--retries > 0 && ret);
return ret;
+}
+int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
+{
+ return __mmc_switch(mmc, set, index, value, true);
}
static int mmc_select_hs(struct mmc *mmc)