[PATCH 0/6] mmc_spi: mmc erase resolve

Earlier "mmc erase " command reorts Ok but not actually erase the contents of some SD cards. This series will resolve this issue.
There is still 1 limitation for some SDHC mmc_spi cards: "mmc erase *blk#* cnt" can not erase only 1 block that means:
=> mmc erase 0x22 1
will not erase the contents of SD card. User has to erase multiple blocks at a time that means:
=> mmc erase 0x22 2
will erase the contents of SD card.
This limitation is from micro SD card side, i found this limitation in Strontium micro SDHC - 4 GB (class 6).
Pragnesh Patel (6): mmc: mmc_spi: correct the while condition mmc: mmc_spi: generate R1 response for different mmc SPI commands mmc: read ssr for SD spi mmc: mmc_spi: Read R2 response for send status command - CMD13 mmc: mmc_spi: Generate R1 response for erase block start and end address mmc_spi: generate R1b response for erase and stop transmission command
drivers/mmc/mmc.c | 5 +++++ drivers/mmc/mmc_spi.c | 52 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 8 deletions(-)

When variable i will become 0, while(i--) loop breaks but variable i will again decrement to -1 because of i-- and that's why below condition "if (!i && (r != resp_match_value)" will never execute, So doing "i--" inside of while() loop solves this problem.
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com Reviewed-by: Bin Meng bin.meng@windriver.com --- drivers/mmc/mmc_spi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index e76ab54838..86cc932151 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -105,12 +105,14 @@ static int mmc_spi_sendcmd(struct udevice *dev, if (resp_match) { r = ~resp_match_value; i = CMD_TIMEOUT; - while (i--) { + while (i) { ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); if (ret) return ret; debug(" resp%d=0x%x", rpos, r); rpos++; + i--; + if (r == resp_match_value) break; }

On Mon, Jun 29, 2020 at 5:48 PM Pragnesh Patel pragnesh.patel@sifive.com wrote:
When variable i will become 0, while(i--) loop breaks but variable i will again decrement to -1 because of i-- and that's why below condition "if (!i && (r != resp_match_value)" will never execute, So doing "i--" inside of while() loop solves this problem.
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com Reviewed-by: Bin Meng bin.meng@windriver.com
drivers/mmc/mmc_spi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
Tested-by: Bin Meng bin.meng@windriver.com

R1 response is 1 byte long for mmc SPI commands as per the updated physical layer specification version 7.10.
So correct the resp and resp_size for existing commands
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com --- drivers/mmc/mmc_spi.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index 86cc932151..ddfebb6ed6 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -305,6 +305,8 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, case MMC_CMD_READ_MULTIPLE_BLOCK: case MMC_CMD_WRITE_SINGLE_BLOCK: case MMC_CMD_WRITE_MULTIPLE_BLOCK: + resp = &resp8; + resp_size = sizeof(resp8); break; default: resp = &resp8;

On Mon, Jun 29, 2020 at 5:48 PM Pragnesh Patel pragnesh.patel@sifive.com wrote:
R1 response is 1 byte long for mmc SPI commands as per the updated physical layer specification version 7.10.
So correct the resp and resp_size for existing commands
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com
drivers/mmc/mmc_spi.c | 2 ++ 1 file changed, 2 insertions(+)
Reviewed-by: Bin Meng bin.meng@windriver.com Tested-by: Bin Meng bin.meng@windriver.com

The content of ssr is useful only for erase operations. This saves erase time.
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com Reviewed-by: Bin Meng bin.meng@windriver.com --- drivers/mmc/mmc.c | 5 +++++ drivers/mmc/mmc_spi.c | 1 + 2 files changed, 6 insertions(+)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 620bb93064..6b193d6d70 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1746,6 +1746,11 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) mmc_set_bus_width(mmc, 1); mmc_select_mode(mmc, MMC_LEGACY); mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); +#if CONFIG_IS_ENABLED(MMC_WRITE) + err = sd_read_ssr(mmc); + if (err) + pr_warn("unable to read ssr\n"); +#endif return 0; }
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index ddfebb6ed6..18d36878ef 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -305,6 +305,7 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, case MMC_CMD_READ_MULTIPLE_BLOCK: case MMC_CMD_WRITE_SINGLE_BLOCK: case MMC_CMD_WRITE_MULTIPLE_BLOCK: + case MMC_CMD_APP_CMD: resp = &resp8; resp_size = sizeof(resp8); break;

On Mon, Jun 29, 2020 at 5:48 PM Pragnesh Patel pragnesh.patel@sifive.com wrote:
The content of ssr is useful only for erase operations. This saves erase time.
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com Reviewed-by: Bin Meng bin.meng@windriver.com
drivers/mmc/mmc.c | 5 +++++ drivers/mmc/mmc_spi.c | 1 + 2 files changed, 6 insertions(+)
Tested-by: Bin Meng bin.meng@windriver.com

Send status command (CMD13) will send R1 response under SD mode but R2 response under SPI mode.
R2 response is 2 bytes long, so read 2 bytes for mmc SPI mode
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com --- drivers/mmc/mmc_spi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index 18d36878ef..ee56de36ec 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -266,7 +266,7 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, u8 *resp = NULL; u32 resp_size = 0; bool resp_match = false; - u8 resp8 = 0, resp40[5] = { 0 }, resp_match_value = 0; + u8 resp8 = 0, resp16[2] = { 0 }, resp40[5] = { 0 }, resp_match_value = 0;
dm_spi_claim_bus(dev);
@@ -291,6 +291,9 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, resp_size = sizeof(resp40); break; case MMC_CMD_SEND_STATUS: + resp = (u8 *)&resp16[0]; + resp_size = sizeof(resp16); + break; case MMC_CMD_SET_BLOCKLEN: case MMC_CMD_SPI_CRC_ON_OFF: case MMC_CMD_STOP_TRANSMISSION: @@ -335,8 +338,10 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, cmd->response[0] |= (uint)resp40[1] << 24; break; case MMC_CMD_SEND_STATUS: - cmd->response[0] = (resp8 & 0xff) ? - MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA; + if (resp16[0] || resp16[1]) + cmd->response[0] = MMC_STATUS_ERROR; + else + cmd->response[0] = MMC_STATUS_RDY_FOR_DATA; break; case MMC_CMD_SEND_CID: case MMC_CMD_SEND_CSD:

On Mon, Jun 29, 2020 at 5:48 PM Pragnesh Patel pragnesh.patel@sifive.com wrote:
Send status command (CMD13) will send R1 response under SD mode but R2 response under SPI mode.
R2 response is 2 bytes long, so read 2 bytes for mmc SPI mode
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com
drivers/mmc/mmc_spi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
Reviewed-by: Bin Meng bin.meng@windriver.com Tested-by: Bin Meng bin.meng@windriver.com

Erase block start address (CMD32) and erase block end address (CMD33) command will generate R1 response for mmc SPI mode.
R1 response is 1 byte long for mmc SPI, so assign 1 byte as a response for this commands.
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com --- drivers/mmc/mmc_spi.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index ee56de36ec..96a41076dc 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -309,6 +309,8 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, case MMC_CMD_WRITE_SINGLE_BLOCK: case MMC_CMD_WRITE_MULTIPLE_BLOCK: case MMC_CMD_APP_CMD: + case SD_CMD_ERASE_WR_BLK_START: + case SD_CMD_ERASE_WR_BLK_END: resp = &resp8; resp_size = sizeof(resp8); break;

On Mon, Jun 29, 2020 at 5:48 PM Pragnesh Patel pragnesh.patel@sifive.com wrote:
Erase block start address (CMD32) and erase block end address (CMD33) command will generate R1 response for mmc SPI mode.
R1 response is 1 byte long for mmc SPI, so assign 1 byte as a response for this commands.
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com
drivers/mmc/mmc_spi.c | 2 ++ 1 file changed, 2 insertions(+)
Reviewed-by: Bin Meng bin.meng@windriver.com Tested-by: Bin Meng bin.meng@windriver.com

As per the SD physical layer specification version 7.10, erase command (CMD38) and stop transmission command (CMD12) will generate R1b response.
R1b = R1 + busy signal
A non-zero value after the R1 response indicates card is ready for next command.
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com --- drivers/mmc/mmc_spi.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index 96a41076dc..50fcd32674 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -59,6 +59,7 @@ #define CMD_TIMEOUT 8 #define READ_TIMEOUT 3000000 /* 1 sec */ #define WRITE_TIMEOUT 3000000 /* 1 sec */ +#define R1B_TIMEOUT 3000000 /* 1 sec */
struct mmc_spi_plat { struct mmc_config cfg; @@ -72,7 +73,7 @@ struct mmc_spi_priv { static int mmc_spi_sendcmd(struct udevice *dev, ushort cmdidx, u32 cmdarg, u32 resp_type, u8 *resp, u32 resp_size, - bool resp_match, u8 resp_match_value) + bool resp_match, u8 resp_match_value, bool r1b) { int i, rpos = 0, ret = 0; u8 cmdo[7], r; @@ -133,6 +134,24 @@ static int mmc_spi_sendcmd(struct udevice *dev, resp[i] = r; }
+ if (r1b == true) { + i = R1B_TIMEOUT; + while (i) { + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + + debug(" resp%d=0x%x", rpos, r); + rpos++; + i--; + + if (r) + break; + } + if (!i) + return -ETIMEDOUT; + } + debug("\n");
return 0; @@ -265,7 +284,7 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, int i, multi, ret = 0; u8 *resp = NULL; u32 resp_size = 0; - bool resp_match = false; + bool resp_match = false, r1b = false; u8 resp8 = 0, resp16[2] = { 0 }, resp40[5] = { 0 }, resp_match_value = 0;
dm_spi_claim_bus(dev); @@ -296,12 +315,17 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, break; case MMC_CMD_SET_BLOCKLEN: case MMC_CMD_SPI_CRC_ON_OFF: - case MMC_CMD_STOP_TRANSMISSION: resp = &resp8; resp_size = sizeof(resp8); resp_match = true; resp_match_value = 0x0; break; + case MMC_CMD_STOP_TRANSMISSION: + case MMC_CMD_ERASE: + resp = &resp8; + resp_size = sizeof(resp8); + r1b = true; + break; case MMC_CMD_SEND_CSD: case MMC_CMD_SEND_CID: case MMC_CMD_READ_SINGLE_BLOCK: @@ -323,7 +347,7 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, };
ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg, cmd->resp_type, - resp, resp_size, resp_match, resp_match_value); + resp, resp_size, resp_match, resp_match_value, r1b); if (ret) goto done;

On Mon, Jun 29, 2020 at 5:48 PM Pragnesh Patel pragnesh.patel@sifive.com wrote:
As per the SD physical layer specification version 7.10, erase command (CMD38) and stop transmission command (CMD12) will generate R1b response.
R1b = R1 + busy signal
A non-zero value after the R1 response indicates card is ready for next command.
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com
drivers/mmc/mmc_spi.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-)
Reviewed-by: Bin Meng bin.meng@windriver.com Tested-by: Bin Meng bin.meng@windriver.com
participants (2)
-
Bin Meng
-
Pragnesh Patel