From: Bin Meng <bin.m...@windriver.com> In the case of a multiple block read operation every transfered block has its suffix of CRC16. Update the state machine logic to handle multiple block read.
This also fixed the wrong command index for STOP_TRANSMISSION, the required command to interupt the multiple block read command, in the old codes. It should be CMD12 (0x4c), not CMD13 (0x4d). Signed-off-by: Bin Meng <bin.m...@windriver.com> --- hw/sd/ssi-sd.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 10b0ac2eaf..889260bd8f 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -51,6 +51,7 @@ struct ssi_sd_state { uint8_t cmdarg[4]; uint8_t response[5]; uint16_t crc16; + int32_t read_bytes; int32_t arglen; int32_t response_pos; int32_t stopping; @@ -82,7 +83,7 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val) ssi_sd_state *s = SSI_SD(dev); /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data. */ - if (s->mode == SSI_SD_DATA_READ && val == 0x4d) { + if (s->mode == SSI_SD_DATA_READ && val == 0x4c) { s->mode = SSI_SD_CMD; /* There must be at least one byte delay before the card responds. */ s->stopping = 1; @@ -200,8 +201,9 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val) return 0xfe; case SSI_SD_DATA_READ: val = sdbus_read_byte(&s->sdbus); + s->read_bytes++; s->crc16 = crc_ccitt_false(s->crc16, (uint8_t *)&val, 1); - if (!sdbus_data_ready(&s->sdbus)) { + if (!sdbus_data_ready(&s->sdbus) || s->read_bytes == 512) { DPRINTF("Data read end\n"); s->mode = SSI_SD_DATA_CRC16; } @@ -212,7 +214,12 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val) s->response_pos++; if (s->response_pos == 2) { DPRINTF("CRC16 read end\n"); - s->mode = SSI_SD_CMD; + if (s->read_bytes == 512 && s->cmd != 17) { + s->mode = SSI_SD_DATA_START; + } else { + s->mode = SSI_SD_CMD; + } + s->read_bytes = 0; s->response_pos = 0; } return val; @@ -252,6 +259,7 @@ static const VMStateDescription vmstate_ssi_sd = { VMSTATE_UINT8_ARRAY(cmdarg, ssi_sd_state, 4), VMSTATE_UINT8_ARRAY(response, ssi_sd_state, 5), VMSTATE_UINT16(crc16, ssi_sd_state), + VMSTATE_INT32(read_bytes, ssi_sd_state), VMSTATE_INT32(arglen, ssi_sd_state), VMSTATE_INT32(response_pos, ssi_sd_state), VMSTATE_INT32(stopping, ssi_sd_state), @@ -304,6 +312,7 @@ static void ssi_sd_reset(DeviceState *dev) memset(s->cmdarg, 0, sizeof(s->cmdarg)); memset(s->response, 0, sizeof(s->response)); s->crc16 = 0; + s->read_bytes = 0; s->arglen = 0; s->response_pos = 0; s->stopping = 0; -- 2.25.1