[U-Boot] [PATCH] mmc: fsl_esdhc: Fix PIO timeout

Benoît Thébaudeau benoit.thebaudeau.dev at gmail.com
Sun Oct 29 21:08:58 UTC 2017


The following error has been observed on i.MX25 with a high-speed SDSC
card:
    Data Write Failed in PIO Mode.

It was caused by the timeout set on PRSSTAT.BWEN, which was triggered
because this bit takes 15 ms to be set after writing the first block to
DATPORT with this card. Without this timeout, all the blocks are
properly written.

This timeout was implemented by decrementing a variable, so it was
depending on the CPU frequency. Fix this issue by setting this timeout
to a long enough absolute duration (500 ms).

Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau.dev at gmail.com>
Cc: Stefano Babic <sbabic at denx.de>
Cc: Fabio Estevam <fabio.estevam at nxp.com>
Cc: Jaehoon Chung <jh80.chung at samsung.com>
---
 drivers/mmc/fsl_esdhc.c | 26 +++++++++++++-------------
 include/fsl_esdhc.h     |  2 +-
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index cc188c4260..499d622c6d 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -171,20 +171,20 @@ static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv,
 	uint databuf;
 	uint size;
 	uint irqstat;
-	uint timeout;
+	ulong start;
 
 	if (data->flags & MMC_DATA_READ) {
 		blocks = data->blocks;
 		buffer = data->dest;
 		while (blocks) {
-			timeout = PIO_TIMEOUT;
+			start = get_timer(0);
 			size = data->blocksize;
 			irqstat = esdhc_read32(&regs->irqstat);
-			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)
-				&& --timeout);
-			if (timeout <= 0) {
-				printf("\nData Read Failed in PIO Mode.");
-				return;
+			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)) {
+				if (get_timer(start) > PIO_TIMEOUT) {
+					printf("\nData Read Failed in PIO Mode.");
+					return;
+				}
 			}
 			while (size && (!(irqstat & IRQSTAT_TC))) {
 				udelay(100); /* Wait before last byte transfer complete */
@@ -200,14 +200,14 @@ static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv,
 		blocks = data->blocks;
 		buffer = (char *)data->src;
 		while (blocks) {
-			timeout = PIO_TIMEOUT;
+			start = get_timer(0);
 			size = data->blocksize;
 			irqstat = esdhc_read32(&regs->irqstat);
-			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BWEN)
-				&& --timeout);
-			if (timeout <= 0) {
-				printf("\nData Write Failed in PIO Mode.");
-				return;
+			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BWEN)) {
+				if (get_timer(start) > PIO_TIMEOUT) {
+					printf("\nData Write Failed in PIO Mode.");
+					return;
+				}
 			}
 			while (size && (!(irqstat & IRQSTAT_TC))) {
 				udelay(100); /* Wait before last byte transfer complete */
diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h
index 02b362d5e3..de1f5e7d9f 100644
--- a/include/fsl_esdhc.h
+++ b/include/fsl_esdhc.h
@@ -130,7 +130,7 @@
 #define XFERTYP_DMAEN		0x00000001
 
 #define CINS_TIMEOUT		1000
-#define PIO_TIMEOUT		100000
+#define PIO_TIMEOUT		500
 
 #define DSADDR		0x2e004
 
-- 
2.14.1



More information about the U-Boot mailing list