From: Bin Meng <bin.m...@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.m...@windriver.com> --- 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