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 |
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 --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);