]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
Fix emmc error state after mmc write timeout
authorIulian Banaga <iulianeugen.banaga@mobileye.com>
Mon, 21 Jul 2025 12:35:00 +0000 (15:35 +0300)
committerPeng Fan <peng.fan@nxp.com>
Thu, 24 Jul 2025 04:43:31 +0000 (12:43 +0800)
This is a fix for the sporadic mmc write failure:
  mmc write failed
  0 blocks written: ERROR

After this happens the emmc will remain in an error state
where subsequent read/writes fail with a timeout.

The mmc driver sends CMD25 - WRITE_MULTIPLE_BLOCK which
can sporadically timeout. When this happens, the mmc driver
aborts the transfer and returns the above error messages.

But the emmc still remains in data transfer mode, since
the timeout was decided by uboot, not by the emmc.

Fix this by sending the STOP_TRANSMISSION command (CMD12)
and waiting for the emmc to be in ready state again (CMD13).

Transferring data blocks after a CMD25 can take anywhere
between 5 and +15s on Samsung EMMCs and the current timeout
is not enough. Increase the timeout by 2x to accommodate the
long transfer times observed.

Signed-off-by: Iulian Banaga <iulianeugen.banaga@mobileye.com>
Acked-by: Jimmy Durand Wesolowski <jimmy.wesolowski@mobileye.com>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
drivers/mmc/mmc_write.c

index 90fcf2679bbb60b6b4c64045960ed2aa5de1a564..928c05872ca0dd9d7595048254820b1a923b83c0 100644 (file)
@@ -155,6 +155,7 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
        struct mmc_cmd cmd;
        struct mmc_data data;
        int timeout_ms = 1000;
+       int err;
 
        if ((start + blkcnt) > mmc_get_blk_desc(mmc)->lba) {
                printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
@@ -181,9 +182,13 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
        data.blocksize = mmc->write_bl_len;
        data.flags = MMC_DATA_WRITE;
 
-       if (mmc_send_cmd(mmc, &cmd, &data)) {
+       err = mmc_send_cmd(mmc, &cmd, &data);
+       if (err) {
                printf("mmc write failed\n");
-               return 0;
+               /*
+                * Don't return 0 here since the emmc will still be in data
+                * transfer mode continue to send the STOP_TRANSMISSION command
+                */
        }
 
        /* SPI multiblock writes terminate using a special
@@ -203,6 +208,9 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
        if (mmc_poll_for_busy(mmc, timeout_ms))
                return 0;
 
+       if (err)
+               return 0;
+
        return blkcnt;
 }