diff mbox series

[15/22] hw/sd: ssi-sd: Support multiple block write

Message ID 20201231113010.27108-16-bmeng.cn@gmail.com (mailing list archive)
State New, archived
Headers show
Series hw/riscv: sifive_u: Add missing SPI support | expand

Commit Message

Bin Meng Dec. 31, 2020, 11:30 a.m. UTC
From: Bin Meng <bin.meng@windriver.com>

For a multiple block write operation, each block begins with a multi
write start token. Unlike the SD mode that the multiple block write
ends when receiving a STOP_TRAN command (CMD12), a special stop tran
tocken is used to signal the card.

Emulating this by manually sending a CMD12 to the SD card core, to
bring it out of the receiving data state.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
---

 hw/sd/ssi-sd.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

Comments

Alistair Francis Jan. 13, 2021, 6:11 p.m. UTC | #1
On Thu, Dec 31, 2020 at 3:47 AM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> From: Bin Meng <bin.meng@windriver.com>
>
> For a multiple block write operation, each block begins with a multi
> write start token. Unlike the SD mode that the multiple block write
> ends when receiving a STOP_TRAN command (CMD12), a special stop tran
> tocken is used to signal the card.
>
> Emulating this by manually sending a CMD12 to the SD card core, to
> bring it out of the receiving data state.
>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>

Acked-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>
>  hw/sd/ssi-sd.c | 26 ++++++++++++++++++++++++--
>  1 file changed, 24 insertions(+), 2 deletions(-)
>
> diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
> index 21a96e91f0..6cf5d749c7 100644
> --- a/hw/sd/ssi-sd.c
> +++ b/hw/sd/ssi-sd.c
> @@ -99,6 +99,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
>  static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
>  {
>      ssi_sd_state *s = SSI_SD(dev);
> +    SDRequest request;
> +    uint8_t longresp[16];
>
>      /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.  */
>      if (s->mode == SSI_SD_DATA_READ && val == 0x4c) {
> @@ -115,9 +117,31 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
>              return SSI_DUMMY;
>              break;
>          case SSI_TOKEN_SINGLE:
> +        case SSI_TOKEN_MULTI_WRITE:
>              DPRINTF("Start write block\n");
>              s->mode = SSI_SD_DATA_WRITE;
>              return SSI_DUMMY;
> +        case SSI_TOKEN_STOP_TRAN:
> +            DPRINTF("Stop multiple write\n");
> +
> +            /* manually issue cmd12 to stop the transfer */
> +            request.cmd = 12;
> +            request.arg = 0;
> +            s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
> +            if (s->arglen <= 0) {
> +                s->arglen = 1;
> +                /* a zero value indicates the card is busy */
> +                s->response[0] = 0;
> +                DPRINTF("SD card busy\n");
> +            } else {
> +                s->arglen = 1;
> +                /* a non-zero value indicates the card is ready */
> +                s->response[0] = SSI_DUMMY;
> +            }
> +
> +            s->mode = SSI_SD_RESPONSE;
> +            s->response_pos = 0;
> +            return SSI_DUMMY;
>          }
>
>          s->cmd = val & 0x3f;
> @@ -126,8 +150,6 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
>          return SSI_DUMMY;
>      case SSI_SD_CMDARG:
>          if (s->arglen == 4) {
> -            SDRequest request;
> -            uint8_t longresp[16];
>              /* FIXME: Check CRC.  */
>              request.cmd = s->cmd;
>              request.arg = ldl_be_p(s->cmdarg);
> --
> 2.25.1
>
>
diff mbox series

Patch

diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 21a96e91f0..6cf5d749c7 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -99,6 +99,8 @@  OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
 static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
 {
     ssi_sd_state *s = SSI_SD(dev);
+    SDRequest request;
+    uint8_t longresp[16];
 
     /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.  */
     if (s->mode == SSI_SD_DATA_READ && val == 0x4c) {
@@ -115,9 +117,31 @@  static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
             return SSI_DUMMY;
             break;
         case SSI_TOKEN_SINGLE:
+        case SSI_TOKEN_MULTI_WRITE:
             DPRINTF("Start write block\n");
             s->mode = SSI_SD_DATA_WRITE;
             return SSI_DUMMY;
+        case SSI_TOKEN_STOP_TRAN:
+            DPRINTF("Stop multiple write\n");
+
+            /* manually issue cmd12 to stop the transfer */
+            request.cmd = 12;
+            request.arg = 0;
+            s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
+            if (s->arglen <= 0) {
+                s->arglen = 1;
+                /* a zero value indicates the card is busy */
+                s->response[0] = 0;
+                DPRINTF("SD card busy\n");
+            } else {
+                s->arglen = 1;
+                /* a non-zero value indicates the card is ready */
+                s->response[0] = SSI_DUMMY;
+            }
+
+            s->mode = SSI_SD_RESPONSE;
+            s->response_pos = 0;
+            return SSI_DUMMY;
         }
 
         s->cmd = val & 0x3f;
@@ -126,8 +150,6 @@  static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
         return SSI_DUMMY;
     case SSI_SD_CMDARG:
         if (s->arglen == 4) {
-            SDRequest request;
-            uint8_t longresp[16];
             /* FIXME: Check CRC.  */
             request.cmd = s->cmd;
             request.arg = ldl_be_p(s->cmdarg);