From 3ba1d53c420c321a72312902b735680491988bad Mon Sep 17 00:00:00 2001 From: Pragnesh Patel Date: Mon, 29 Jun 2020 15:17:24 +0530 Subject: [PATCH 1/6] mmc: mmc_spi: correct the while condition 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 Reviewed-by: Bin Meng Tested-by: Bin Meng --- 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; } From a236d834fa431191b80e15088995ee4d06685674 Mon Sep 17 00:00:00 2001 From: Pragnesh Patel Date: Mon, 29 Jun 2020 15:17:25 +0530 Subject: [PATCH 2/6] mmc: mmc_spi: generate R1 response for different mmc SPI commands 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 Reviewed-by: Bin Meng Tested-by: Bin Meng --- 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; From 810bc13803027c63560504a3b910cf2ef3799194 Mon Sep 17 00:00:00 2001 From: Pragnesh Patel Date: Mon, 29 Jun 2020 15:17:26 +0530 Subject: [PATCH 3/6] mmc: read ssr for SD spi The content of ssr is useful only for erase operations. This saves erase time. Signed-off-by: Pragnesh Patel Reviewed-by: Bin Meng Tested-by: Bin Meng --- 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 50f47d4ba2..7b5c55be7d 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1753,6 +1753,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; From 70f176ae827823cb6fb7edccc8211c1f2f92b754 Mon Sep 17 00:00:00 2001 From: Pragnesh Patel Date: Mon, 29 Jun 2020 15:17:27 +0530 Subject: [PATCH 4/6] mmc: mmc_spi: Read R2 response for send status command - CMD13 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 Reviewed-by: Bin Meng Tested-by: Bin Meng --- 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: From 6f4555af8471491d7f8c01187a97f2b0fcedc286 Mon Sep 17 00:00:00 2001 From: Pragnesh Patel Date: Mon, 29 Jun 2020 15:17:28 +0530 Subject: [PATCH 5/6] mmc: mmc_spi: Generate R1 response for erase block start and end address 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 Reviewed-by: Bin Meng Tested-by: Bin Meng --- 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; From ed4a11cb7d19a26dd0625bc468ef930c035a71b2 Mon Sep 17 00:00:00 2001 From: Pragnesh Patel Date: Mon, 29 Jun 2020 15:17:29 +0530 Subject: [PATCH 6/6] mmc_spi: generate R1b response for erase and stop transmission command 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 Reviewed-by: Bin Meng Tested-by: Bin Meng --- 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;