1ffdb20beSMike Frysinger /* 2ffdb20beSMike Frysinger * Simulate a SPI flash 3ffdb20beSMike Frysinger * 4ffdb20beSMike Frysinger * Copyright (c) 2011-2013 The Chromium OS Authors. 5ffdb20beSMike Frysinger * See file CREDITS for list of people who contributed to this 6ffdb20beSMike Frysinger * project. 7ffdb20beSMike Frysinger * 8ffdb20beSMike Frysinger * Licensed under the GPL-2 or later. 9ffdb20beSMike Frysinger */ 10ffdb20beSMike Frysinger 11ffdb20beSMike Frysinger #include <common.h> 12ffdb20beSMike Frysinger #include <malloc.h> 13ffdb20beSMike Frysinger #include <spi.h> 14ffdb20beSMike Frysinger #include <os.h> 15ffdb20beSMike Frysinger 16ffdb20beSMike Frysinger #include <spi_flash.h> 17ffdb20beSMike Frysinger #include "sf_internal.h" 18ffdb20beSMike Frysinger 19ffdb20beSMike Frysinger #include <asm/getopt.h> 20ffdb20beSMike Frysinger #include <asm/spi.h> 21ffdb20beSMike Frysinger #include <asm/state.h> 22ffdb20beSMike Frysinger 23ffdb20beSMike Frysinger /* 24ffdb20beSMike Frysinger * The different states that our SPI flash transitions between. 25ffdb20beSMike Frysinger * We need to keep track of this across multiple xfer calls since 26ffdb20beSMike Frysinger * the SPI bus could possibly call down into us multiple times. 27ffdb20beSMike Frysinger */ 28ffdb20beSMike Frysinger enum sandbox_sf_state { 29ffdb20beSMike Frysinger SF_CMD, /* default state -- we're awaiting a command */ 30ffdb20beSMike Frysinger SF_ID, /* read the flash's (jedec) ID code */ 31ffdb20beSMike Frysinger SF_ADDR, /* processing the offset in the flash to read/etc... */ 32ffdb20beSMike Frysinger SF_READ, /* reading data from the flash */ 33ffdb20beSMike Frysinger SF_WRITE, /* writing data to the flash, i.e. page programming */ 34ffdb20beSMike Frysinger SF_ERASE, /* erase the flash */ 35ffdb20beSMike Frysinger SF_READ_STATUS, /* read the flash's status register */ 36ffdb20beSMike Frysinger SF_READ_STATUS1, /* read the flash's status register upper 8 bits*/ 37ffdb20beSMike Frysinger }; 38ffdb20beSMike Frysinger 39ffdb20beSMike Frysinger static const char *sandbox_sf_state_name(enum sandbox_sf_state state) 40ffdb20beSMike Frysinger { 41ffdb20beSMike Frysinger static const char * const states[] = { 42ffdb20beSMike Frysinger "CMD", "ID", "ADDR", "READ", "WRITE", "ERASE", "READ_STATUS", 43ffdb20beSMike Frysinger }; 44ffdb20beSMike Frysinger return states[state]; 45ffdb20beSMike Frysinger } 46ffdb20beSMike Frysinger 47ffdb20beSMike Frysinger /* Bits for the status register */ 48ffdb20beSMike Frysinger #define STAT_WIP (1 << 0) 49ffdb20beSMike Frysinger #define STAT_WEL (1 << 1) 50ffdb20beSMike Frysinger 51ffdb20beSMike Frysinger /* Assume all SPI flashes have 3 byte addresses since they do atm */ 52ffdb20beSMike Frysinger #define SF_ADDR_LEN 3 53ffdb20beSMike Frysinger 54*110bdee0SSimon Glass #define IDCODE_LEN 3 55ffdb20beSMike Frysinger 56ffdb20beSMike Frysinger /* Used to quickly bulk erase backing store */ 57ffdb20beSMike Frysinger static u8 sandbox_sf_0xff[0x1000]; 58ffdb20beSMike Frysinger 59ffdb20beSMike Frysinger /* Internal state data for each SPI flash */ 60ffdb20beSMike Frysinger struct sandbox_spi_flash { 61ffdb20beSMike Frysinger /* 62ffdb20beSMike Frysinger * As we receive data over the SPI bus, our flash transitions 63ffdb20beSMike Frysinger * between states. For example, we start off in the SF_CMD 64ffdb20beSMike Frysinger * state where the first byte tells us what operation to perform 65ffdb20beSMike Frysinger * (such as read or write the flash). But the operation itself 66ffdb20beSMike Frysinger * can go through a few states such as first reading in the 67ffdb20beSMike Frysinger * offset in the flash to perform the requested operation. 68ffdb20beSMike Frysinger * Thus "state" stores the exact state that our machine is in 69ffdb20beSMike Frysinger * while "cmd" stores the overall command we're processing. 70ffdb20beSMike Frysinger */ 71ffdb20beSMike Frysinger enum sandbox_sf_state state; 72ffdb20beSMike Frysinger uint cmd; 73*110bdee0SSimon Glass /* Erase size of current erase command */ 74*110bdee0SSimon Glass uint erase_size; 75ffdb20beSMike Frysinger /* Current position in the flash; used when reading/writing/etc... */ 76ffdb20beSMike Frysinger uint off; 77ffdb20beSMike Frysinger /* How many address bytes we've consumed */ 78ffdb20beSMike Frysinger uint addr_bytes, pad_addr_bytes; 79ffdb20beSMike Frysinger /* The current flash status (see STAT_XXX defines above) */ 80ffdb20beSMike Frysinger u16 status; 81ffdb20beSMike Frysinger /* Data describing the flash we're emulating */ 82*110bdee0SSimon Glass const struct spi_flash_params *data; 83ffdb20beSMike Frysinger /* The file on disk to serv up data from */ 84ffdb20beSMike Frysinger int fd; 85ffdb20beSMike Frysinger }; 86ffdb20beSMike Frysinger 87ffdb20beSMike Frysinger static int sandbox_sf_setup(void **priv, const char *spec) 88ffdb20beSMike Frysinger { 89ffdb20beSMike Frysinger /* spec = idcode:file */ 90ffdb20beSMike Frysinger struct sandbox_spi_flash *sbsf; 91ffdb20beSMike Frysinger const char *file; 92*110bdee0SSimon Glass size_t len, idname_len; 93*110bdee0SSimon Glass const struct spi_flash_params *data; 94ffdb20beSMike Frysinger 95ffdb20beSMike Frysinger file = strchr(spec, ':'); 96ffdb20beSMike Frysinger if (!file) { 97ffdb20beSMike Frysinger printf("sandbox_sf: unable to parse file\n"); 98ffdb20beSMike Frysinger goto error; 99ffdb20beSMike Frysinger } 100ffdb20beSMike Frysinger idname_len = file - spec; 101ffdb20beSMike Frysinger ++file; 102ffdb20beSMike Frysinger 103*110bdee0SSimon Glass for (data = spi_flash_params_table; data->name; data++) { 104ffdb20beSMike Frysinger len = strlen(data->name); 105ffdb20beSMike Frysinger if (idname_len != len) 106ffdb20beSMike Frysinger continue; 107ffdb20beSMike Frysinger if (!memcmp(spec, data->name, len)) 108ffdb20beSMike Frysinger break; 109ffdb20beSMike Frysinger } 110*110bdee0SSimon Glass if (!data->name) { 111ffdb20beSMike Frysinger printf("sandbox_sf: unknown flash '%*s'\n", (int)idname_len, 112ffdb20beSMike Frysinger spec); 113ffdb20beSMike Frysinger goto error; 114ffdb20beSMike Frysinger } 115ffdb20beSMike Frysinger 116ffdb20beSMike Frysinger if (sandbox_sf_0xff[0] == 0x00) 117ffdb20beSMike Frysinger memset(sandbox_sf_0xff, 0xff, sizeof(sandbox_sf_0xff)); 118ffdb20beSMike Frysinger 119ffdb20beSMike Frysinger sbsf = calloc(sizeof(*sbsf), 1); 120ffdb20beSMike Frysinger if (!sbsf) { 121ffdb20beSMike Frysinger printf("sandbox_sf: out of memory\n"); 122ffdb20beSMike Frysinger goto error; 123ffdb20beSMike Frysinger } 124ffdb20beSMike Frysinger 125ffdb20beSMike Frysinger sbsf->fd = os_open(file, 02); 126ffdb20beSMike Frysinger if (sbsf->fd == -1) { 127ffdb20beSMike Frysinger free(sbsf); 128ffdb20beSMike Frysinger printf("sandbox_sf: unable to open file '%s'\n", file); 129ffdb20beSMike Frysinger goto error; 130ffdb20beSMike Frysinger } 131ffdb20beSMike Frysinger 132ffdb20beSMike Frysinger sbsf->data = data; 133ffdb20beSMike Frysinger 134ffdb20beSMike Frysinger *priv = sbsf; 135ffdb20beSMike Frysinger return 0; 136ffdb20beSMike Frysinger 137ffdb20beSMike Frysinger error: 138ffdb20beSMike Frysinger return 1; 139ffdb20beSMike Frysinger } 140ffdb20beSMike Frysinger 141ffdb20beSMike Frysinger static void sandbox_sf_free(void *priv) 142ffdb20beSMike Frysinger { 143ffdb20beSMike Frysinger struct sandbox_spi_flash *sbsf = priv; 144ffdb20beSMike Frysinger 145ffdb20beSMike Frysinger os_close(sbsf->fd); 146ffdb20beSMike Frysinger free(sbsf); 147ffdb20beSMike Frysinger } 148ffdb20beSMike Frysinger 149ffdb20beSMike Frysinger static void sandbox_sf_cs_activate(void *priv) 150ffdb20beSMike Frysinger { 151ffdb20beSMike Frysinger struct sandbox_spi_flash *sbsf = priv; 152ffdb20beSMike Frysinger 153ffdb20beSMike Frysinger debug("sandbox_sf: CS activated; state is fresh!\n"); 154ffdb20beSMike Frysinger 155ffdb20beSMike Frysinger /* CS is asserted, so reset state */ 156ffdb20beSMike Frysinger sbsf->off = 0; 157ffdb20beSMike Frysinger sbsf->addr_bytes = 0; 158ffdb20beSMike Frysinger sbsf->pad_addr_bytes = 0; 159ffdb20beSMike Frysinger sbsf->state = SF_CMD; 160ffdb20beSMike Frysinger sbsf->cmd = SF_CMD; 161ffdb20beSMike Frysinger } 162ffdb20beSMike Frysinger 163ffdb20beSMike Frysinger static void sandbox_sf_cs_deactivate(void *priv) 164ffdb20beSMike Frysinger { 165ffdb20beSMike Frysinger debug("sandbox_sf: CS deactivated; cmd done processing!\n"); 166ffdb20beSMike Frysinger } 167ffdb20beSMike Frysinger 168ffdb20beSMike Frysinger /* Figure out what command this stream is telling us to do */ 169ffdb20beSMike Frysinger static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx, 170ffdb20beSMike Frysinger u8 *tx) 171ffdb20beSMike Frysinger { 172ffdb20beSMike Frysinger enum sandbox_sf_state oldstate = sbsf->state; 173ffdb20beSMike Frysinger 174ffdb20beSMike Frysinger /* We need to output a byte for the cmd byte we just ate */ 175ffdb20beSMike Frysinger sandbox_spi_tristate(tx, 1); 176ffdb20beSMike Frysinger 177ffdb20beSMike Frysinger sbsf->cmd = rx[0]; 178ffdb20beSMike Frysinger switch (sbsf->cmd) { 179ffdb20beSMike Frysinger case CMD_READ_ID: 180ffdb20beSMike Frysinger sbsf->state = SF_ID; 181ffdb20beSMike Frysinger sbsf->cmd = SF_ID; 182ffdb20beSMike Frysinger break; 183ffdb20beSMike Frysinger case CMD_READ_ARRAY_FAST: 184ffdb20beSMike Frysinger sbsf->pad_addr_bytes = 1; 185ffdb20beSMike Frysinger case CMD_READ_ARRAY_SLOW: 186ffdb20beSMike Frysinger case CMD_PAGE_PROGRAM: 187ffdb20beSMike Frysinger sbsf->state = SF_ADDR; 188ffdb20beSMike Frysinger break; 189ffdb20beSMike Frysinger case CMD_WRITE_DISABLE: 190ffdb20beSMike Frysinger debug(" write disabled\n"); 191ffdb20beSMike Frysinger sbsf->status &= ~STAT_WEL; 192ffdb20beSMike Frysinger break; 193ffdb20beSMike Frysinger case CMD_READ_STATUS: 194ffdb20beSMike Frysinger sbsf->state = SF_READ_STATUS; 195ffdb20beSMike Frysinger break; 196ffdb20beSMike Frysinger case CMD_READ_STATUS1: 197ffdb20beSMike Frysinger sbsf->state = SF_READ_STATUS1; 198ffdb20beSMike Frysinger break; 199ffdb20beSMike Frysinger case CMD_WRITE_ENABLE: 200ffdb20beSMike Frysinger debug(" write enabled\n"); 201ffdb20beSMike Frysinger sbsf->status |= STAT_WEL; 202ffdb20beSMike Frysinger break; 203ffdb20beSMike Frysinger default: { 204*110bdee0SSimon Glass int flags = sbsf->data->flags; 205ffdb20beSMike Frysinger 206*110bdee0SSimon Glass /* we only support erase here */ 207*110bdee0SSimon Glass if (sbsf->cmd == CMD_ERASE_CHIP) { 208*110bdee0SSimon Glass sbsf->erase_size = sbsf->data->sector_size * 209*110bdee0SSimon Glass sbsf->data->nr_sectors; 210*110bdee0SSimon Glass } else if (sbsf->cmd == CMD_ERASE_4K && (flags & SECT_4K)) { 211*110bdee0SSimon Glass sbsf->erase_size = 4 << 10; 212*110bdee0SSimon Glass } else if (sbsf->cmd == CMD_ERASE_32K && (flags & SECT_32K)) { 213*110bdee0SSimon Glass sbsf->erase_size = 32 << 10; 214*110bdee0SSimon Glass } else if (sbsf->cmd == CMD_ERASE_64K && 215*110bdee0SSimon Glass !(flags & (SECT_4K | SECT_32K))) { 216*110bdee0SSimon Glass sbsf->erase_size = 64 << 10; 217*110bdee0SSimon Glass } else { 218ffdb20beSMike Frysinger debug(" cmd unknown: %#x\n", sbsf->cmd); 219ffdb20beSMike Frysinger return 1; 220ffdb20beSMike Frysinger } 221*110bdee0SSimon Glass sbsf->state = SF_ADDR; 222*110bdee0SSimon Glass break; 223*110bdee0SSimon Glass } 224ffdb20beSMike Frysinger } 225ffdb20beSMike Frysinger 226ffdb20beSMike Frysinger if (oldstate != sbsf->state) 227ffdb20beSMike Frysinger debug(" cmd: transition to %s state\n", 228ffdb20beSMike Frysinger sandbox_sf_state_name(sbsf->state)); 229ffdb20beSMike Frysinger 230ffdb20beSMike Frysinger return 0; 231ffdb20beSMike Frysinger } 232ffdb20beSMike Frysinger 233ffdb20beSMike Frysinger int sandbox_erase_part(struct sandbox_spi_flash *sbsf, int size) 234ffdb20beSMike Frysinger { 235ffdb20beSMike Frysinger int todo; 236ffdb20beSMike Frysinger int ret; 237ffdb20beSMike Frysinger 238ffdb20beSMike Frysinger while (size > 0) { 239ffdb20beSMike Frysinger todo = min(size, sizeof(sandbox_sf_0xff)); 240ffdb20beSMike Frysinger ret = os_write(sbsf->fd, sandbox_sf_0xff, todo); 241ffdb20beSMike Frysinger if (ret != todo) 242ffdb20beSMike Frysinger return ret; 243ffdb20beSMike Frysinger size -= todo; 244ffdb20beSMike Frysinger } 245ffdb20beSMike Frysinger 246ffdb20beSMike Frysinger return 0; 247ffdb20beSMike Frysinger } 248ffdb20beSMike Frysinger 249ffdb20beSMike Frysinger static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx, 250ffdb20beSMike Frysinger uint bytes) 251ffdb20beSMike Frysinger { 252ffdb20beSMike Frysinger struct sandbox_spi_flash *sbsf = priv; 253ffdb20beSMike Frysinger uint cnt, pos = 0; 254ffdb20beSMike Frysinger int ret; 255ffdb20beSMike Frysinger 256ffdb20beSMike Frysinger debug("sandbox_sf: state:%x(%s) bytes:%u\n", sbsf->state, 257ffdb20beSMike Frysinger sandbox_sf_state_name(sbsf->state), bytes); 258ffdb20beSMike Frysinger 259ffdb20beSMike Frysinger if (sbsf->state == SF_CMD) { 260ffdb20beSMike Frysinger /* Figure out the initial state */ 261ffdb20beSMike Frysinger if (sandbox_sf_process_cmd(sbsf, rx, tx)) 262ffdb20beSMike Frysinger return 1; 263ffdb20beSMike Frysinger ++pos; 264ffdb20beSMike Frysinger } 265ffdb20beSMike Frysinger 266ffdb20beSMike Frysinger /* Process the remaining data */ 267ffdb20beSMike Frysinger while (pos < bytes) { 268ffdb20beSMike Frysinger switch (sbsf->state) { 269ffdb20beSMike Frysinger case SF_ID: { 270ffdb20beSMike Frysinger u8 id; 271ffdb20beSMike Frysinger 272ffdb20beSMike Frysinger debug(" id: off:%u tx:", sbsf->off); 273*110bdee0SSimon Glass if (sbsf->off < IDCODE_LEN) { 274*110bdee0SSimon Glass /* Extract correct byte from ID 0x00aabbcc */ 275*110bdee0SSimon Glass id = sbsf->data->jedec >> 276*110bdee0SSimon Glass (8 * (IDCODE_LEN - 1 - sbsf->off)); 277*110bdee0SSimon Glass } else { 278ffdb20beSMike Frysinger id = 0; 279*110bdee0SSimon Glass } 280*110bdee0SSimon Glass debug("%d %02x\n", sbsf->off, id); 281ffdb20beSMike Frysinger tx[pos++] = id; 282ffdb20beSMike Frysinger ++sbsf->off; 283ffdb20beSMike Frysinger break; 284ffdb20beSMike Frysinger } 285ffdb20beSMike Frysinger case SF_ADDR: 286ffdb20beSMike Frysinger debug(" addr: bytes:%u rx:%02x ", sbsf->addr_bytes, 287ffdb20beSMike Frysinger rx[pos]); 288ffdb20beSMike Frysinger 289ffdb20beSMike Frysinger if (sbsf->addr_bytes++ < SF_ADDR_LEN) 290ffdb20beSMike Frysinger sbsf->off = (sbsf->off << 8) | rx[pos]; 291ffdb20beSMike Frysinger debug("addr:%06x\n", sbsf->off); 292ffdb20beSMike Frysinger 293ffdb20beSMike Frysinger sandbox_spi_tristate(&tx[pos++], 1); 294ffdb20beSMike Frysinger 295ffdb20beSMike Frysinger /* See if we're done processing */ 296ffdb20beSMike Frysinger if (sbsf->addr_bytes < 297ffdb20beSMike Frysinger SF_ADDR_LEN + sbsf->pad_addr_bytes) 298ffdb20beSMike Frysinger break; 299ffdb20beSMike Frysinger 300ffdb20beSMike Frysinger /* Next state! */ 301ffdb20beSMike Frysinger if (os_lseek(sbsf->fd, sbsf->off, OS_SEEK_SET) < 0) { 302ffdb20beSMike Frysinger puts("sandbox_sf: os_lseek() failed"); 303ffdb20beSMike Frysinger return 1; 304ffdb20beSMike Frysinger } 305ffdb20beSMike Frysinger switch (sbsf->cmd) { 306ffdb20beSMike Frysinger case CMD_READ_ARRAY_FAST: 307ffdb20beSMike Frysinger case CMD_READ_ARRAY_SLOW: 308ffdb20beSMike Frysinger sbsf->state = SF_READ; 309ffdb20beSMike Frysinger break; 310ffdb20beSMike Frysinger case CMD_PAGE_PROGRAM: 311ffdb20beSMike Frysinger sbsf->state = SF_WRITE; 312ffdb20beSMike Frysinger break; 313ffdb20beSMike Frysinger default: 314ffdb20beSMike Frysinger /* assume erase state ... */ 315ffdb20beSMike Frysinger sbsf->state = SF_ERASE; 316ffdb20beSMike Frysinger goto case_sf_erase; 317ffdb20beSMike Frysinger } 318ffdb20beSMike Frysinger debug(" cmd: transition to %s state\n", 319ffdb20beSMike Frysinger sandbox_sf_state_name(sbsf->state)); 320ffdb20beSMike Frysinger break; 321ffdb20beSMike Frysinger case SF_READ: 322ffdb20beSMike Frysinger /* 323ffdb20beSMike Frysinger * XXX: need to handle exotic behavior: 324ffdb20beSMike Frysinger * - reading past end of device 325ffdb20beSMike Frysinger */ 326ffdb20beSMike Frysinger 327ffdb20beSMike Frysinger cnt = bytes - pos; 328ffdb20beSMike Frysinger debug(" tx: read(%u)\n", cnt); 329ffdb20beSMike Frysinger ret = os_read(sbsf->fd, tx + pos, cnt); 330ffdb20beSMike Frysinger if (ret < 0) { 331ffdb20beSMike Frysinger puts("sandbox_spi: os_read() failed\n"); 332ffdb20beSMike Frysinger return 1; 333ffdb20beSMike Frysinger } 334ffdb20beSMike Frysinger pos += ret; 335ffdb20beSMike Frysinger break; 336ffdb20beSMike Frysinger case SF_READ_STATUS: 337ffdb20beSMike Frysinger debug(" read status: %#x\n", sbsf->status); 338ffdb20beSMike Frysinger cnt = bytes - pos; 339ffdb20beSMike Frysinger memset(tx + pos, sbsf->status, cnt); 340ffdb20beSMike Frysinger pos += cnt; 341ffdb20beSMike Frysinger break; 342ffdb20beSMike Frysinger case SF_READ_STATUS1: 343ffdb20beSMike Frysinger debug(" read status: %#x\n", sbsf->status); 344ffdb20beSMike Frysinger cnt = bytes - pos; 345ffdb20beSMike Frysinger memset(tx + pos, sbsf->status >> 8, cnt); 346ffdb20beSMike Frysinger pos += cnt; 347ffdb20beSMike Frysinger break; 348ffdb20beSMike Frysinger case SF_WRITE: 349ffdb20beSMike Frysinger /* 350ffdb20beSMike Frysinger * XXX: need to handle exotic behavior: 351ffdb20beSMike Frysinger * - unaligned addresses 352ffdb20beSMike Frysinger * - more than a page (256) worth of data 353ffdb20beSMike Frysinger * - reading past end of device 354ffdb20beSMike Frysinger */ 355ffdb20beSMike Frysinger if (!(sbsf->status & STAT_WEL)) { 356ffdb20beSMike Frysinger puts("sandbox_sf: write enable not set before write\n"); 357ffdb20beSMike Frysinger goto done; 358ffdb20beSMike Frysinger } 359ffdb20beSMike Frysinger 360ffdb20beSMike Frysinger cnt = bytes - pos; 361ffdb20beSMike Frysinger debug(" rx: write(%u)\n", cnt); 362ffdb20beSMike Frysinger sandbox_spi_tristate(&tx[pos], cnt); 363ffdb20beSMike Frysinger ret = os_write(sbsf->fd, rx + pos, cnt); 364ffdb20beSMike Frysinger if (ret < 0) { 365ffdb20beSMike Frysinger puts("sandbox_spi: os_write() failed\n"); 366ffdb20beSMike Frysinger return 1; 367ffdb20beSMike Frysinger } 368ffdb20beSMike Frysinger pos += ret; 369ffdb20beSMike Frysinger sbsf->status &= ~STAT_WEL; 370ffdb20beSMike Frysinger break; 371ffdb20beSMike Frysinger case SF_ERASE: 372ffdb20beSMike Frysinger case_sf_erase: { 373ffdb20beSMike Frysinger if (!(sbsf->status & STAT_WEL)) { 374ffdb20beSMike Frysinger puts("sandbox_sf: write enable not set before erase\n"); 375ffdb20beSMike Frysinger goto done; 376ffdb20beSMike Frysinger } 377ffdb20beSMike Frysinger 378ffdb20beSMike Frysinger /* verify address is aligned */ 379*110bdee0SSimon Glass if (sbsf->off & (sbsf->erase_size - 1)) { 380ffdb20beSMike Frysinger debug(" sector erase: cmd:%#x needs align:%#x, but we got %#x\n", 381*110bdee0SSimon Glass sbsf->cmd, sbsf->erase_size, 382ffdb20beSMike Frysinger sbsf->off); 383ffdb20beSMike Frysinger sbsf->status &= ~STAT_WEL; 384ffdb20beSMike Frysinger goto done; 385ffdb20beSMike Frysinger } 386ffdb20beSMike Frysinger 387*110bdee0SSimon Glass debug(" sector erase addr: %u, size: %u\n", sbsf->off, 388*110bdee0SSimon Glass sbsf->erase_size); 389ffdb20beSMike Frysinger 390ffdb20beSMike Frysinger cnt = bytes - pos; 391ffdb20beSMike Frysinger sandbox_spi_tristate(&tx[pos], cnt); 392ffdb20beSMike Frysinger pos += cnt; 393ffdb20beSMike Frysinger 394ffdb20beSMike Frysinger /* 395ffdb20beSMike Frysinger * TODO(vapier@gentoo.org): latch WIP in status, and 396ffdb20beSMike Frysinger * delay before clearing it ? 397ffdb20beSMike Frysinger */ 398*110bdee0SSimon Glass ret = sandbox_erase_part(sbsf, sbsf->erase_size); 399ffdb20beSMike Frysinger sbsf->status &= ~STAT_WEL; 400ffdb20beSMike Frysinger if (ret) { 401ffdb20beSMike Frysinger debug("sandbox_sf: Erase failed\n"); 402ffdb20beSMike Frysinger goto done; 403ffdb20beSMike Frysinger } 404ffdb20beSMike Frysinger goto done; 405ffdb20beSMike Frysinger } 406ffdb20beSMike Frysinger default: 407ffdb20beSMike Frysinger debug(" ??? no idea what to do ???\n"); 408ffdb20beSMike Frysinger goto done; 409ffdb20beSMike Frysinger } 410ffdb20beSMike Frysinger } 411ffdb20beSMike Frysinger 412ffdb20beSMike Frysinger done: 413ffdb20beSMike Frysinger return pos == bytes ? 0 : 1; 414ffdb20beSMike Frysinger } 415ffdb20beSMike Frysinger 416ffdb20beSMike Frysinger static const struct sandbox_spi_emu_ops sandbox_sf_ops = { 417ffdb20beSMike Frysinger .setup = sandbox_sf_setup, 418ffdb20beSMike Frysinger .free = sandbox_sf_free, 419ffdb20beSMike Frysinger .cs_activate = sandbox_sf_cs_activate, 420ffdb20beSMike Frysinger .cs_deactivate = sandbox_sf_cs_deactivate, 421ffdb20beSMike Frysinger .xfer = sandbox_sf_xfer, 422ffdb20beSMike Frysinger }; 423ffdb20beSMike Frysinger 424ffdb20beSMike Frysinger static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state, 425ffdb20beSMike Frysinger const char *arg) 426ffdb20beSMike Frysinger { 427ffdb20beSMike Frysinger unsigned long bus, cs; 428ffdb20beSMike Frysinger const char *spec = sandbox_spi_parse_spec(arg, &bus, &cs); 429ffdb20beSMike Frysinger 430ffdb20beSMike Frysinger if (!spec) 431ffdb20beSMike Frysinger return 1; 432ffdb20beSMike Frysinger 433ffdb20beSMike Frysinger /* 434ffdb20beSMike Frysinger * It is safe to not make a copy of 'spec' because it comes from the 435ffdb20beSMike Frysinger * command line. 436ffdb20beSMike Frysinger * 437ffdb20beSMike Frysinger * TODO(sjg@chromium.org): It would be nice if we could parse the 438ffdb20beSMike Frysinger * spec here, but the problem is that no U-Boot init has been done 439ffdb20beSMike Frysinger * yet. Perhaps we can figure something out. 440ffdb20beSMike Frysinger */ 441ffdb20beSMike Frysinger state->spi[bus][cs].ops = &sandbox_sf_ops; 442ffdb20beSMike Frysinger state->spi[bus][cs].spec = spec; 443ffdb20beSMike Frysinger return 0; 444ffdb20beSMike Frysinger } 445ffdb20beSMike Frysinger SANDBOX_CMDLINE_OPT(spi_sf, 1, "connect a SPI flash: <bus>:<cs>:<id>:<file>"); 446