sandbox: Convert SPI flash emulation to use sf_params

At present sandbox has its own table of supported SPI flash chips. Now that
the SPI flash system is fully consolidated and has its own list, sandbox
should use that.

This enables us to expand the number of chips that sandbox supports.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
This commit is contained in:
Simon Glass 2014-09-15 06:33:19 -06:00
parent f9860cf081
commit 110bdee00f

View file

@ -51,46 +51,7 @@ static const char *sandbox_sf_state_name(enum sandbox_sf_state state)
/* Assume all SPI flashes have 3 byte addresses since they do atm */ /* Assume all SPI flashes have 3 byte addresses since they do atm */
#define SF_ADDR_LEN 3 #define SF_ADDR_LEN 3
struct sandbox_spi_flash_erase_commands { #define IDCODE_LEN 3
u8 cmd;
u32 size;
};
#define IDCODE_LEN 5
#define MAX_ERASE_CMDS 3
struct sandbox_spi_flash_data {
const char *name;
u8 idcode[IDCODE_LEN];
u32 size;
const struct sandbox_spi_flash_erase_commands
erase_cmds[MAX_ERASE_CMDS];
};
/* Structure describing all the flashes we know how to emulate */
static const struct sandbox_spi_flash_data sandbox_sf_flashes[] = {
{
"M25P16", { 0x20, 0x20, 0x15 }, (2 << 20),
{ /* erase commands */
{ 0xd8, (64 << 10), }, /* sector */
{ 0xc7, (2 << 20), }, /* bulk */
},
},
{
"W25Q32", { 0xef, 0x40, 0x16 }, (4 << 20),
{ /* erase commands */
{ 0x20, (4 << 10), }, /* 4KB */
{ 0xd8, (64 << 10), }, /* sector */
{ 0xc7, (4 << 20), }, /* bulk */
},
},
{
"W25Q128", { 0xef, 0x40, 0x18 }, (16 << 20),
{ /* erase commands */
{ 0x20, (4 << 10), }, /* 4KB */
{ 0xd8, (64 << 10), }, /* sector */
{ 0xc7, (16 << 20), }, /* bulk */
},
},
};
/* Used to quickly bulk erase backing store */ /* Used to quickly bulk erase backing store */
static u8 sandbox_sf_0xff[0x1000]; static u8 sandbox_sf_0xff[0x1000];
@ -109,7 +70,8 @@ struct sandbox_spi_flash {
*/ */
enum sandbox_sf_state state; enum sandbox_sf_state state;
uint cmd; uint cmd;
const void *cmd_data; /* Erase size of current erase command */
uint erase_size;
/* Current position in the flash; used when reading/writing/etc... */ /* Current position in the flash; used when reading/writing/etc... */
uint off; uint off;
/* How many address bytes we've consumed */ /* How many address bytes we've consumed */
@ -117,7 +79,7 @@ struct sandbox_spi_flash {
/* The current flash status (see STAT_XXX defines above) */ /* The current flash status (see STAT_XXX defines above) */
u16 status; u16 status;
/* Data describing the flash we're emulating */ /* Data describing the flash we're emulating */
const struct sandbox_spi_flash_data *data; const struct spi_flash_params *data;
/* The file on disk to serv up data from */ /* The file on disk to serv up data from */
int fd; int fd;
}; };
@ -127,8 +89,8 @@ static int sandbox_sf_setup(void **priv, const char *spec)
/* spec = idcode:file */ /* spec = idcode:file */
struct sandbox_spi_flash *sbsf; struct sandbox_spi_flash *sbsf;
const char *file; const char *file;
size_t i, len, idname_len; size_t len, idname_len;
const struct sandbox_spi_flash_data *data; const struct spi_flash_params *data;
file = strchr(spec, ':'); file = strchr(spec, ':');
if (!file) { if (!file) {
@ -138,15 +100,14 @@ static int sandbox_sf_setup(void **priv, const char *spec)
idname_len = file - spec; idname_len = file - spec;
++file; ++file;
for (i = 0; i < ARRAY_SIZE(sandbox_sf_flashes); ++i) { for (data = spi_flash_params_table; data->name; data++) {
data = &sandbox_sf_flashes[i];
len = strlen(data->name); len = strlen(data->name);
if (idname_len != len) if (idname_len != len)
continue; continue;
if (!memcmp(spec, data->name, len)) if (!memcmp(spec, data->name, len))
break; break;
} }
if (i == ARRAY_SIZE(sandbox_sf_flashes)) { if (!data->name) {
printf("sandbox_sf: unknown flash '%*s'\n", (int)idname_len, printf("sandbox_sf: unknown flash '%*s'\n", (int)idname_len,
spec); spec);
goto error; goto error;
@ -223,7 +184,6 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
sbsf->pad_addr_bytes = 1; sbsf->pad_addr_bytes = 1;
case CMD_READ_ARRAY_SLOW: case CMD_READ_ARRAY_SLOW:
case CMD_PAGE_PROGRAM: case CMD_PAGE_PROGRAM:
state_addr:
sbsf->state = SF_ADDR; sbsf->state = SF_ADDR;
break; break;
case CMD_WRITE_DISABLE: case CMD_WRITE_DISABLE:
@ -241,24 +201,25 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
sbsf->status |= STAT_WEL; sbsf->status |= STAT_WEL;
break; break;
default: { default: {
size_t i; int flags = sbsf->data->flags;
/* handle erase commands first */ /* we only support erase here */
for (i = 0; i < MAX_ERASE_CMDS; ++i) { if (sbsf->cmd == CMD_ERASE_CHIP) {
const struct sandbox_spi_flash_erase_commands * sbsf->erase_size = sbsf->data->sector_size *
erase_cmd = &sbsf->data->erase_cmds[i]; sbsf->data->nr_sectors;
} else if (sbsf->cmd == CMD_ERASE_4K && (flags & SECT_4K)) {
if (erase_cmd->cmd == 0x00) sbsf->erase_size = 4 << 10;
continue; } else if (sbsf->cmd == CMD_ERASE_32K && (flags & SECT_32K)) {
if (sbsf->cmd != erase_cmd->cmd) sbsf->erase_size = 32 << 10;
continue; } else if (sbsf->cmd == CMD_ERASE_64K &&
!(flags & (SECT_4K | SECT_32K))) {
sbsf->cmd_data = erase_cmd; sbsf->erase_size = 64 << 10;
goto state_addr; } else {
debug(" cmd unknown: %#x\n", sbsf->cmd);
return 1;
} }
sbsf->state = SF_ADDR;
debug(" cmd unknown: %#x\n", sbsf->cmd); break;
return 1;
} }
} }
@ -309,11 +270,14 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
u8 id; u8 id;
debug(" id: off:%u tx:", sbsf->off); debug(" id: off:%u tx:", sbsf->off);
if (sbsf->off < IDCODE_LEN) if (sbsf->off < IDCODE_LEN) {
id = sbsf->data->idcode[sbsf->off]; /* Extract correct byte from ID 0x00aabbcc */
else id = sbsf->data->jedec >>
(8 * (IDCODE_LEN - 1 - sbsf->off));
} else {
id = 0; id = 0;
debug("%02x\n", id); }
debug("%d %02x\n", sbsf->off, id);
tx[pos++] = id; tx[pos++] = id;
++sbsf->off; ++sbsf->off;
break; break;
@ -406,24 +370,22 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
break; break;
case SF_ERASE: case SF_ERASE:
case_sf_erase: { case_sf_erase: {
const struct sandbox_spi_flash_erase_commands *
erase_cmd = sbsf->cmd_data;
if (!(sbsf->status & STAT_WEL)) { if (!(sbsf->status & STAT_WEL)) {
puts("sandbox_sf: write enable not set before erase\n"); puts("sandbox_sf: write enable not set before erase\n");
goto done; goto done;
} }
/* verify address is aligned */ /* verify address is aligned */
if (sbsf->off & (erase_cmd->size - 1)) { if (sbsf->off & (sbsf->erase_size - 1)) {
debug(" sector erase: cmd:%#x needs align:%#x, but we got %#x\n", debug(" sector erase: cmd:%#x needs align:%#x, but we got %#x\n",
erase_cmd->cmd, erase_cmd->size, sbsf->cmd, sbsf->erase_size,
sbsf->off); sbsf->off);
sbsf->status &= ~STAT_WEL; sbsf->status &= ~STAT_WEL;
goto done; goto done;
} }
debug(" sector erase addr: %u\n", sbsf->off); debug(" sector erase addr: %u, size: %u\n", sbsf->off,
sbsf->erase_size);
cnt = bytes - pos; cnt = bytes - pos;
sandbox_spi_tristate(&tx[pos], cnt); sandbox_spi_tristate(&tx[pos], cnt);
@ -433,7 +395,7 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
* TODO(vapier@gentoo.org): latch WIP in status, and * TODO(vapier@gentoo.org): latch WIP in status, and
* delay before clearing it ? * delay before clearing it ?
*/ */
ret = sandbox_erase_part(sbsf, erase_cmd->size); ret = sandbox_erase_part(sbsf, sbsf->erase_size);
sbsf->status &= ~STAT_WEL; sbsf->status &= ~STAT_WEL;
if (ret) { if (ret) {
debug("sandbox_sf: Erase failed\n"); debug("sandbox_sf: Erase failed\n");