diff mbox

[U-Boot,09/33] mmc: rework mmc_switch for non-send_status scenario

Message ID 1494828447-24332-9-git-send-email-xzy.xu@rock-chips.com
State Not Applicable
Delegated to: Jaehoon Chung
Headers show

Commit Message

Xu Ziyuan May 15, 2017, 6:07 a.m. UTC
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>
---

 drivers/mmc/mmc.c | 55 +++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 45 insertions(+), 10 deletions(-)
diff mbox

Patch

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 13d8f04..9aee6ff 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)