diff mbox series

[U-Boot,v2,09/11] mmc: During a switch, poll on dat0 if available and check the final status

Message ID 20190702085358.27368-10-jjhiblot@ti.com
State Accepted
Commit bb98b8c5c06a5a9befb74aef843f7cd698c52d5d
Delegated to: Peng Fan
Headers show
Series Improvements on the MMC switch | expand

Commit Message

Jean-Jacques Hiblot July 2, 2019, 8:53 a.m. UTC
The switch operation can sometimes make the bus unreliable, in that case
the send_status parameter should be false to indicate not to poll using
CMD13. If polling on dat0 is possible, we should use it to detect the end
of the operation.
At the end of the operation it is safe to use CMD13 to get the status of
the card. It is important to do so because the operation may have failed.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
---

Changes in v2: None

 drivers/mmc/mmc.c | 49 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 36 insertions(+), 13 deletions(-)
diff mbox series

Patch

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index e5cee7dbc8..1ad35fff7d 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -746,6 +746,7 @@  static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
 static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
 			bool send_status)
 {
+	unsigned int status, start;
 	struct mmc_cmd cmd;
 	int timeout = DEFAULT_CMD6_TIMEOUT_MS;
 	bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) &&
@@ -765,25 +766,47 @@  static 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);
+	} while (ret && retries-- > 0);
 
-		if (ret) {
-			retries--;
-			continue;
-		}
+	if (ret)
+		return ret;
 
-		if (!send_status) {
-			mdelay(50);
-			return 0;
-		}
+	start = get_timer(0);
 
-		/* Waiting for the ready status */
-		return mmc_poll_for_busy(mmc, timeout);
-	}
+	/* poll dat0 for rdy/buys status */
+	ret = mmc_wait_dat0(mmc, 1, timeout);
+	if (ret && ret != -ENOSYS)
+		return ret;
 
-	return ret;
+	/*
+	 * In cases when not allowed to poll by using CMD13 or because we aren't
+	 * capable of polling by using mmc_wait_dat0, then rely on waiting the
+	 * stated timeout to be sufficient.
+	 */
+	if (ret == -ENOSYS && !send_status)
+		mdelay(timeout);
+
+	/* Finally wait until the card is ready or indicates a failure
+	 * to switch. It doesn't hurt to use CMD13 here even if send_status
+	 * is false, because by now (after 'timeout' ms) the bus should be
+	 * reliable.
+	 */
+	do {
+		ret = mmc_send_status(mmc, &status);
+
+		if (!ret && (status & MMC_STATUS_SWITCH_ERROR)) {
+			pr_debug("switch failed %d/%d/0x%x !\n", set, index,
+				 value);
+			return -EIO;
+		}
+		if (!ret && (status & MMC_STATUS_RDY_FOR_DATA))
+			return 0;
+		udelay(100);
+	} while (get_timer(start) < timeout);
 
+	return -ETIMEDOUT;
 }
 
 int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)