mirror of https://gitee.com/openkylin/qemu.git
hw/sd: ssi-sd: Support single block write
Add 2 more states for the block write operation. The SPI host needs to send a data start token to start the transfer, and the data block written to the card will be acknowledged by a data response token. Signed-off-by: Bin Meng <bin.meng@windriver.com> [PMD: Change VMState version id 6 -> 7] Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-Id: <20210128063035.15674-6-bmeng.cn@gmail.com> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
This commit is contained in:
parent
995731d3f7
commit
5020e3cb76
|
@ -43,6 +43,8 @@ typedef enum {
|
|||
SSI_SD_DATA_START,
|
||||
SSI_SD_DATA_READ,
|
||||
SSI_SD_DATA_CRC16,
|
||||
SSI_SD_DATA_WRITE,
|
||||
SSI_SD_SKIP_CRC16,
|
||||
} ssi_sd_mode;
|
||||
|
||||
struct ssi_sd_state {
|
||||
|
@ -53,6 +55,7 @@ struct ssi_sd_state {
|
|||
uint8_t response[5];
|
||||
uint16_t crc16;
|
||||
int32_t read_bytes;
|
||||
int32_t write_bytes;
|
||||
int32_t arglen;
|
||||
int32_t response_pos;
|
||||
int32_t stopping;
|
||||
|
@ -85,6 +88,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
|
|||
/* dummy value - don't care */
|
||||
#define SSI_DUMMY 0xff
|
||||
|
||||
/* data accepted */
|
||||
#define DATA_RESPONSE_ACCEPTED 0x05
|
||||
|
||||
static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
||||
{
|
||||
ssi_sd_state *s = SSI_SD(dev);
|
||||
|
@ -113,10 +119,17 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
|||
|
||||
switch (s->mode) {
|
||||
case SSI_SD_CMD:
|
||||
if (val == SSI_DUMMY) {
|
||||
switch (val) {
|
||||
case SSI_DUMMY:
|
||||
DPRINTF("NULL command\n");
|
||||
return SSI_DUMMY;
|
||||
break;
|
||||
case SSI_TOKEN_SINGLE:
|
||||
DPRINTF("Start write block\n");
|
||||
s->mode = SSI_SD_DATA_WRITE;
|
||||
return SSI_DUMMY;
|
||||
}
|
||||
|
||||
s->cmd = val & 0x3f;
|
||||
s->mode = SSI_SD_CMDARG;
|
||||
s->arglen = 0;
|
||||
|
@ -250,6 +263,27 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
|||
s->response_pos = 0;
|
||||
}
|
||||
return val;
|
||||
case SSI_SD_DATA_WRITE:
|
||||
sdbus_write_byte(&s->sdbus, val);
|
||||
s->write_bytes++;
|
||||
if (!sdbus_receive_ready(&s->sdbus) || s->write_bytes == 512) {
|
||||
DPRINTF("Data write end\n");
|
||||
s->mode = SSI_SD_SKIP_CRC16;
|
||||
s->response_pos = 0;
|
||||
}
|
||||
return val;
|
||||
case SSI_SD_SKIP_CRC16:
|
||||
/* we don't verify the crc16 */
|
||||
s->response_pos++;
|
||||
if (s->response_pos == 2) {
|
||||
DPRINTF("CRC16 receive end\n");
|
||||
s->mode = SSI_SD_RESPONSE;
|
||||
s->write_bytes = 0;
|
||||
s->arglen = 1;
|
||||
s->response[0] = DATA_RESPONSE_ACCEPTED;
|
||||
s->response_pos = 0;
|
||||
}
|
||||
return SSI_DUMMY;
|
||||
}
|
||||
/* Should never happen. */
|
||||
return SSI_DUMMY;
|
||||
|
@ -259,7 +293,7 @@ static int ssi_sd_post_load(void *opaque, int version_id)
|
|||
{
|
||||
ssi_sd_state *s = (ssi_sd_state *)opaque;
|
||||
|
||||
if (s->mode > SSI_SD_DATA_CRC16) {
|
||||
if (s->mode > SSI_SD_SKIP_CRC16) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (s->mode == SSI_SD_CMDARG &&
|
||||
|
@ -277,8 +311,8 @@ static int ssi_sd_post_load(void *opaque, int version_id)
|
|||
|
||||
static const VMStateDescription vmstate_ssi_sd = {
|
||||
.name = "ssi_sd",
|
||||
.version_id = 6,
|
||||
.minimum_version_id = 6,
|
||||
.version_id = 7,
|
||||
.minimum_version_id = 7,
|
||||
.post_load = ssi_sd_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT32(mode, ssi_sd_state),
|
||||
|
@ -287,6 +321,7 @@ static const VMStateDescription vmstate_ssi_sd = {
|
|||
VMSTATE_UINT8_ARRAY(response, ssi_sd_state, 5),
|
||||
VMSTATE_UINT16(crc16, ssi_sd_state),
|
||||
VMSTATE_INT32(read_bytes, ssi_sd_state),
|
||||
VMSTATE_INT32(write_bytes, ssi_sd_state),
|
||||
VMSTATE_INT32(arglen, ssi_sd_state),
|
||||
VMSTATE_INT32(response_pos, ssi_sd_state),
|
||||
VMSTATE_INT32(stopping, ssi_sd_state),
|
||||
|
@ -340,6 +375,7 @@ static void ssi_sd_reset(DeviceState *dev)
|
|||
memset(s->response, 0, sizeof(s->response));
|
||||
s->crc16 = 0;
|
||||
s->read_bytes = 0;
|
||||
s->write_bytes = 0;
|
||||
s->arglen = 0;
|
||||
s->response_pos = 0;
|
||||
s->stopping = 0;
|
||||
|
|
Loading…
Reference in New Issue