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> 12b6c2956dSSimon Glass #include <dm.h> 13ffdb20beSMike Frysinger #include <malloc.h> 14ffdb20beSMike Frysinger #include <spi.h> 15ffdb20beSMike Frysinger #include <os.h> 16ffdb20beSMike Frysinger 17ffdb20beSMike Frysinger #include <spi_flash.h> 18ffdb20beSMike Frysinger #include "sf_internal.h" 19ffdb20beSMike Frysinger 20ffdb20beSMike Frysinger #include <asm/getopt.h> 21ffdb20beSMike Frysinger #include <asm/spi.h> 22ffdb20beSMike Frysinger #include <asm/state.h> 23b6c2956dSSimon Glass #include <dm/device-internal.h> 24b6c2956dSSimon Glass #include <dm/lists.h> 25b6c2956dSSimon Glass #include <dm/uclass-internal.h> 26b6c2956dSSimon Glass 27b6c2956dSSimon Glass DECLARE_GLOBAL_DATA_PTR; 28ffdb20beSMike Frysinger 29ffdb20beSMike Frysinger /* 30ffdb20beSMike Frysinger * The different states that our SPI flash transitions between. 31ffdb20beSMike Frysinger * We need to keep track of this across multiple xfer calls since 32ffdb20beSMike Frysinger * the SPI bus could possibly call down into us multiple times. 33ffdb20beSMike Frysinger */ 34ffdb20beSMike Frysinger enum sandbox_sf_state { 35ffdb20beSMike Frysinger SF_CMD, /* default state -- we're awaiting a command */ 36ffdb20beSMike Frysinger SF_ID, /* read the flash's (jedec) ID code */ 37ffdb20beSMike Frysinger SF_ADDR, /* processing the offset in the flash to read/etc... */ 38ffdb20beSMike Frysinger SF_READ, /* reading data from the flash */ 39ffdb20beSMike Frysinger SF_WRITE, /* writing data to the flash, i.e. page programming */ 40ffdb20beSMike Frysinger SF_ERASE, /* erase the flash */ 41ffdb20beSMike Frysinger SF_READ_STATUS, /* read the flash's status register */ 42ffdb20beSMike Frysinger SF_READ_STATUS1, /* read the flash's status register upper 8 bits*/ 43b6c2956dSSimon Glass SF_WRITE_STATUS, /* write the flash's status register */ 44ffdb20beSMike Frysinger }; 45ffdb20beSMike Frysinger 46ffdb20beSMike Frysinger static const char *sandbox_sf_state_name(enum sandbox_sf_state state) 47ffdb20beSMike Frysinger { 48ffdb20beSMike Frysinger static const char * const states[] = { 49ffdb20beSMike Frysinger "CMD", "ID", "ADDR", "READ", "WRITE", "ERASE", "READ_STATUS", 50b6c2956dSSimon Glass "READ_STATUS1", "WRITE_STATUS", 51ffdb20beSMike Frysinger }; 52ffdb20beSMike Frysinger return states[state]; 53ffdb20beSMike Frysinger } 54ffdb20beSMike Frysinger 55ffdb20beSMike Frysinger /* Bits for the status register */ 56ffdb20beSMike Frysinger #define STAT_WIP (1 << 0) 57ffdb20beSMike Frysinger #define STAT_WEL (1 << 1) 58ffdb20beSMike Frysinger 59ffdb20beSMike Frysinger /* Assume all SPI flashes have 3 byte addresses since they do atm */ 60ffdb20beSMike Frysinger #define SF_ADDR_LEN 3 61ffdb20beSMike Frysinger 62110bdee0SSimon Glass #define IDCODE_LEN 3 63ffdb20beSMike Frysinger 64ffdb20beSMike Frysinger /* Used to quickly bulk erase backing store */ 65ffdb20beSMike Frysinger static u8 sandbox_sf_0xff[0x1000]; 66ffdb20beSMike Frysinger 67ffdb20beSMike Frysinger /* Internal state data for each SPI flash */ 68ffdb20beSMike Frysinger struct sandbox_spi_flash { 69b6c2956dSSimon Glass unsigned int cs; /* Chip select we are attached to */ 70ffdb20beSMike Frysinger /* 71ffdb20beSMike Frysinger * As we receive data over the SPI bus, our flash transitions 72ffdb20beSMike Frysinger * between states. For example, we start off in the SF_CMD 73ffdb20beSMike Frysinger * state where the first byte tells us what operation to perform 74ffdb20beSMike Frysinger * (such as read or write the flash). But the operation itself 75ffdb20beSMike Frysinger * can go through a few states such as first reading in the 76ffdb20beSMike Frysinger * offset in the flash to perform the requested operation. 77ffdb20beSMike Frysinger * Thus "state" stores the exact state that our machine is in 78ffdb20beSMike Frysinger * while "cmd" stores the overall command we're processing. 79ffdb20beSMike Frysinger */ 80ffdb20beSMike Frysinger enum sandbox_sf_state state; 81ffdb20beSMike Frysinger uint cmd; 82110bdee0SSimon Glass /* Erase size of current erase command */ 83110bdee0SSimon Glass uint erase_size; 84ffdb20beSMike Frysinger /* Current position in the flash; used when reading/writing/etc... */ 85ffdb20beSMike Frysinger uint off; 86ffdb20beSMike Frysinger /* How many address bytes we've consumed */ 87ffdb20beSMike Frysinger uint addr_bytes, pad_addr_bytes; 88ffdb20beSMike Frysinger /* The current flash status (see STAT_XXX defines above) */ 89ffdb20beSMike Frysinger u16 status; 90ffdb20beSMike Frysinger /* Data describing the flash we're emulating */ 91f790ca7cSJagan Teki const struct spi_flash_info *data; 92ffdb20beSMike Frysinger /* The file on disk to serv up data from */ 93ffdb20beSMike Frysinger int fd; 94ffdb20beSMike Frysinger }; 95ffdb20beSMike Frysinger 96b6c2956dSSimon Glass struct sandbox_spi_flash_plat_data { 97b6c2956dSSimon Glass const char *filename; 98b6c2956dSSimon Glass const char *device_name; 99b6c2956dSSimon Glass int bus; 100b6c2956dSSimon Glass int cs; 101b6c2956dSSimon Glass }; 102b6c2956dSSimon Glass 103b6c2956dSSimon Glass /** 104b6c2956dSSimon Glass * This is a very strange probe function. If it has platform data (which may 105b6c2956dSSimon Glass * have come from the device tree) then this function gets the filename and 106b6c2956dSSimon Glass * device type from there. Failing that it looks at the command line 107b6c2956dSSimon Glass * parameter. 108b6c2956dSSimon Glass */ 109b6c2956dSSimon Glass static int sandbox_sf_probe(struct udevice *dev) 110ffdb20beSMike Frysinger { 111ffdb20beSMike Frysinger /* spec = idcode:file */ 112b6c2956dSSimon Glass struct sandbox_spi_flash *sbsf = dev_get_priv(dev); 113ffdb20beSMike Frysinger const char *file; 114110bdee0SSimon Glass size_t len, idname_len; 115f790ca7cSJagan Teki const struct spi_flash_info *data; 116b6c2956dSSimon Glass struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev); 117b6c2956dSSimon Glass struct sandbox_state *state = state_get_current(); 118b6c2956dSSimon Glass struct udevice *bus = dev->parent; 119b6c2956dSSimon Glass const char *spec = NULL; 120b6c2956dSSimon Glass int ret = 0; 121b6c2956dSSimon Glass int cs = -1; 122b6c2956dSSimon Glass int i; 123b6c2956dSSimon Glass 124b6c2956dSSimon Glass debug("%s: bus %d, looking for emul=%p: ", __func__, bus->seq, dev); 125b6c2956dSSimon Glass if (bus->seq >= 0 && bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS) { 126b6c2956dSSimon Glass for (i = 0; i < CONFIG_SANDBOX_SPI_MAX_CS; i++) { 127b6c2956dSSimon Glass if (state->spi[bus->seq][i].emul == dev) 128b6c2956dSSimon Glass cs = i; 129b6c2956dSSimon Glass } 130b6c2956dSSimon Glass } 131b6c2956dSSimon Glass if (cs == -1) { 132832adb21SSimon Glass printf("Error: Unknown chip select for device '%s'\n", 133b6c2956dSSimon Glass dev->name); 134b6c2956dSSimon Glass return -EINVAL; 135b6c2956dSSimon Glass } 136b6c2956dSSimon Glass debug("found at cs %d\n", cs); 137b6c2956dSSimon Glass 138b6c2956dSSimon Glass if (!pdata->filename) { 139b6c2956dSSimon Glass struct sandbox_state *state = state_get_current(); 140b6c2956dSSimon Glass 141b6c2956dSSimon Glass assert(bus->seq != -1); 142b6c2956dSSimon Glass if (bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS) 143b6c2956dSSimon Glass spec = state->spi[bus->seq][cs].spec; 1441603bf3cSSimon Glass if (!spec) { 14520f655daSSimon Glass debug("%s: No spec found for bus %d, cs %d\n", 14620f655daSSimon Glass __func__, bus->seq, cs); 1471603bf3cSSimon Glass ret = -ENOENT; 1481603bf3cSSimon Glass goto error; 1491603bf3cSSimon Glass } 150ffdb20beSMike Frysinger 151ffdb20beSMike Frysinger file = strchr(spec, ':'); 152ffdb20beSMike Frysinger if (!file) { 15320f655daSSimon Glass printf("%s: unable to parse file\n", __func__); 154b6c2956dSSimon Glass ret = -EINVAL; 155ffdb20beSMike Frysinger goto error; 156ffdb20beSMike Frysinger } 157ffdb20beSMike Frysinger idname_len = file - spec; 158b6c2956dSSimon Glass pdata->filename = file + 1; 159b6c2956dSSimon Glass pdata->device_name = spec; 160ffdb20beSMike Frysinger ++file; 161b6c2956dSSimon Glass } else { 162b6c2956dSSimon Glass spec = strchr(pdata->device_name, ','); 163b6c2956dSSimon Glass if (spec) 164b6c2956dSSimon Glass spec++; 165b6c2956dSSimon Glass else 166b6c2956dSSimon Glass spec = pdata->device_name; 167b6c2956dSSimon Glass idname_len = strlen(spec); 168b6c2956dSSimon Glass } 169b6c2956dSSimon Glass debug("%s: device='%s'\n", __func__, spec); 170ffdb20beSMike Frysinger 171f790ca7cSJagan Teki for (data = spi_flash_ids; data->name; data++) { 172ffdb20beSMike Frysinger len = strlen(data->name); 173ffdb20beSMike Frysinger if (idname_len != len) 174ffdb20beSMike Frysinger continue; 175b6c2956dSSimon Glass if (!strncasecmp(spec, data->name, len)) 176ffdb20beSMike Frysinger break; 177ffdb20beSMike Frysinger } 178110bdee0SSimon Glass if (!data->name) { 17920f655daSSimon Glass printf("%s: unknown flash '%*s'\n", __func__, (int)idname_len, 180ffdb20beSMike Frysinger spec); 181b6c2956dSSimon Glass ret = -EINVAL; 182ffdb20beSMike Frysinger goto error; 183ffdb20beSMike Frysinger } 184ffdb20beSMike Frysinger 185ffdb20beSMike Frysinger if (sandbox_sf_0xff[0] == 0x00) 186ffdb20beSMike Frysinger memset(sandbox_sf_0xff, 0xff, sizeof(sandbox_sf_0xff)); 187ffdb20beSMike Frysinger 188b6c2956dSSimon Glass sbsf->fd = os_open(pdata->filename, 02); 189ffdb20beSMike Frysinger if (sbsf->fd == -1) { 19020f655daSSimon Glass printf("%s: unable to open file '%s'\n", __func__, 191b6c2956dSSimon Glass pdata->filename); 192b6c2956dSSimon Glass ret = -EIO; 193ffdb20beSMike Frysinger goto error; 194ffdb20beSMike Frysinger } 195ffdb20beSMike Frysinger 196ffdb20beSMike Frysinger sbsf->data = data; 197b6c2956dSSimon Glass sbsf->cs = cs; 198ffdb20beSMike Frysinger 199ffdb20beSMike Frysinger return 0; 200ffdb20beSMike Frysinger 201ffdb20beSMike Frysinger error: 2021603bf3cSSimon Glass debug("%s: Got error %d\n", __func__, ret); 203b6c2956dSSimon Glass return ret; 204ffdb20beSMike Frysinger } 205ffdb20beSMike Frysinger 206b6c2956dSSimon Glass static int sandbox_sf_remove(struct udevice *dev) 207ffdb20beSMike Frysinger { 208b6c2956dSSimon Glass struct sandbox_spi_flash *sbsf = dev_get_priv(dev); 209ffdb20beSMike Frysinger 210ffdb20beSMike Frysinger os_close(sbsf->fd); 211b6c2956dSSimon Glass 212b6c2956dSSimon Glass return 0; 213ffdb20beSMike Frysinger } 214ffdb20beSMike Frysinger 215b6c2956dSSimon Glass static void sandbox_sf_cs_activate(struct udevice *dev) 216ffdb20beSMike Frysinger { 217b6c2956dSSimon Glass struct sandbox_spi_flash *sbsf = dev_get_priv(dev); 218ffdb20beSMike Frysinger 219ffdb20beSMike Frysinger debug("sandbox_sf: CS activated; state is fresh!\n"); 220ffdb20beSMike Frysinger 221ffdb20beSMike Frysinger /* CS is asserted, so reset state */ 222ffdb20beSMike Frysinger sbsf->off = 0; 223ffdb20beSMike Frysinger sbsf->addr_bytes = 0; 224ffdb20beSMike Frysinger sbsf->pad_addr_bytes = 0; 225ffdb20beSMike Frysinger sbsf->state = SF_CMD; 226ffdb20beSMike Frysinger sbsf->cmd = SF_CMD; 227ffdb20beSMike Frysinger } 228ffdb20beSMike Frysinger 229b6c2956dSSimon Glass static void sandbox_sf_cs_deactivate(struct udevice *dev) 230ffdb20beSMike Frysinger { 231ffdb20beSMike Frysinger debug("sandbox_sf: CS deactivated; cmd done processing!\n"); 232ffdb20beSMike Frysinger } 233ffdb20beSMike Frysinger 234b6c2956dSSimon Glass /* 235b6c2956dSSimon Glass * There are times when the data lines are allowed to tristate. What 236b6c2956dSSimon Glass * is actually sensed on the line depends on the hardware. It could 237b6c2956dSSimon Glass * always be 0xFF/0x00 (if there are pull ups/downs), or things could 238b6c2956dSSimon Glass * float and so we'd get garbage back. This func encapsulates that 239b6c2956dSSimon Glass * scenario so we can worry about the details here. 240b6c2956dSSimon Glass */ 241b6c2956dSSimon Glass static void sandbox_spi_tristate(u8 *buf, uint len) 242b6c2956dSSimon Glass { 243b6c2956dSSimon Glass /* XXX: make this into a user config option ? */ 244b6c2956dSSimon Glass memset(buf, 0xff, len); 245b6c2956dSSimon Glass } 246b6c2956dSSimon Glass 247ffdb20beSMike Frysinger /* Figure out what command this stream is telling us to do */ 248ffdb20beSMike Frysinger static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx, 249ffdb20beSMike Frysinger u8 *tx) 250ffdb20beSMike Frysinger { 251ffdb20beSMike Frysinger enum sandbox_sf_state oldstate = sbsf->state; 252ffdb20beSMike Frysinger 253ffdb20beSMike Frysinger /* We need to output a byte for the cmd byte we just ate */ 254b6c2956dSSimon Glass if (tx) 255ffdb20beSMike Frysinger sandbox_spi_tristate(tx, 1); 256ffdb20beSMike Frysinger 257ffdb20beSMike Frysinger sbsf->cmd = rx[0]; 258ffdb20beSMike Frysinger switch (sbsf->cmd) { 259ffdb20beSMike Frysinger case CMD_READ_ID: 260ffdb20beSMike Frysinger sbsf->state = SF_ID; 261ffdb20beSMike Frysinger sbsf->cmd = SF_ID; 262ffdb20beSMike Frysinger break; 263ffdb20beSMike Frysinger case CMD_READ_ARRAY_FAST: 264ffdb20beSMike Frysinger sbsf->pad_addr_bytes = 1; 265ffdb20beSMike Frysinger case CMD_READ_ARRAY_SLOW: 266ffdb20beSMike Frysinger case CMD_PAGE_PROGRAM: 267ffdb20beSMike Frysinger sbsf->state = SF_ADDR; 268ffdb20beSMike Frysinger break; 269ffdb20beSMike Frysinger case CMD_WRITE_DISABLE: 270ffdb20beSMike Frysinger debug(" write disabled\n"); 271ffdb20beSMike Frysinger sbsf->status &= ~STAT_WEL; 272ffdb20beSMike Frysinger break; 273ffdb20beSMike Frysinger case CMD_READ_STATUS: 274ffdb20beSMike Frysinger sbsf->state = SF_READ_STATUS; 275ffdb20beSMike Frysinger break; 276ffdb20beSMike Frysinger case CMD_READ_STATUS1: 277ffdb20beSMike Frysinger sbsf->state = SF_READ_STATUS1; 278ffdb20beSMike Frysinger break; 279ffdb20beSMike Frysinger case CMD_WRITE_ENABLE: 280ffdb20beSMike Frysinger debug(" write enabled\n"); 281ffdb20beSMike Frysinger sbsf->status |= STAT_WEL; 282ffdb20beSMike Frysinger break; 283b6c2956dSSimon Glass case CMD_WRITE_STATUS: 284b6c2956dSSimon Glass sbsf->state = SF_WRITE_STATUS; 285b6c2956dSSimon Glass break; 286ffdb20beSMike Frysinger default: { 287110bdee0SSimon Glass int flags = sbsf->data->flags; 288ffdb20beSMike Frysinger 289110bdee0SSimon Glass /* we only support erase here */ 290110bdee0SSimon Glass if (sbsf->cmd == CMD_ERASE_CHIP) { 291110bdee0SSimon Glass sbsf->erase_size = sbsf->data->sector_size * 292eccb6be0SJagan Teki sbsf->data->n_sectors; 293110bdee0SSimon Glass } else if (sbsf->cmd == CMD_ERASE_4K && (flags & SECT_4K)) { 294110bdee0SSimon Glass sbsf->erase_size = 4 << 10; 295ddc2dfbbSJagan Teki } else if (sbsf->cmd == CMD_ERASE_64K && !(flags & SECT_4K)) { 296110bdee0SSimon Glass sbsf->erase_size = 64 << 10; 297110bdee0SSimon Glass } else { 298ffdb20beSMike Frysinger debug(" cmd unknown: %#x\n", sbsf->cmd); 299b6c2956dSSimon Glass return -EIO; 300ffdb20beSMike Frysinger } 301110bdee0SSimon Glass sbsf->state = SF_ADDR; 302110bdee0SSimon Glass break; 303110bdee0SSimon Glass } 304ffdb20beSMike Frysinger } 305ffdb20beSMike Frysinger 306ffdb20beSMike Frysinger if (oldstate != sbsf->state) 307ffdb20beSMike Frysinger debug(" cmd: transition to %s state\n", 308ffdb20beSMike Frysinger sandbox_sf_state_name(sbsf->state)); 309ffdb20beSMike Frysinger 310ffdb20beSMike Frysinger return 0; 311ffdb20beSMike Frysinger } 312ffdb20beSMike Frysinger 313ffdb20beSMike Frysinger int sandbox_erase_part(struct sandbox_spi_flash *sbsf, int size) 314ffdb20beSMike Frysinger { 315ffdb20beSMike Frysinger int todo; 316ffdb20beSMike Frysinger int ret; 317ffdb20beSMike Frysinger 318ffdb20beSMike Frysinger while (size > 0) { 319b4141195SMasahiro Yamada todo = min(size, (int)sizeof(sandbox_sf_0xff)); 320ffdb20beSMike Frysinger ret = os_write(sbsf->fd, sandbox_sf_0xff, todo); 321ffdb20beSMike Frysinger if (ret != todo) 322ffdb20beSMike Frysinger return ret; 323ffdb20beSMike Frysinger size -= todo; 324ffdb20beSMike Frysinger } 325ffdb20beSMike Frysinger 326ffdb20beSMike Frysinger return 0; 327ffdb20beSMike Frysinger } 328ffdb20beSMike Frysinger 329b6c2956dSSimon Glass static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, 330b6c2956dSSimon Glass const void *rxp, void *txp, unsigned long flags) 331ffdb20beSMike Frysinger { 332b6c2956dSSimon Glass struct sandbox_spi_flash *sbsf = dev_get_priv(dev); 333b6c2956dSSimon Glass const uint8_t *rx = rxp; 334b6c2956dSSimon Glass uint8_t *tx = txp; 335ffdb20beSMike Frysinger uint cnt, pos = 0; 336b6c2956dSSimon Glass int bytes = bitlen / 8; 337ffdb20beSMike Frysinger int ret; 338ffdb20beSMike Frysinger 339ffdb20beSMike Frysinger debug("sandbox_sf: state:%x(%s) bytes:%u\n", sbsf->state, 340ffdb20beSMike Frysinger sandbox_sf_state_name(sbsf->state), bytes); 341ffdb20beSMike Frysinger 342b6c2956dSSimon Glass if ((flags & SPI_XFER_BEGIN)) 343b6c2956dSSimon Glass sandbox_sf_cs_activate(dev); 344b6c2956dSSimon Glass 345ffdb20beSMike Frysinger if (sbsf->state == SF_CMD) { 346ffdb20beSMike Frysinger /* Figure out the initial state */ 347b6c2956dSSimon Glass ret = sandbox_sf_process_cmd(sbsf, rx, tx); 348b6c2956dSSimon Glass if (ret) 349b6c2956dSSimon Glass return ret; 350ffdb20beSMike Frysinger ++pos; 351ffdb20beSMike Frysinger } 352ffdb20beSMike Frysinger 353ffdb20beSMike Frysinger /* Process the remaining data */ 354ffdb20beSMike Frysinger while (pos < bytes) { 355ffdb20beSMike Frysinger switch (sbsf->state) { 356ffdb20beSMike Frysinger case SF_ID: { 357ffdb20beSMike Frysinger u8 id; 358ffdb20beSMike Frysinger 359ffdb20beSMike Frysinger debug(" id: off:%u tx:", sbsf->off); 360110bdee0SSimon Glass if (sbsf->off < IDCODE_LEN) { 361110bdee0SSimon Glass /* Extract correct byte from ID 0x00aabbcc */ 362523b4e37SJagan Teki id = ((JEDEC_MFR(sbsf->data) << 16) | 363523b4e37SJagan Teki JEDEC_ID(sbsf->data)) >> 364110bdee0SSimon Glass (8 * (IDCODE_LEN - 1 - sbsf->off)); 365110bdee0SSimon Glass } else { 366ffdb20beSMike Frysinger id = 0; 367110bdee0SSimon Glass } 368110bdee0SSimon Glass debug("%d %02x\n", sbsf->off, id); 369ffdb20beSMike Frysinger tx[pos++] = id; 370ffdb20beSMike Frysinger ++sbsf->off; 371ffdb20beSMike Frysinger break; 372ffdb20beSMike Frysinger } 373ffdb20beSMike Frysinger case SF_ADDR: 374ffdb20beSMike Frysinger debug(" addr: bytes:%u rx:%02x ", sbsf->addr_bytes, 375ffdb20beSMike Frysinger rx[pos]); 376ffdb20beSMike Frysinger 377ffdb20beSMike Frysinger if (sbsf->addr_bytes++ < SF_ADDR_LEN) 378ffdb20beSMike Frysinger sbsf->off = (sbsf->off << 8) | rx[pos]; 379ffdb20beSMike Frysinger debug("addr:%06x\n", sbsf->off); 380ffdb20beSMike Frysinger 381b6c2956dSSimon Glass if (tx) 382b6c2956dSSimon Glass sandbox_spi_tristate(&tx[pos], 1); 383b6c2956dSSimon Glass pos++; 384ffdb20beSMike Frysinger 385ffdb20beSMike Frysinger /* See if we're done processing */ 386ffdb20beSMike Frysinger if (sbsf->addr_bytes < 387ffdb20beSMike Frysinger SF_ADDR_LEN + sbsf->pad_addr_bytes) 388ffdb20beSMike Frysinger break; 389ffdb20beSMike Frysinger 390ffdb20beSMike Frysinger /* Next state! */ 391ffdb20beSMike Frysinger if (os_lseek(sbsf->fd, sbsf->off, OS_SEEK_SET) < 0) { 392ffdb20beSMike Frysinger puts("sandbox_sf: os_lseek() failed"); 393b6c2956dSSimon Glass return -EIO; 394ffdb20beSMike Frysinger } 395ffdb20beSMike Frysinger switch (sbsf->cmd) { 396ffdb20beSMike Frysinger case CMD_READ_ARRAY_FAST: 397ffdb20beSMike Frysinger case CMD_READ_ARRAY_SLOW: 398ffdb20beSMike Frysinger sbsf->state = SF_READ; 399ffdb20beSMike Frysinger break; 400ffdb20beSMike Frysinger case CMD_PAGE_PROGRAM: 401ffdb20beSMike Frysinger sbsf->state = SF_WRITE; 402ffdb20beSMike Frysinger break; 403ffdb20beSMike Frysinger default: 404ffdb20beSMike Frysinger /* assume erase state ... */ 405ffdb20beSMike Frysinger sbsf->state = SF_ERASE; 406ffdb20beSMike Frysinger goto case_sf_erase; 407ffdb20beSMike Frysinger } 408ffdb20beSMike Frysinger debug(" cmd: transition to %s state\n", 409ffdb20beSMike Frysinger sandbox_sf_state_name(sbsf->state)); 410ffdb20beSMike Frysinger break; 411ffdb20beSMike Frysinger case SF_READ: 412ffdb20beSMike Frysinger /* 413ffdb20beSMike Frysinger * XXX: need to handle exotic behavior: 414ffdb20beSMike Frysinger * - reading past end of device 415ffdb20beSMike Frysinger */ 416ffdb20beSMike Frysinger 417ffdb20beSMike Frysinger cnt = bytes - pos; 418ffdb20beSMike Frysinger debug(" tx: read(%u)\n", cnt); 419b6c2956dSSimon Glass assert(tx); 420ffdb20beSMike Frysinger ret = os_read(sbsf->fd, tx + pos, cnt); 421ffdb20beSMike Frysinger if (ret < 0) { 422b6c2956dSSimon Glass puts("sandbox_sf: os_read() failed\n"); 423b6c2956dSSimon Glass return -EIO; 424ffdb20beSMike Frysinger } 425ffdb20beSMike Frysinger pos += ret; 426ffdb20beSMike Frysinger break; 427ffdb20beSMike Frysinger case SF_READ_STATUS: 428ffdb20beSMike Frysinger debug(" read status: %#x\n", sbsf->status); 429ffdb20beSMike Frysinger cnt = bytes - pos; 430ffdb20beSMike Frysinger memset(tx + pos, sbsf->status, cnt); 431ffdb20beSMike Frysinger pos += cnt; 432ffdb20beSMike Frysinger break; 433ffdb20beSMike Frysinger case SF_READ_STATUS1: 434ffdb20beSMike Frysinger debug(" read status: %#x\n", sbsf->status); 435ffdb20beSMike Frysinger cnt = bytes - pos; 436ffdb20beSMike Frysinger memset(tx + pos, sbsf->status >> 8, cnt); 437ffdb20beSMike Frysinger pos += cnt; 438ffdb20beSMike Frysinger break; 439b6c2956dSSimon Glass case SF_WRITE_STATUS: 440b6c2956dSSimon Glass debug(" write status: %#x (ignored)\n", rx[pos]); 441b6c2956dSSimon Glass pos = bytes; 442b6c2956dSSimon Glass break; 443ffdb20beSMike Frysinger case SF_WRITE: 444ffdb20beSMike Frysinger /* 445ffdb20beSMike Frysinger * XXX: need to handle exotic behavior: 446ffdb20beSMike Frysinger * - unaligned addresses 447ffdb20beSMike Frysinger * - more than a page (256) worth of data 448ffdb20beSMike Frysinger * - reading past end of device 449ffdb20beSMike Frysinger */ 450ffdb20beSMike Frysinger if (!(sbsf->status & STAT_WEL)) { 451ffdb20beSMike Frysinger puts("sandbox_sf: write enable not set before write\n"); 452ffdb20beSMike Frysinger goto done; 453ffdb20beSMike Frysinger } 454ffdb20beSMike Frysinger 455ffdb20beSMike Frysinger cnt = bytes - pos; 456ffdb20beSMike Frysinger debug(" rx: write(%u)\n", cnt); 457b6c2956dSSimon Glass if (tx) 458ffdb20beSMike Frysinger sandbox_spi_tristate(&tx[pos], cnt); 459ffdb20beSMike Frysinger ret = os_write(sbsf->fd, rx + pos, cnt); 460ffdb20beSMike Frysinger if (ret < 0) { 461ffdb20beSMike Frysinger puts("sandbox_spi: os_write() failed\n"); 462b6c2956dSSimon Glass return -EIO; 463ffdb20beSMike Frysinger } 464ffdb20beSMike Frysinger pos += ret; 465ffdb20beSMike Frysinger sbsf->status &= ~STAT_WEL; 466ffdb20beSMike Frysinger break; 467ffdb20beSMike Frysinger case SF_ERASE: 468ffdb20beSMike Frysinger case_sf_erase: { 469ffdb20beSMike Frysinger if (!(sbsf->status & STAT_WEL)) { 470ffdb20beSMike Frysinger puts("sandbox_sf: write enable not set before erase\n"); 471ffdb20beSMike Frysinger goto done; 472ffdb20beSMike Frysinger } 473ffdb20beSMike Frysinger 474ffdb20beSMike Frysinger /* verify address is aligned */ 475110bdee0SSimon Glass if (sbsf->off & (sbsf->erase_size - 1)) { 476ffdb20beSMike Frysinger debug(" sector erase: cmd:%#x needs align:%#x, but we got %#x\n", 477110bdee0SSimon Glass sbsf->cmd, sbsf->erase_size, 478ffdb20beSMike Frysinger sbsf->off); 479ffdb20beSMike Frysinger sbsf->status &= ~STAT_WEL; 480ffdb20beSMike Frysinger goto done; 481ffdb20beSMike Frysinger } 482ffdb20beSMike Frysinger 483110bdee0SSimon Glass debug(" sector erase addr: %u, size: %u\n", sbsf->off, 484110bdee0SSimon Glass sbsf->erase_size); 485ffdb20beSMike Frysinger 486ffdb20beSMike Frysinger cnt = bytes - pos; 487b6c2956dSSimon Glass if (tx) 488ffdb20beSMike Frysinger sandbox_spi_tristate(&tx[pos], cnt); 489ffdb20beSMike Frysinger pos += cnt; 490ffdb20beSMike Frysinger 491ffdb20beSMike Frysinger /* 492ffdb20beSMike Frysinger * TODO(vapier@gentoo.org): latch WIP in status, and 493ffdb20beSMike Frysinger * delay before clearing it ? 494ffdb20beSMike Frysinger */ 495110bdee0SSimon Glass ret = sandbox_erase_part(sbsf, sbsf->erase_size); 496ffdb20beSMike Frysinger sbsf->status &= ~STAT_WEL; 497ffdb20beSMike Frysinger if (ret) { 498ffdb20beSMike Frysinger debug("sandbox_sf: Erase failed\n"); 499ffdb20beSMike Frysinger goto done; 500ffdb20beSMike Frysinger } 501ffdb20beSMike Frysinger goto done; 502ffdb20beSMike Frysinger } 503ffdb20beSMike Frysinger default: 504ffdb20beSMike Frysinger debug(" ??? no idea what to do ???\n"); 505ffdb20beSMike Frysinger goto done; 506ffdb20beSMike Frysinger } 507ffdb20beSMike Frysinger } 508ffdb20beSMike Frysinger 509ffdb20beSMike Frysinger done: 510b6c2956dSSimon Glass if (flags & SPI_XFER_END) 511b6c2956dSSimon Glass sandbox_sf_cs_deactivate(dev); 512b6c2956dSSimon Glass return pos == bytes ? 0 : -EIO; 513ffdb20beSMike Frysinger } 514ffdb20beSMike Frysinger 515b6c2956dSSimon Glass int sandbox_sf_ofdata_to_platdata(struct udevice *dev) 516b6c2956dSSimon Glass { 517b6c2956dSSimon Glass struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev); 518b6c2956dSSimon Glass const void *blob = gd->fdt_blob; 519e160f7d4SSimon Glass int node = dev_of_offset(dev); 520b6c2956dSSimon Glass 521b6c2956dSSimon Glass pdata->filename = fdt_getprop(blob, node, "sandbox,filename", NULL); 522b6c2956dSSimon Glass pdata->device_name = fdt_getprop(blob, node, "compatible", NULL); 523b6c2956dSSimon Glass if (!pdata->filename || !pdata->device_name) { 524b6c2956dSSimon Glass debug("%s: Missing properties, filename=%s, device_name=%s\n", 525b6c2956dSSimon Glass __func__, pdata->filename, pdata->device_name); 526b6c2956dSSimon Glass return -EINVAL; 527b6c2956dSSimon Glass } 528b6c2956dSSimon Glass 529b6c2956dSSimon Glass return 0; 530b6c2956dSSimon Glass } 531b6c2956dSSimon Glass 532b6c2956dSSimon Glass static const struct dm_spi_emul_ops sandbox_sf_emul_ops = { 533ffdb20beSMike Frysinger .xfer = sandbox_sf_xfer, 534ffdb20beSMike Frysinger }; 535ffdb20beSMike Frysinger 536b6c2956dSSimon Glass #ifdef CONFIG_SPI_FLASH 537ffdb20beSMike Frysinger static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state, 538ffdb20beSMike Frysinger const char *arg) 539ffdb20beSMike Frysinger { 540ffdb20beSMike Frysinger unsigned long bus, cs; 541ffdb20beSMike Frysinger const char *spec = sandbox_spi_parse_spec(arg, &bus, &cs); 542ffdb20beSMike Frysinger 543ffdb20beSMike Frysinger if (!spec) 544ffdb20beSMike Frysinger return 1; 545ffdb20beSMike Frysinger 546ffdb20beSMike Frysinger /* 547ffdb20beSMike Frysinger * It is safe to not make a copy of 'spec' because it comes from the 548ffdb20beSMike Frysinger * command line. 549ffdb20beSMike Frysinger * 550ffdb20beSMike Frysinger * TODO(sjg@chromium.org): It would be nice if we could parse the 551ffdb20beSMike Frysinger * spec here, but the problem is that no U-Boot init has been done 552ffdb20beSMike Frysinger * yet. Perhaps we can figure something out. 553ffdb20beSMike Frysinger */ 554ffdb20beSMike Frysinger state->spi[bus][cs].spec = spec; 55520f655daSSimon Glass debug("%s: Setting up spec '%s' for bus %ld, cs %ld\n", __func__, 55620f655daSSimon Glass spec, bus, cs); 55720f655daSSimon Glass 558ffdb20beSMike Frysinger return 0; 559ffdb20beSMike Frysinger } 560ffdb20beSMike Frysinger SANDBOX_CMDLINE_OPT(spi_sf, 1, "connect a SPI flash: <bus>:<cs>:<id>:<file>"); 561b6c2956dSSimon Glass 562b6c2956dSSimon Glass int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs, 563b6c2956dSSimon Glass struct udevice *bus, int of_offset, const char *spec) 564b6c2956dSSimon Glass { 565b6c2956dSSimon Glass struct udevice *emul; 566b6c2956dSSimon Glass char name[20], *str; 567b6c2956dSSimon Glass struct driver *drv; 568b6c2956dSSimon Glass int ret; 569b6c2956dSSimon Glass 570b6c2956dSSimon Glass /* now the emulator */ 571b6c2956dSSimon Glass strncpy(name, spec, sizeof(name) - 6); 572b6c2956dSSimon Glass name[sizeof(name) - 6] = '\0'; 573b6c2956dSSimon Glass strcat(name, "-emul"); 574b6c2956dSSimon Glass str = strdup(name); 575b6c2956dSSimon Glass if (!str) 576b6c2956dSSimon Glass return -ENOMEM; 577b6c2956dSSimon Glass drv = lists_driver_lookup_name("sandbox_sf_emul"); 578b6c2956dSSimon Glass if (!drv) { 579b6c2956dSSimon Glass puts("Cannot find sandbox_sf_emul driver\n"); 580b6c2956dSSimon Glass return -ENOENT; 581b6c2956dSSimon Glass } 582b6c2956dSSimon Glass ret = device_bind(bus, drv, str, NULL, of_offset, &emul); 583b6c2956dSSimon Glass if (ret) { 584b6c2956dSSimon Glass printf("Cannot create emul device for spec '%s' (err=%d)\n", 585b6c2956dSSimon Glass spec, ret); 586b6c2956dSSimon Glass return ret; 587b6c2956dSSimon Glass } 588b6c2956dSSimon Glass state->spi[busnum][cs].emul = emul; 589b6c2956dSSimon Glass 590b6c2956dSSimon Glass return 0; 591b6c2956dSSimon Glass } 592b6c2956dSSimon Glass 593b6c2956dSSimon Glass void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs) 594b6c2956dSSimon Glass { 595d0cff03eSSimon Glass struct udevice *dev; 596d0cff03eSSimon Glass 597d0cff03eSSimon Glass dev = state->spi[busnum][cs].emul; 598*706865afSStefan Roese device_remove(dev, DM_REMOVE_NORMAL); 599d0cff03eSSimon Glass device_unbind(dev); 600b6c2956dSSimon Glass state->spi[busnum][cs].emul = NULL; 601b6c2956dSSimon Glass } 602b6c2956dSSimon Glass 603b6c2956dSSimon Glass static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum, 604b6c2956dSSimon Glass int cs, const char *spec) 605b6c2956dSSimon Glass { 606b6c2956dSSimon Glass struct udevice *bus, *slave; 607b6c2956dSSimon Glass int ret; 608b6c2956dSSimon Glass 609b6c2956dSSimon Glass ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, true, &bus); 610b6c2956dSSimon Glass if (ret) { 611b6c2956dSSimon Glass printf("Invalid bus %d for spec '%s' (err=%d)\n", busnum, 612b6c2956dSSimon Glass spec, ret); 613b6c2956dSSimon Glass return ret; 614b6c2956dSSimon Glass } 615ff56bba2SSimon Glass ret = spi_find_chip_select(bus, cs, &slave); 616b6c2956dSSimon Glass if (!ret) { 617b6c2956dSSimon Glass printf("Chip select %d already exists for spec '%s'\n", cs, 618b6c2956dSSimon Glass spec); 619b6c2956dSSimon Glass return -EEXIST; 620b6c2956dSSimon Glass } 621b6c2956dSSimon Glass 6226b18656aSSimon Glass ret = device_bind_driver(bus, "spi_flash_std", spec, &slave); 623b6c2956dSSimon Glass if (ret) 624b6c2956dSSimon Glass return ret; 625b6c2956dSSimon Glass 626b6c2956dSSimon Glass return sandbox_sf_bind_emul(state, busnum, cs, bus, -1, spec); 627b6c2956dSSimon Glass } 628b6c2956dSSimon Glass 629b6c2956dSSimon Glass int sandbox_spi_get_emul(struct sandbox_state *state, 630b6c2956dSSimon Glass struct udevice *bus, struct udevice *slave, 631b6c2956dSSimon Glass struct udevice **emulp) 632b6c2956dSSimon Glass { 633b6c2956dSSimon Glass struct sandbox_spi_info *info; 634b6c2956dSSimon Glass int busnum = bus->seq; 635b6c2956dSSimon Glass int cs = spi_chip_select(slave); 636b6c2956dSSimon Glass int ret; 637b6c2956dSSimon Glass 638b6c2956dSSimon Glass info = &state->spi[busnum][cs]; 639b6c2956dSSimon Glass if (!info->emul) { 640b6c2956dSSimon Glass /* Use the same device tree node as the SPI flash device */ 641b6c2956dSSimon Glass debug("%s: busnum=%u, cs=%u: binding SPI flash emulation: ", 642b6c2956dSSimon Glass __func__, busnum, cs); 643b6c2956dSSimon Glass ret = sandbox_sf_bind_emul(state, busnum, cs, bus, 644e160f7d4SSimon Glass dev_of_offset(slave), slave->name); 645b6c2956dSSimon Glass if (ret) { 646b6c2956dSSimon Glass debug("failed (err=%d)\n", ret); 647b6c2956dSSimon Glass return ret; 648b6c2956dSSimon Glass } 649b6c2956dSSimon Glass debug("OK\n"); 650b6c2956dSSimon Glass } 651b6c2956dSSimon Glass *emulp = info->emul; 652b6c2956dSSimon Glass 653b6c2956dSSimon Glass return 0; 654b6c2956dSSimon Glass } 655b6c2956dSSimon Glass 656b6c2956dSSimon Glass int dm_scan_other(bool pre_reloc_only) 657b6c2956dSSimon Glass { 658b6c2956dSSimon Glass struct sandbox_state *state = state_get_current(); 659b6c2956dSSimon Glass int busnum, cs; 660b6c2956dSSimon Glass 661b6c2956dSSimon Glass if (pre_reloc_only) 662b6c2956dSSimon Glass return 0; 663b6c2956dSSimon Glass for (busnum = 0; busnum < CONFIG_SANDBOX_SPI_MAX_BUS; busnum++) { 664b6c2956dSSimon Glass for (cs = 0; cs < CONFIG_SANDBOX_SPI_MAX_CS; cs++) { 665b6c2956dSSimon Glass const char *spec = state->spi[busnum][cs].spec; 666b6c2956dSSimon Glass int ret; 667b6c2956dSSimon Glass 668b6c2956dSSimon Glass if (spec) { 669b6c2956dSSimon Glass ret = sandbox_sf_bind_bus_cs(state, busnum, 670b6c2956dSSimon Glass cs, spec); 671b6c2956dSSimon Glass if (ret) { 672b6c2956dSSimon Glass debug("%s: Bind failed for bus %d, cs %d\n", 673b6c2956dSSimon Glass __func__, busnum, cs); 674b6c2956dSSimon Glass return ret; 675b6c2956dSSimon Glass } 67620f655daSSimon Glass debug("%s: Setting up spec '%s' for bus %d, cs %d\n", 67720f655daSSimon Glass __func__, spec, busnum, cs); 678b6c2956dSSimon Glass } 679b6c2956dSSimon Glass } 680b6c2956dSSimon Glass } 681b6c2956dSSimon Glass 682b6c2956dSSimon Glass return 0; 683b6c2956dSSimon Glass } 684b6c2956dSSimon Glass #endif 685b6c2956dSSimon Glass 686b6c2956dSSimon Glass static const struct udevice_id sandbox_sf_ids[] = { 687b6c2956dSSimon Glass { .compatible = "sandbox,spi-flash" }, 688b6c2956dSSimon Glass { } 689b6c2956dSSimon Glass }; 690b6c2956dSSimon Glass 691b6c2956dSSimon Glass U_BOOT_DRIVER(sandbox_sf_emul) = { 692b6c2956dSSimon Glass .name = "sandbox_sf_emul", 693b6c2956dSSimon Glass .id = UCLASS_SPI_EMUL, 694b6c2956dSSimon Glass .of_match = sandbox_sf_ids, 695b6c2956dSSimon Glass .ofdata_to_platdata = sandbox_sf_ofdata_to_platdata, 696b6c2956dSSimon Glass .probe = sandbox_sf_probe, 697b6c2956dSSimon Glass .remove = sandbox_sf_remove, 698b6c2956dSSimon Glass .priv_auto_alloc_size = sizeof(struct sandbox_spi_flash), 699b6c2956dSSimon Glass .platdata_auto_alloc_size = sizeof(struct sandbox_spi_flash_plat_data), 700b6c2956dSSimon Glass .ops = &sandbox_sf_emul_ops, 701b6c2956dSSimon Glass }; 702