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

Ziyuan Xu xzy.xu at rock-chips.com
Mon May 15 06:07:03 UTC 2017


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 at rock-chips.com>
---

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

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)
-- 
2.7.4




More information about the U-Boot mailing list