mmc: sandbox: Add support for writing
This adds support writing to the sandbox mmc backed by an in-memory buffer. The unit test has been updated to test reading, writing, and erasing. I'm not sure what MMCs erase to; I picked 0, but if it's 0xFF then that can be easily changed. Signed-off-by: Sean Anderson <sean.anderson@seco.com> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
c28d5d704d
commit
3f6fb77175
|
@ -17,6 +17,17 @@ struct sandbox_mmc_plat {
|
||||||
struct mmc mmc;
|
struct mmc mmc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MMC_CSIZE 0
|
||||||
|
#define MMC_CMULT 8 /* 8 because the card is high-capacity */
|
||||||
|
#define MMC_BL_LEN_SHIFT 10
|
||||||
|
#define MMC_BL_LEN BIT(MMC_BL_LEN_SHIFT)
|
||||||
|
#define MMC_CAPACITY (((MMC_CSIZE + 1) << (MMC_CMULT + 2)) \
|
||||||
|
* MMC_BL_LEN) /* 1 MiB */
|
||||||
|
|
||||||
|
struct sandbox_mmc_priv {
|
||||||
|
u8 buf[MMC_CAPACITY];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sandbox_mmc_send_cmd() - Emulate SD commands
|
* sandbox_mmc_send_cmd() - Emulate SD commands
|
||||||
*
|
*
|
||||||
|
@ -26,6 +37,10 @@ struct sandbox_mmc_plat {
|
||||||
static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
|
static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
|
||||||
struct mmc_data *data)
|
struct mmc_data *data)
|
||||||
{
|
{
|
||||||
|
struct sandbox_mmc_priv *priv = dev_get_priv(dev);
|
||||||
|
struct mmc *mmc = mmc_get_mmc_dev(dev);
|
||||||
|
static ulong erase_start, erase_end;
|
||||||
|
|
||||||
switch (cmd->cmdidx) {
|
switch (cmd->cmdidx) {
|
||||||
case MMC_CMD_ALL_SEND_CID:
|
case MMC_CMD_ALL_SEND_CID:
|
||||||
memset(cmd->response, '\0', sizeof(cmd->response));
|
memset(cmd->response, '\0', sizeof(cmd->response));
|
||||||
|
@ -44,8 +59,9 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
|
||||||
break;
|
break;
|
||||||
case MMC_CMD_SEND_CSD:
|
case MMC_CMD_SEND_CSD:
|
||||||
cmd->response[0] = 0;
|
cmd->response[0] = 0;
|
||||||
cmd->response[1] = 10 << 16; /* 1 << block_len */
|
cmd->response[1] = (MMC_BL_LEN_SHIFT << 16) |
|
||||||
cmd->response[2] = 0;
|
((MMC_CSIZE >> 16) & 0x3f);
|
||||||
|
cmd->response[2] = (MMC_CSIZE & 0xffff) << 16;
|
||||||
cmd->response[3] = 0;
|
cmd->response[3] = 0;
|
||||||
break;
|
break;
|
||||||
case SD_CMD_SWITCH_FUNC: {
|
case SD_CMD_SWITCH_FUNC: {
|
||||||
|
@ -59,13 +75,27 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MMC_CMD_READ_SINGLE_BLOCK:
|
case MMC_CMD_READ_SINGLE_BLOCK:
|
||||||
memset(data->dest, '\0', data->blocksize);
|
|
||||||
break;
|
|
||||||
case MMC_CMD_READ_MULTIPLE_BLOCK:
|
case MMC_CMD_READ_MULTIPLE_BLOCK:
|
||||||
strcpy(data->dest, "this is a test");
|
memcpy(data->dest, &priv->buf[cmd->cmdarg * data->blocksize],
|
||||||
|
data->blocks * data->blocksize);
|
||||||
|
break;
|
||||||
|
case MMC_CMD_WRITE_SINGLE_BLOCK:
|
||||||
|
case MMC_CMD_WRITE_MULTIPLE_BLOCK:
|
||||||
|
memcpy(&priv->buf[cmd->cmdarg * data->blocksize], data->src,
|
||||||
|
data->blocks * data->blocksize);
|
||||||
break;
|
break;
|
||||||
case MMC_CMD_STOP_TRANSMISSION:
|
case MMC_CMD_STOP_TRANSMISSION:
|
||||||
break;
|
break;
|
||||||
|
case SD_CMD_ERASE_WR_BLK_START:
|
||||||
|
erase_start = cmd->cmdarg;
|
||||||
|
break;
|
||||||
|
case SD_CMD_ERASE_WR_BLK_END:
|
||||||
|
erase_end = cmd->cmdarg;
|
||||||
|
break;
|
||||||
|
case MMC_CMD_ERASE:
|
||||||
|
memset(&priv->buf[erase_start * mmc->write_bl_len], '\0',
|
||||||
|
(erase_end - erase_start + 1) * mmc->write_bl_len);
|
||||||
|
break;
|
||||||
case SD_CMD_APP_SEND_OP_COND:
|
case SD_CMD_APP_SEND_OP_COND:
|
||||||
cmd->response[0] = OCR_BUSY | OCR_HCS;
|
cmd->response[0] = OCR_BUSY | OCR_HCS;
|
||||||
cmd->response[1] = 0;
|
cmd->response[1] = 0;
|
||||||
|
@ -148,5 +178,6 @@ U_BOOT_DRIVER(mmc_sandbox) = {
|
||||||
.bind = sandbox_mmc_bind,
|
.bind = sandbox_mmc_bind,
|
||||||
.unbind = sandbox_mmc_unbind,
|
.unbind = sandbox_mmc_unbind,
|
||||||
.probe = sandbox_mmc_probe,
|
.probe = sandbox_mmc_probe,
|
||||||
.plat_auto = sizeof(struct sandbox_mmc_plat),
|
.priv_auto = sizeof(struct sandbox_mmc_priv),
|
||||||
|
.plat_auto = sizeof(struct sandbox_mmc_plat),
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,16 +29,25 @@ static int dm_test_mmc_blk(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
struct blk_desc *dev_desc;
|
struct blk_desc *dev_desc;
|
||||||
char cmp[1024];
|
int i;
|
||||||
|
char write[1024], read[1024];
|
||||||
|
|
||||||
ut_assertok(uclass_get_device(UCLASS_MMC, 0, &dev));
|
ut_assertok(uclass_get_device(UCLASS_MMC, 0, &dev));
|
||||||
ut_assertok(blk_get_device_by_str("mmc", "0", &dev_desc));
|
ut_assertok(blk_get_device_by_str("mmc", "0", &dev_desc));
|
||||||
|
|
||||||
/* Read a few blocks and look for the string we expect */
|
/* Write a few blocks and verify that we get the same data back */
|
||||||
ut_asserteq(512, dev_desc->blksz);
|
ut_asserteq(512, dev_desc->blksz);
|
||||||
memset(cmp, '\0', sizeof(cmp));
|
for (i = 0; i < sizeof(write); i++)
|
||||||
ut_asserteq(2, blk_dread(dev_desc, 0, 2, cmp));
|
write[i] = i;
|
||||||
ut_assertok(strcmp(cmp, "this is a test"));
|
ut_asserteq(2, blk_dwrite(dev_desc, 0, 2, write));
|
||||||
|
ut_asserteq(2, blk_dread(dev_desc, 0, 2, read));
|
||||||
|
ut_asserteq_mem(write, read, sizeof(write));
|
||||||
|
|
||||||
|
/* Now erase them */
|
||||||
|
memset(write, '\0', sizeof(write));
|
||||||
|
ut_asserteq(2, blk_derase(dev_desc, 0, 2));
|
||||||
|
ut_asserteq(2, blk_dread(dev_desc, 0, 2, read));
|
||||||
|
ut_asserteq_mem(write, read, sizeof(write));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue