mirror of https://github.com/xemu-project/xemu.git
hw/sd: ssi-sd: Support multiple block write
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 token 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> Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-Id: <20210128063035.15674-7-bmeng.cn@gmail.com> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
This commit is contained in:
parent
5020e3cb76
commit
d56f3efa28
|
@ -4,6 +4,11 @@
|
||||||
* Copyright (c) 2007-2009 CodeSourcery.
|
* Copyright (c) 2007-2009 CodeSourcery.
|
||||||
* Written by Paul Brook
|
* Written by Paul Brook
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2021 Wind River Systems, Inc.
|
||||||
|
* Improved by Bin Meng <bin.meng@windriver.com>
|
||||||
|
*
|
||||||
|
* Validated with U-Boot v2021.01 and Linux v5.10 mmc_spi driver
|
||||||
|
*
|
||||||
* This code is licensed under the GNU GPL v2.
|
* This code is licensed under the GNU GPL v2.
|
||||||
*
|
*
|
||||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||||
|
@ -82,6 +87,10 @@ OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
|
||||||
#define SSI_SDR_ADDRESS_ERROR 0x2000
|
#define SSI_SDR_ADDRESS_ERROR 0x2000
|
||||||
#define SSI_SDR_PARAMETER_ERROR 0x4000
|
#define SSI_SDR_PARAMETER_ERROR 0x4000
|
||||||
|
|
||||||
|
/* multiple block write */
|
||||||
|
#define SSI_TOKEN_MULTI_WRITE 0xfc
|
||||||
|
/* terminate multiple block write */
|
||||||
|
#define SSI_TOKEN_STOP_TRAN 0xfd
|
||||||
/* single block read/write, multiple block read */
|
/* single block read/write, multiple block read */
|
||||||
#define SSI_TOKEN_SINGLE 0xfe
|
#define SSI_TOKEN_SINGLE 0xfe
|
||||||
|
|
||||||
|
@ -94,6 +103,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
|
||||||
static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
||||||
{
|
{
|
||||||
ssi_sd_state *s = SSI_SD(dev);
|
ssi_sd_state *s = SSI_SD(dev);
|
||||||
|
SDRequest request;
|
||||||
|
uint8_t longresp[16];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.
|
* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.
|
||||||
|
@ -125,8 +136,28 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
||||||
return SSI_DUMMY;
|
return SSI_DUMMY;
|
||||||
break;
|
break;
|
||||||
case SSI_TOKEN_SINGLE:
|
case SSI_TOKEN_SINGLE:
|
||||||
|
case SSI_TOKEN_MULTI_WRITE:
|
||||||
DPRINTF("Start write block\n");
|
DPRINTF("Start write block\n");
|
||||||
s->mode = SSI_SD_DATA_WRITE;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
return SSI_DUMMY;
|
return SSI_DUMMY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,8 +167,6 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
||||||
return SSI_DUMMY;
|
return SSI_DUMMY;
|
||||||
case SSI_SD_CMDARG:
|
case SSI_SD_CMDARG:
|
||||||
if (s->arglen == 4) {
|
if (s->arglen == 4) {
|
||||||
SDRequest request;
|
|
||||||
uint8_t longresp[16];
|
|
||||||
/* FIXME: Check CRC. */
|
/* FIXME: Check CRC. */
|
||||||
request.cmd = s->cmd;
|
request.cmd = s->cmd;
|
||||||
request.arg = ldl_be_p(s->cmdarg);
|
request.arg = ldl_be_p(s->cmdarg);
|
||||||
|
|
Loading…
Reference in New Issue