summaryrefslogtreecommitdiffstats
path: root/qemu/roms/u-boot/drivers/mtd/spi
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/u-boot/drivers/mtd/spi')
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/Makefile17
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/eeprom_m95xxx.c111
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/fsl_espi_spl.c90
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/ramtron.c403
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/sandbox.c483
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/sf.c58
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/sf_internal.h159
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/sf_ops.c518
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/sf_params.c131
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/sf_probe.c391
-rw-r--r--qemu/roms/u-boot/drivers/mtd/spi/spi_spl_load.c80
11 files changed, 2441 insertions, 0 deletions
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/Makefile b/qemu/roms/u-boot/drivers/mtd/spi/Makefile
new file mode 100644
index 000000000..9e18fb41d
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/Makefile
@@ -0,0 +1,17 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_SPL_SPI_LOAD) += spi_spl_load.o
+obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o
+endif
+
+obj-$(CONFIG_CMD_SF) += sf.o
+obj-$(CONFIG_SPI_FLASH) += sf_params.o sf_probe.o sf_ops.o
+obj-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o
+obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
+obj-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/eeprom_m95xxx.c b/qemu/roms/u-boot/drivers/mtd/spi/eeprom_m95xxx.c
new file mode 100644
index 000000000..a019939b8
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/eeprom_m95xxx.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009
+ * Albin Tonnerre, Free Electrons <albin.tonnerre@free-electrons.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi.h>
+
+#define SPI_EEPROM_WREN 0x06
+#define SPI_EEPROM_RDSR 0x05
+#define SPI_EEPROM_READ 0x03
+#define SPI_EEPROM_WRITE 0x02
+
+#ifndef CONFIG_DEFAULT_SPI_BUS
+#define CONFIG_DEFAULT_SPI_BUS 0
+#endif
+
+#ifndef CONFIG_DEFAULT_SPI_MODE
+#define CONFIG_DEFAULT_SPI_MODE SPI_MODE_0
+#endif
+
+#ifndef CONFIG_SYS_SPI_WRITE_TOUT
+#define CONFIG_SYS_SPI_WRITE_TOUT (5 * CONFIG_SYS_HZ)
+#endif
+
+ssize_t spi_read(uchar *addr, int alen, uchar *buffer, int len)
+{
+ struct spi_slave *slave;
+ u8 cmd = SPI_EEPROM_READ;
+
+ slave = spi_setup_slave(CONFIG_DEFAULT_SPI_BUS, 1, 1000000,
+ CONFIG_DEFAULT_SPI_MODE);
+ if (!slave)
+ return 0;
+
+ spi_claim_bus(slave);
+
+ /* command */
+ if (spi_xfer(slave, 8, &cmd, NULL, SPI_XFER_BEGIN))
+ return -1;
+
+ /*
+ * if alen == 3, addr[0] is the block number, we never use it here.
+ * All we need are the lower 16 bits.
+ */
+ if (alen == 3)
+ addr++;
+
+ /* address, and data */
+ if (spi_xfer(slave, 16, addr, NULL, 0))
+ return -1;
+ if (spi_xfer(slave, 8 * len, NULL, buffer, SPI_XFER_END))
+ return -1;
+
+ spi_release_bus(slave);
+ spi_free_slave(slave);
+ return len;
+}
+
+ssize_t spi_write(uchar *addr, int alen, uchar *buffer, int len)
+{
+ struct spi_slave *slave;
+ char buf[3];
+ ulong start;
+
+ slave = spi_setup_slave(CONFIG_DEFAULT_SPI_BUS, 1, 1000000,
+ CONFIG_DEFAULT_SPI_MODE);
+ if (!slave)
+ return 0;
+
+ spi_claim_bus(slave);
+
+ buf[0] = SPI_EEPROM_WREN;
+ if (spi_xfer(slave, 8, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END))
+ return -1;
+
+ buf[0] = SPI_EEPROM_WRITE;
+
+ /* As for reading, drop addr[0] if alen is 3 */
+ if (alen == 3) {
+ alen--;
+ addr++;
+ }
+
+ memcpy(buf + 1, addr, alen);
+ /* command + addr, then data */
+ if (spi_xfer(slave, 24, buf, NULL, SPI_XFER_BEGIN))
+ return -1;
+ if (spi_xfer(slave, len * 8, buffer, NULL, SPI_XFER_END))
+ return -1;
+
+ start = get_timer(0);
+ do {
+ buf[0] = SPI_EEPROM_RDSR;
+ buf[1] = 0;
+ spi_xfer(slave, 16, buf, buf, SPI_XFER_BEGIN | SPI_XFER_END);
+
+ if (!(buf[1] & 1))
+ break;
+
+ } while (get_timer(start) < CONFIG_SYS_SPI_WRITE_TOUT);
+
+ if (buf[1] & 1)
+ printf("*** spi_write: Timeout while writing!\n");
+
+ spi_release_bus(slave);
+ spi_free_slave(slave);
+ return len;
+}
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/fsl_espi_spl.c b/qemu/roms/u-boot/drivers/mtd/spi/fsl_espi_spl.c
new file mode 100644
index 000000000..b915469b4
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/fsl_espi_spl.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi_flash.h>
+#include <malloc.h>
+
+#define ESPI_BOOT_IMAGE_SIZE 0x48
+#define ESPI_BOOT_IMAGE_ADDR 0x50
+#define CONFIG_CFG_DATA_SECTOR 0
+
+void spi_spl_load_image(uint32_t offs, unsigned int size, void *vdst)
+{
+ struct spi_flash *flash;
+
+ flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ if (flash == NULL) {
+ puts("\nspi_flash_probe failed");
+ hang();
+ }
+
+ spi_flash_read(flash, offs, size, vdst);
+}
+
+/*
+ * The main entry for SPI booting. It's necessary that SDRAM is already
+ * configured and available since this code loads the main U-Boot image
+ * from SPI into SDRAM and starts it from there.
+ */
+void spi_boot(void)
+{
+ void (*uboot)(void) __noreturn;
+ u32 offset, code_len, copy_len = 0;
+#ifndef CONFIG_FSL_CORENET
+ unsigned char *buf = NULL;
+#endif
+ struct spi_flash *flash;
+
+ flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ if (flash == NULL) {
+ puts("\nspi_flash_probe failed");
+ hang();
+ }
+
+#ifdef CONFIG_FSL_CORENET
+ offset = CONFIG_SYS_SPI_FLASH_U_BOOT_OFFS;
+ code_len = CONFIG_SYS_SPI_FLASH_U_BOOT_SIZE;
+#else
+ /*
+ * Load U-Boot image from SPI flash into RAM
+ */
+ buf = malloc(flash->page_size);
+ if (buf == NULL) {
+ puts("\nmalloc failed");
+ hang();
+ }
+ memset(buf, 0, flash->page_size);
+
+ spi_flash_read(flash, CONFIG_CFG_DATA_SECTOR,
+ flash->page_size, (void *)buf);
+ offset = *(u32 *)(buf + ESPI_BOOT_IMAGE_ADDR);
+ /* Skip spl code */
+ offset += CONFIG_SYS_SPI_FLASH_U_BOOT_OFFS;
+ /* Get the code size from offset 0x48 */
+ code_len = *(u32 *)(buf + ESPI_BOOT_IMAGE_SIZE);
+ /* Skip spl code */
+ code_len = code_len - CONFIG_SPL_MAX_SIZE;
+#endif
+ /* copy code to DDR */
+ printf("Loading second stage boot loader ");
+ while (copy_len <= code_len) {
+ spi_flash_read(flash, offset + copy_len, 0x2000,
+ (void *)(CONFIG_SYS_SPI_FLASH_U_BOOT_DST
+ + copy_len));
+ copy_len = copy_len + 0x2000;
+ putc('.');
+ }
+
+ /*
+ * Jump to U-Boot image
+ */
+ flush_cache(CONFIG_SYS_SPI_FLASH_U_BOOT_DST, code_len);
+ uboot = (void *)CONFIG_SYS_SPI_FLASH_U_BOOT_START;
+ (*uboot)();
+}
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/ramtron.c b/qemu/roms/u-boot/drivers/mtd/spi/ramtron.c
new file mode 100644
index 000000000..d50da37c8
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/ramtron.c
@@ -0,0 +1,403 @@
+/*
+ * (C) Copyright 2010
+ * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Note: RAMTRON SPI FRAMs are ferroelectric, nonvolatile RAMs
+ * with an interface identical to SPI flash devices.
+ * However since they behave like RAM there are no delays or
+ * busy polls required. They can sustain read or write at the
+ * allowed SPI bus speed, which can be 40 MHz for some devices.
+ *
+ * Unfortunately some RAMTRON devices do not have a means of
+ * identifying them. They will leave the SO line undriven when
+ * the READ-ID command is issued. It is therefore mandatory
+ * that the MISO line has a proper pull-up, so that READ-ID
+ * will return a row of 0xff. This 0xff pseudo-id will cause
+ * probes by all vendor specific functions that are designed
+ * to handle it. If the MISO line is not pulled up, READ-ID
+ * could return any random noise, even mimicking another
+ * device.
+ *
+ * We use CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
+ * to define which device will be assumed after a simple status
+ * register verify. This method is prone to false positive
+ * detection and should therefore be the last to be tried.
+ * Enter it in the last position in the table in spi_flash.c!
+ *
+ * The define CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC both activates
+ * compilation of the special handler and defines the device
+ * to assume.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <spi_flash.h>
+#include "sf_internal.h"
+
+/*
+ * Properties of supported FRAMs
+ * Note: speed is currently not used because we have no method to deliver that
+ * value to the upper layers
+ */
+struct ramtron_spi_fram_params {
+ u32 size; /* size in bytes */
+ u8 addr_len; /* number of address bytes */
+ u8 merge_cmd; /* some address bits are in the command byte */
+ u8 id1; /* device ID 1 (family, density) */
+ u8 id2; /* device ID 2 (sub, rev, rsvd) */
+ u32 speed; /* max. SPI clock in Hz */
+ const char *name; /* name for display and/or matching */
+};
+
+struct ramtron_spi_fram {
+ struct spi_flash flash;
+ const struct ramtron_spi_fram_params *params;
+};
+
+static inline struct ramtron_spi_fram *to_ramtron_spi_fram(struct spi_flash
+ *flash)
+{
+ return container_of(flash, struct ramtron_spi_fram, flash);
+}
+
+/*
+ * table describing supported FRAM chips:
+ * chips without RDID command must have the values 0xff for id1 and id2
+ */
+static const struct ramtron_spi_fram_params ramtron_spi_fram_table[] = {
+ {
+ .size = 32*1024,
+ .addr_len = 2,
+ .merge_cmd = 0,
+ .id1 = 0x22,
+ .id2 = 0x00,
+ .speed = 40000000,
+ .name = "FM25V02",
+ },
+ {
+ .size = 32*1024,
+ .addr_len = 2,
+ .merge_cmd = 0,
+ .id1 = 0x22,
+ .id2 = 0x01,
+ .speed = 40000000,
+ .name = "FM25VN02",
+ },
+ {
+ .size = 64*1024,
+ .addr_len = 2,
+ .merge_cmd = 0,
+ .id1 = 0x23,
+ .id2 = 0x00,
+ .speed = 40000000,
+ .name = "FM25V05",
+ },
+ {
+ .size = 64*1024,
+ .addr_len = 2,
+ .merge_cmd = 0,
+ .id1 = 0x23,
+ .id2 = 0x01,
+ .speed = 40000000,
+ .name = "FM25VN05",
+ },
+ {
+ .size = 128*1024,
+ .addr_len = 3,
+ .merge_cmd = 0,
+ .id1 = 0x24,
+ .id2 = 0x00,
+ .speed = 40000000,
+ .name = "FM25V10",
+ },
+ {
+ .size = 128*1024,
+ .addr_len = 3,
+ .merge_cmd = 0,
+ .id1 = 0x24,
+ .id2 = 0x01,
+ .speed = 40000000,
+ .name = "FM25VN10",
+ },
+#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
+ {
+ .size = 256*1024,
+ .addr_len = 3,
+ .merge_cmd = 0,
+ .id1 = 0xff,
+ .id2 = 0xff,
+ .speed = 40000000,
+ .name = "FM25H20",
+ },
+#endif
+};
+
+static int ramtron_common(struct spi_flash *flash,
+ u32 offset, size_t len, void *buf, u8 command)
+{
+ struct ramtron_spi_fram *sn = to_ramtron_spi_fram(flash);
+ u8 cmd[4];
+ int cmd_len;
+ int ret;
+
+ if (sn->params->addr_len == 3 && sn->params->merge_cmd == 0) {
+ cmd[0] = command;
+ cmd[1] = offset >> 16;
+ cmd[2] = offset >> 8;
+ cmd[3] = offset;
+ cmd_len = 4;
+ } else if (sn->params->addr_len == 2 && sn->params->merge_cmd == 0) {
+ cmd[0] = command;
+ cmd[1] = offset >> 8;
+ cmd[2] = offset;
+ cmd_len = 3;
+ } else {
+ printf("SF: unsupported addr_len or merge_cmd\n");
+ return -1;
+ }
+
+ /* claim the bus */
+ ret = spi_claim_bus(flash->spi);
+ if (ret) {
+ debug("SF: Unable to claim SPI bus\n");
+ return ret;
+ }
+
+ if (command == CMD_PAGE_PROGRAM) {
+ /* send WREN */
+ ret = spi_flash_cmd_write_enable(flash);
+ if (ret < 0) {
+ debug("SF: Enabling Write failed\n");
+ goto releasebus;
+ }
+ }
+
+ /* do the transaction */
+ if (command == CMD_PAGE_PROGRAM)
+ ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, buf, len);
+ else
+ ret = spi_flash_cmd_read(flash->spi, cmd, cmd_len, buf, len);
+ if (ret < 0)
+ debug("SF: Transaction failed\n");
+
+releasebus:
+ /* release the bus */
+ spi_release_bus(flash->spi);
+ return ret;
+}
+
+static int ramtron_read(struct spi_flash *flash,
+ u32 offset, size_t len, void *buf)
+{
+ return ramtron_common(flash, offset, len, buf,
+ CMD_READ_ARRAY_SLOW);
+}
+
+static int ramtron_write(struct spi_flash *flash,
+ u32 offset, size_t len, const void *buf)
+{
+ return ramtron_common(flash, offset, len, (void *)buf,
+ CMD_PAGE_PROGRAM);
+}
+
+static int ramtron_erase(struct spi_flash *flash, u32 offset, size_t len)
+{
+ debug("SF: Erase of RAMTRON FRAMs is pointless\n");
+ return -1;
+}
+
+/*
+ * nore: we are called here with idcode pointing to the first non-0x7f byte
+ * already!
+ */
+static struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi,
+ u8 *idcode)
+{
+ const struct ramtron_spi_fram_params *params;
+ struct ramtron_spi_fram *sn;
+ unsigned int i;
+#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
+ int ret;
+ u8 sr;
+#endif
+
+ /* NOTE: the bus has been claimed before this function is called! */
+ switch (idcode[0]) {
+ case 0xc2:
+ /* JEDEC conformant RAMTRON id */
+ for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) {
+ params = &ramtron_spi_fram_table[i];
+ if (idcode[1] == params->id1 &&
+ idcode[2] == params->id2)
+ goto found;
+ }
+ break;
+#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
+ case 0xff:
+ /*
+ * probably open MISO line, pulled up.
+ * We COULD have a non JEDEC conformant FRAM here,
+ * read the status register to verify
+ */
+ ret = spi_flash_cmd(spi, CMD_READ_STATUS, &sr, 1);
+ if (ret)
+ return NULL;
+
+ /* Bits 5,4,0 are fixed 0 for all devices */
+ if ((sr & 0x31) != 0x00)
+ return NULL;
+ /* now find the device */
+ for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) {
+ params = &ramtron_spi_fram_table[i];
+ if (!strcmp(params->name,
+ CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC))
+ goto found;
+ }
+ debug("SF: Unsupported non-JEDEC RAMTRON device "
+ CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC "\n");
+ break;
+#endif
+ default:
+ break;
+ }
+
+ /* arriving here means no method has found a device we can handle */
+ debug("SF/ramtron: unsupported device id0=%02x id1=%02x id2=%02x\n",
+ idcode[0], idcode[1], idcode[2]);
+ return NULL;
+
+found:
+ sn = malloc(sizeof(*sn));
+ if (!sn) {
+ debug("SF: Failed to allocate memory\n");
+ return NULL;
+ }
+
+ sn->params = params;
+
+ sn->flash.write = ramtron_write;
+ sn->flash.read = ramtron_read;
+ sn->flash.erase = ramtron_erase;
+ sn->flash.size = params->size;
+
+ return &sn->flash;
+}
+
+/*
+ * The following table holds all device probe functions
+ * (All flashes are removed and implemented a common probe at
+ * spi_flash_probe.c)
+ *
+ * shift: number of continuation bytes before the ID
+ * idcode: the expected IDCODE or 0xff for non JEDEC devices
+ * probe: the function to call
+ *
+ * Non JEDEC devices should be ordered in the table such that
+ * the probe functions with best detection algorithms come first.
+ *
+ * Several matching entries are permitted, they will be tried
+ * in sequence until a probe function returns non NULL.
+ *
+ * IDCODE_CONT_LEN may be redefined if a device needs to declare a
+ * larger "shift" value. IDCODE_PART_LEN generally shouldn't be
+ * changed. This is the max number of bytes probe functions may
+ * examine when looking up part-specific identification info.
+ *
+ * Probe functions will be given the idcode buffer starting at their
+ * manu id byte (the "idcode" in the table below). In other words,
+ * all of the continuation bytes will be skipped (the "shift" below).
+ */
+#define IDCODE_CONT_LEN 0
+#define IDCODE_PART_LEN 5
+static const struct {
+ const u8 shift;
+ const u8 idcode;
+ struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode);
+} flashes[] = {
+ /* Keep it sorted by define name */
+#ifdef CONFIG_SPI_FRAM_RAMTRON
+ { 6, 0xc2, spi_fram_probe_ramtron, },
+# undef IDCODE_CONT_LEN
+# define IDCODE_CONT_LEN 6
+#endif
+#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
+ { 0, 0xff, spi_fram_probe_ramtron, },
+#endif
+};
+#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN)
+
+struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int spi_mode)
+{
+ struct spi_slave *spi;
+ struct spi_flash *flash = NULL;
+ int ret, i, shift;
+ u8 idcode[IDCODE_LEN], *idp;
+
+ spi = spi_setup_slave(bus, cs, max_hz, spi_mode);
+ if (!spi) {
+ printf("SF: Failed to set up slave\n");
+ return NULL;
+ }
+
+ ret = spi_claim_bus(spi);
+ if (ret) {
+ debug("SF: Failed to claim SPI bus: %d\n", ret);
+ goto err_claim_bus;
+ }
+
+ /* Read the ID codes */
+ ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
+ if (ret)
+ goto err_read_id;
+
+#ifdef DEBUG
+ printf("SF: Got idcodes\n");
+ print_buffer(0, idcode, 1, sizeof(idcode), 0);
+#endif
+
+ /* count the number of continuation bytes */
+ for (shift = 0, idp = idcode;
+ shift < IDCODE_CONT_LEN && *idp == 0x7f;
+ ++shift, ++idp)
+ continue;
+
+ /* search the table for matches in shift and id */
+ for (i = 0; i < ARRAY_SIZE(flashes); ++i)
+ if (flashes[i].shift == shift && flashes[i].idcode == *idp) {
+ /* we have a match, call probe */
+ flash = flashes[i].probe(spi, idp);
+ if (flash)
+ break;
+ }
+
+ if (!flash) {
+ printf("SF: Unsupported manufacturer %02x\n", *idp);
+ goto err_manufacturer_probe;
+ }
+
+ printf("SF: Detected %s with total size ", flash->name);
+ print_size(flash->size, "");
+ puts("\n");
+
+ spi_release_bus(spi);
+
+ return flash;
+
+err_manufacturer_probe:
+err_read_id:
+ spi_release_bus(spi);
+err_claim_bus:
+ spi_free_slave(spi);
+ return NULL;
+}
+
+void spi_flash_free(struct spi_flash *flash)
+{
+ spi_free_slave(flash->spi);
+ free(flash);
+}
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/sandbox.c b/qemu/roms/u-boot/drivers/mtd/spi/sandbox.c
new file mode 100644
index 000000000..a62ef4cbb
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/sandbox.c
@@ -0,0 +1,483 @@
+/*
+ * Simulate a SPI flash
+ *
+ * Copyright (c) 2011-2013 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+#include <os.h>
+
+#include <spi_flash.h>
+#include "sf_internal.h"
+
+#include <asm/getopt.h>
+#include <asm/spi.h>
+#include <asm/state.h>
+
+/*
+ * The different states that our SPI flash transitions between.
+ * We need to keep track of this across multiple xfer calls since
+ * the SPI bus could possibly call down into us multiple times.
+ */
+enum sandbox_sf_state {
+ SF_CMD, /* default state -- we're awaiting a command */
+ SF_ID, /* read the flash's (jedec) ID code */
+ SF_ADDR, /* processing the offset in the flash to read/etc... */
+ SF_READ, /* reading data from the flash */
+ SF_WRITE, /* writing data to the flash, i.e. page programming */
+ SF_ERASE, /* erase the flash */
+ SF_READ_STATUS, /* read the flash's status register */
+ SF_READ_STATUS1, /* read the flash's status register upper 8 bits*/
+};
+
+static const char *sandbox_sf_state_name(enum sandbox_sf_state state)
+{
+ static const char * const states[] = {
+ "CMD", "ID", "ADDR", "READ", "WRITE", "ERASE", "READ_STATUS",
+ };
+ return states[state];
+}
+
+/* Bits for the status register */
+#define STAT_WIP (1 << 0)
+#define STAT_WEL (1 << 1)
+
+/* Assume all SPI flashes have 3 byte addresses since they do atm */
+#define SF_ADDR_LEN 3
+
+struct sandbox_spi_flash_erase_commands {
+ 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 */
+static u8 sandbox_sf_0xff[0x1000];
+
+/* Internal state data for each SPI flash */
+struct sandbox_spi_flash {
+ /*
+ * As we receive data over the SPI bus, our flash transitions
+ * between states. For example, we start off in the SF_CMD
+ * state where the first byte tells us what operation to perform
+ * (such as read or write the flash). But the operation itself
+ * can go through a few states such as first reading in the
+ * offset in the flash to perform the requested operation.
+ * Thus "state" stores the exact state that our machine is in
+ * while "cmd" stores the overall command we're processing.
+ */
+ enum sandbox_sf_state state;
+ uint cmd;
+ const void *cmd_data;
+ /* Current position in the flash; used when reading/writing/etc... */
+ uint off;
+ /* How many address bytes we've consumed */
+ uint addr_bytes, pad_addr_bytes;
+ /* The current flash status (see STAT_XXX defines above) */
+ u16 status;
+ /* Data describing the flash we're emulating */
+ const struct sandbox_spi_flash_data *data;
+ /* The file on disk to serv up data from */
+ int fd;
+};
+
+static int sandbox_sf_setup(void **priv, const char *spec)
+{
+ /* spec = idcode:file */
+ struct sandbox_spi_flash *sbsf;
+ const char *file;
+ size_t i, len, idname_len;
+ const struct sandbox_spi_flash_data *data;
+
+ file = strchr(spec, ':');
+ if (!file) {
+ printf("sandbox_sf: unable to parse file\n");
+ goto error;
+ }
+ idname_len = file - spec;
+ ++file;
+
+ for (i = 0; i < ARRAY_SIZE(sandbox_sf_flashes); ++i) {
+ data = &sandbox_sf_flashes[i];
+ len = strlen(data->name);
+ if (idname_len != len)
+ continue;
+ if (!memcmp(spec, data->name, len))
+ break;
+ }
+ if (i == ARRAY_SIZE(sandbox_sf_flashes)) {
+ printf("sandbox_sf: unknown flash '%*s'\n", (int)idname_len,
+ spec);
+ goto error;
+ }
+
+ if (sandbox_sf_0xff[0] == 0x00)
+ memset(sandbox_sf_0xff, 0xff, sizeof(sandbox_sf_0xff));
+
+ sbsf = calloc(sizeof(*sbsf), 1);
+ if (!sbsf) {
+ printf("sandbox_sf: out of memory\n");
+ goto error;
+ }
+
+ sbsf->fd = os_open(file, 02);
+ if (sbsf->fd == -1) {
+ free(sbsf);
+ printf("sandbox_sf: unable to open file '%s'\n", file);
+ goto error;
+ }
+
+ sbsf->data = data;
+
+ *priv = sbsf;
+ return 0;
+
+ error:
+ return 1;
+}
+
+static void sandbox_sf_free(void *priv)
+{
+ struct sandbox_spi_flash *sbsf = priv;
+
+ os_close(sbsf->fd);
+ free(sbsf);
+}
+
+static void sandbox_sf_cs_activate(void *priv)
+{
+ struct sandbox_spi_flash *sbsf = priv;
+
+ debug("sandbox_sf: CS activated; state is fresh!\n");
+
+ /* CS is asserted, so reset state */
+ sbsf->off = 0;
+ sbsf->addr_bytes = 0;
+ sbsf->pad_addr_bytes = 0;
+ sbsf->state = SF_CMD;
+ sbsf->cmd = SF_CMD;
+}
+
+static void sandbox_sf_cs_deactivate(void *priv)
+{
+ debug("sandbox_sf: CS deactivated; cmd done processing!\n");
+}
+
+/* Figure out what command this stream is telling us to do */
+static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
+ u8 *tx)
+{
+ enum sandbox_sf_state oldstate = sbsf->state;
+
+ /* We need to output a byte for the cmd byte we just ate */
+ sandbox_spi_tristate(tx, 1);
+
+ sbsf->cmd = rx[0];
+ switch (sbsf->cmd) {
+ case CMD_READ_ID:
+ sbsf->state = SF_ID;
+ sbsf->cmd = SF_ID;
+ break;
+ case CMD_READ_ARRAY_FAST:
+ sbsf->pad_addr_bytes = 1;
+ case CMD_READ_ARRAY_SLOW:
+ case CMD_PAGE_PROGRAM:
+ state_addr:
+ sbsf->state = SF_ADDR;
+ break;
+ case CMD_WRITE_DISABLE:
+ debug(" write disabled\n");
+ sbsf->status &= ~STAT_WEL;
+ break;
+ case CMD_READ_STATUS:
+ sbsf->state = SF_READ_STATUS;
+ break;
+ case CMD_READ_STATUS1:
+ sbsf->state = SF_READ_STATUS1;
+ break;
+ case CMD_WRITE_ENABLE:
+ debug(" write enabled\n");
+ sbsf->status |= STAT_WEL;
+ break;
+ default: {
+ size_t i;
+
+ /* handle erase commands first */
+ for (i = 0; i < MAX_ERASE_CMDS; ++i) {
+ const struct sandbox_spi_flash_erase_commands *
+ erase_cmd = &sbsf->data->erase_cmds[i];
+
+ if (erase_cmd->cmd == 0x00)
+ continue;
+ if (sbsf->cmd != erase_cmd->cmd)
+ continue;
+
+ sbsf->cmd_data = erase_cmd;
+ goto state_addr;
+ }
+
+ debug(" cmd unknown: %#x\n", sbsf->cmd);
+ return 1;
+ }
+ }
+
+ if (oldstate != sbsf->state)
+ debug(" cmd: transition to %s state\n",
+ sandbox_sf_state_name(sbsf->state));
+
+ return 0;
+}
+
+int sandbox_erase_part(struct sandbox_spi_flash *sbsf, int size)
+{
+ int todo;
+ int ret;
+
+ while (size > 0) {
+ todo = min(size, sizeof(sandbox_sf_0xff));
+ ret = os_write(sbsf->fd, sandbox_sf_0xff, todo);
+ if (ret != todo)
+ return ret;
+ size -= todo;
+ }
+
+ return 0;
+}
+
+static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
+ uint bytes)
+{
+ struct sandbox_spi_flash *sbsf = priv;
+ uint cnt, pos = 0;
+ int ret;
+
+ debug("sandbox_sf: state:%x(%s) bytes:%u\n", sbsf->state,
+ sandbox_sf_state_name(sbsf->state), bytes);
+
+ if (sbsf->state == SF_CMD) {
+ /* Figure out the initial state */
+ if (sandbox_sf_process_cmd(sbsf, rx, tx))
+ return 1;
+ ++pos;
+ }
+
+ /* Process the remaining data */
+ while (pos < bytes) {
+ switch (sbsf->state) {
+ case SF_ID: {
+ u8 id;
+
+ debug(" id: off:%u tx:", sbsf->off);
+ if (sbsf->off < IDCODE_LEN)
+ id = sbsf->data->idcode[sbsf->off];
+ else
+ id = 0;
+ debug("%02x\n", id);
+ tx[pos++] = id;
+ ++sbsf->off;
+ break;
+ }
+ case SF_ADDR:
+ debug(" addr: bytes:%u rx:%02x ", sbsf->addr_bytes,
+ rx[pos]);
+
+ if (sbsf->addr_bytes++ < SF_ADDR_LEN)
+ sbsf->off = (sbsf->off << 8) | rx[pos];
+ debug("addr:%06x\n", sbsf->off);
+
+ sandbox_spi_tristate(&tx[pos++], 1);
+
+ /* See if we're done processing */
+ if (sbsf->addr_bytes <
+ SF_ADDR_LEN + sbsf->pad_addr_bytes)
+ break;
+
+ /* Next state! */
+ if (os_lseek(sbsf->fd, sbsf->off, OS_SEEK_SET) < 0) {
+ puts("sandbox_sf: os_lseek() failed");
+ return 1;
+ }
+ switch (sbsf->cmd) {
+ case CMD_READ_ARRAY_FAST:
+ case CMD_READ_ARRAY_SLOW:
+ sbsf->state = SF_READ;
+ break;
+ case CMD_PAGE_PROGRAM:
+ sbsf->state = SF_WRITE;
+ break;
+ default:
+ /* assume erase state ... */
+ sbsf->state = SF_ERASE;
+ goto case_sf_erase;
+ }
+ debug(" cmd: transition to %s state\n",
+ sandbox_sf_state_name(sbsf->state));
+ break;
+ case SF_READ:
+ /*
+ * XXX: need to handle exotic behavior:
+ * - reading past end of device
+ */
+
+ cnt = bytes - pos;
+ debug(" tx: read(%u)\n", cnt);
+ ret = os_read(sbsf->fd, tx + pos, cnt);
+ if (ret < 0) {
+ puts("sandbox_spi: os_read() failed\n");
+ return 1;
+ }
+ pos += ret;
+ break;
+ case SF_READ_STATUS:
+ debug(" read status: %#x\n", sbsf->status);
+ cnt = bytes - pos;
+ memset(tx + pos, sbsf->status, cnt);
+ pos += cnt;
+ break;
+ case SF_READ_STATUS1:
+ debug(" read status: %#x\n", sbsf->status);
+ cnt = bytes - pos;
+ memset(tx + pos, sbsf->status >> 8, cnt);
+ pos += cnt;
+ break;
+ case SF_WRITE:
+ /*
+ * XXX: need to handle exotic behavior:
+ * - unaligned addresses
+ * - more than a page (256) worth of data
+ * - reading past end of device
+ */
+ if (!(sbsf->status & STAT_WEL)) {
+ puts("sandbox_sf: write enable not set before write\n");
+ goto done;
+ }
+
+ cnt = bytes - pos;
+ debug(" rx: write(%u)\n", cnt);
+ sandbox_spi_tristate(&tx[pos], cnt);
+ ret = os_write(sbsf->fd, rx + pos, cnt);
+ if (ret < 0) {
+ puts("sandbox_spi: os_write() failed\n");
+ return 1;
+ }
+ pos += ret;
+ sbsf->status &= ~STAT_WEL;
+ break;
+ case SF_ERASE:
+ case_sf_erase: {
+ const struct sandbox_spi_flash_erase_commands *
+ erase_cmd = sbsf->cmd_data;
+
+ if (!(sbsf->status & STAT_WEL)) {
+ puts("sandbox_sf: write enable not set before erase\n");
+ goto done;
+ }
+
+ /* verify address is aligned */
+ if (sbsf->off & (erase_cmd->size - 1)) {
+ debug(" sector erase: cmd:%#x needs align:%#x, but we got %#x\n",
+ erase_cmd->cmd, erase_cmd->size,
+ sbsf->off);
+ sbsf->status &= ~STAT_WEL;
+ goto done;
+ }
+
+ debug(" sector erase addr: %u\n", sbsf->off);
+
+ cnt = bytes - pos;
+ sandbox_spi_tristate(&tx[pos], cnt);
+ pos += cnt;
+
+ /*
+ * TODO(vapier@gentoo.org): latch WIP in status, and
+ * delay before clearing it ?
+ */
+ ret = sandbox_erase_part(sbsf, erase_cmd->size);
+ sbsf->status &= ~STAT_WEL;
+ if (ret) {
+ debug("sandbox_sf: Erase failed\n");
+ goto done;
+ }
+ goto done;
+ }
+ default:
+ debug(" ??? no idea what to do ???\n");
+ goto done;
+ }
+ }
+
+ done:
+ return pos == bytes ? 0 : 1;
+}
+
+static const struct sandbox_spi_emu_ops sandbox_sf_ops = {
+ .setup = sandbox_sf_setup,
+ .free = sandbox_sf_free,
+ .cs_activate = sandbox_sf_cs_activate,
+ .cs_deactivate = sandbox_sf_cs_deactivate,
+ .xfer = sandbox_sf_xfer,
+};
+
+static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state,
+ const char *arg)
+{
+ unsigned long bus, cs;
+ const char *spec = sandbox_spi_parse_spec(arg, &bus, &cs);
+
+ if (!spec)
+ return 1;
+
+ /*
+ * It is safe to not make a copy of 'spec' because it comes from the
+ * command line.
+ *
+ * TODO(sjg@chromium.org): It would be nice if we could parse the
+ * spec here, but the problem is that no U-Boot init has been done
+ * yet. Perhaps we can figure something out.
+ */
+ state->spi[bus][cs].ops = &sandbox_sf_ops;
+ state->spi[bus][cs].spec = spec;
+ return 0;
+}
+SANDBOX_CMDLINE_OPT(spi_sf, 1, "connect a SPI flash: <bus>:<cs>:<id>:<file>");
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/sf.c b/qemu/roms/u-boot/drivers/mtd/spi/sf.c
new file mode 100644
index 000000000..664e86082
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/sf.c
@@ -0,0 +1,58 @@
+/*
+ * SPI flash interface
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi.h>
+
+static int spi_flash_read_write(struct spi_slave *spi,
+ const u8 *cmd, size_t cmd_len,
+ const u8 *data_out, u8 *data_in,
+ size_t data_len)
+{
+ unsigned long flags = SPI_XFER_BEGIN;
+ int ret;
+
+#ifdef CONFIG_SF_DUAL_FLASH
+ if (spi->flags & SPI_XFER_U_PAGE)
+ flags |= SPI_XFER_U_PAGE;
+#endif
+ if (data_len == 0)
+ flags |= SPI_XFER_END;
+
+ ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
+ if (ret) {
+ debug("SF: Failed to send command (%zu bytes): %d\n",
+ cmd_len, ret);
+ } else if (data_len != 0) {
+ ret = spi_xfer(spi, data_len * 8, data_out, data_in,
+ SPI_XFER_END);
+ if (ret)
+ debug("SF: Failed to transfer %zu bytes of data: %d\n",
+ data_len, ret);
+ }
+
+ return ret;
+}
+
+int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
+ size_t cmd_len, void *data, size_t data_len)
+{
+ return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len);
+}
+
+int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len)
+{
+ return spi_flash_cmd_read(spi, &cmd, 1, response, len);
+}
+
+int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
+ const void *data, size_t data_len)
+{
+ return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len);
+}
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/sf_internal.h b/qemu/roms/u-boot/drivers/mtd/spi/sf_internal.h
new file mode 100644
index 000000000..6bcd52204
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/sf_internal.h
@@ -0,0 +1,159 @@
+/*
+ * SPI flash internal definitions
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _SF_INTERNAL_H_
+#define _SF_INTERNAL_H_
+
+#define SPI_FLASH_3B_ADDR_LEN 3
+#define SPI_FLASH_CMD_LEN (1 + SPI_FLASH_3B_ADDR_LEN)
+#define SPI_FLASH_16MB_BOUN 0x1000000
+
+/* CFI Manufacture ID's */
+#define SPI_FLASH_CFI_MFR_SPANSION 0x01
+#define SPI_FLASH_CFI_MFR_STMICRO 0x20
+#define SPI_FLASH_CFI_MFR_MACRONIX 0xc2
+#define SPI_FLASH_CFI_MFR_WINBOND 0xef
+
+/* Erase commands */
+#define CMD_ERASE_4K 0x20
+#define CMD_ERASE_32K 0x52
+#define CMD_ERASE_CHIP 0xc7
+#define CMD_ERASE_64K 0xd8
+
+/* Write commands */
+#define CMD_WRITE_STATUS 0x01
+#define CMD_PAGE_PROGRAM 0x02
+#define CMD_WRITE_DISABLE 0x04
+#define CMD_READ_STATUS 0x05
+#define CMD_QUAD_PAGE_PROGRAM 0x32
+#define CMD_READ_STATUS1 0x35
+#define CMD_WRITE_ENABLE 0x06
+#define CMD_READ_CONFIG 0x35
+#define CMD_FLAG_STATUS 0x70
+
+/* Read commands */
+#define CMD_READ_ARRAY_SLOW 0x03
+#define CMD_READ_ARRAY_FAST 0x0b
+#define CMD_READ_DUAL_OUTPUT_FAST 0x3b
+#define CMD_READ_DUAL_IO_FAST 0xbb
+#define CMD_READ_QUAD_OUTPUT_FAST 0x6b
+#define CMD_READ_QUAD_IO_FAST 0xeb
+#define CMD_READ_ID 0x9f
+
+/* Bank addr access commands */
+#ifdef CONFIG_SPI_FLASH_BAR
+# define CMD_BANKADDR_BRWR 0x17
+# define CMD_BANKADDR_BRRD 0x16
+# define CMD_EXTNADDR_WREAR 0xC5
+# define CMD_EXTNADDR_RDEAR 0xC8
+#endif
+
+/* Common status */
+#define STATUS_WIP (1 << 0)
+#define STATUS_QEB_WINSPAN (1 << 1)
+#define STATUS_QEB_MXIC (1 << 6)
+#define STATUS_PEC (1 << 7)
+
+/* Flash timeout values */
+#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ)
+#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ)
+#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ)
+
+/* SST specific */
+#ifdef CONFIG_SPI_FLASH_SST
+# define SST_WP 0x01 /* Supports AAI word program */
+# define CMD_SST_BP 0x02 /* Byte Program */
+# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */
+
+int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
+ const void *buf);
+#endif
+
+/* Send a single-byte command to the device and read the response */
+int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
+
+/*
+ * Send a multi-byte command to the device and read the response. Used
+ * for flash array reads, etc.
+ */
+int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
+ size_t cmd_len, void *data, size_t data_len);
+
+/*
+ * Send a multi-byte command to the device followed by (optional)
+ * data. Used for programming the flash array, etc.
+ */
+int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
+ const void *data, size_t data_len);
+
+
+/* Flash erase(sectors) operation, support all possible erase commands */
+int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len);
+
+/* Read the status register */
+int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs);
+
+/* Program the status register */
+int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws);
+
+/* Read the config register */
+int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc);
+
+/* Program the config register */
+int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc);
+
+/* Enable writing on the SPI flash */
+static inline int spi_flash_cmd_write_enable(struct spi_flash *flash)
+{
+ return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0);
+}
+
+/* Disable writing on the SPI flash */
+static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
+{
+ return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);
+}
+
+/*
+ * Send the read status command to the device and wait for the wip
+ * (write-in-progress) bit to clear itself.
+ */
+int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout);
+
+/*
+ * Used for spi_flash write operation
+ * - SPI claim
+ * - spi_flash_cmd_write_enable
+ * - spi_flash_cmd_write
+ * - spi_flash_cmd_wait_ready
+ * - SPI release
+ */
+int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
+ size_t cmd_len, const void *buf, size_t buf_len);
+
+/*
+ * Flash write operation, support all possible write commands.
+ * Write the requested data out breaking it up into multiple write
+ * commands as needed per the write size.
+ */
+int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
+ size_t len, const void *buf);
+
+/*
+ * Same as spi_flash_cmd_read() except it also claims/releases the SPI
+ * bus. Used as common part of the ->read() operation.
+ */
+int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
+ size_t cmd_len, void *data, size_t data_len);
+
+/* Flash read operation, support all possible read commands */
+int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
+ size_t len, void *data);
+
+#endif /* _SF_INTERNAL_H_ */
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/sf_ops.c b/qemu/roms/u-boot/drivers/mtd/spi/sf_ops.c
new file mode 100644
index 000000000..ef91b924d
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/sf_ops.c
@@ -0,0 +1,518 @@
+/*
+ * SPI flash operations
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
+ * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <watchdog.h>
+
+#include "sf_internal.h"
+
+static void spi_flash_addr(u32 addr, u8 *cmd)
+{
+ /* cmd[0] is actual command */
+ cmd[1] = addr >> 16;
+ cmd[2] = addr >> 8;
+ cmd[3] = addr >> 0;
+}
+
+int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs)
+{
+ int ret;
+ u8 cmd;
+
+ cmd = CMD_READ_STATUS;
+ ret = spi_flash_read_common(flash, &cmd, 1, rs, 1);
+ if (ret < 0) {
+ debug("SF: fail to read status register\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws)
+{
+ u8 cmd;
+ int ret;
+
+ cmd = CMD_WRITE_STATUS;
+ ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1);
+ if (ret < 0) {
+ debug("SF: fail to write status register\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc)
+{
+ int ret;
+ u8 cmd;
+
+ cmd = CMD_READ_CONFIG;
+ ret = spi_flash_read_common(flash, &cmd, 1, rc, 1);
+ if (ret < 0) {
+ debug("SF: fail to read config register\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc)
+{
+ u8 data[2];
+ u8 cmd;
+ int ret;
+
+ ret = spi_flash_cmd_read_status(flash, &data[0]);
+ if (ret < 0)
+ return ret;
+
+ cmd = CMD_WRITE_STATUS;
+ data[1] = wc;
+ ret = spi_flash_write_common(flash, &cmd, 1, &data, 2);
+ if (ret) {
+ debug("SF: fail to write config register\n");
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_SPI_FLASH_BAR
+static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel)
+{
+ u8 cmd;
+ int ret;
+
+ if (flash->bank_curr == bank_sel) {
+ debug("SF: not require to enable bank%d\n", bank_sel);
+ return 0;
+ }
+
+ cmd = flash->bank_write_cmd;
+ ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1);
+ if (ret < 0) {
+ debug("SF: fail to write bank register\n");
+ return ret;
+ }
+ flash->bank_curr = bank_sel;
+
+ return 0;
+}
+
+static int spi_flash_bank(struct spi_flash *flash, u32 offset)
+{
+ u8 bank_sel;
+ int ret;
+
+ bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift);
+
+ ret = spi_flash_cmd_bankaddr_write(flash, bank_sel);
+ if (ret) {
+ debug("SF: fail to set bank%d\n", bank_sel);
+ return ret;
+ }
+
+ return bank_sel;
+}
+#endif
+
+#ifdef CONFIG_SF_DUAL_FLASH
+static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr)
+{
+ switch (flash->dual_flash) {
+ case SF_DUAL_STACKED_FLASH:
+ if (*addr >= (flash->size >> 1)) {
+ *addr -= flash->size >> 1;
+ flash->spi->flags |= SPI_XFER_U_PAGE;
+ } else {
+ flash->spi->flags &= ~SPI_XFER_U_PAGE;
+ }
+ break;
+ case SF_DUAL_PARALLEL_FLASH:
+ *addr >>= flash->shift;
+ break;
+ default:
+ debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash);
+ break;
+ }
+}
+#endif
+
+int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
+{
+ struct spi_slave *spi = flash->spi;
+ unsigned long timebase;
+ unsigned long flags = SPI_XFER_BEGIN;
+ int ret;
+ u8 status;
+ u8 check_status = 0x0;
+ u8 poll_bit = STATUS_WIP;
+ u8 cmd = flash->poll_cmd;
+
+ if (cmd == CMD_FLAG_STATUS) {
+ poll_bit = STATUS_PEC;
+ check_status = poll_bit;
+ }
+
+#ifdef CONFIG_SF_DUAL_FLASH
+ if (spi->flags & SPI_XFER_U_PAGE)
+ flags |= SPI_XFER_U_PAGE;
+#endif
+ ret = spi_xfer(spi, 8, &cmd, NULL, flags);
+ if (ret) {
+ debug("SF: fail to read %s status register\n",
+ cmd == CMD_READ_STATUS ? "read" : "flag");
+ return ret;
+ }
+
+ timebase = get_timer(0);
+ do {
+ WATCHDOG_RESET();
+
+ ret = spi_xfer(spi, 8, NULL, &status, 0);
+ if (ret)
+ return -1;
+
+ if ((status & poll_bit) == check_status)
+ break;
+
+ } while (get_timer(timebase) < timeout);
+
+ spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
+
+ if ((status & poll_bit) == check_status)
+ return 0;
+
+ /* Timed out */
+ debug("SF: time out!\n");
+ return -1;
+}
+
+int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
+ size_t cmd_len, const void *buf, size_t buf_len)
+{
+ struct spi_slave *spi = flash->spi;
+ unsigned long timeout = SPI_FLASH_PROG_TIMEOUT;
+ int ret;
+
+ if (buf == NULL)
+ timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT;
+
+ ret = spi_claim_bus(flash->spi);
+ if (ret) {
+ debug("SF: unable to claim SPI bus\n");
+ return ret;
+ }
+
+ ret = spi_flash_cmd_write_enable(flash);
+ if (ret < 0) {
+ debug("SF: enabling write failed\n");
+ return ret;
+ }
+
+ ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len);
+ if (ret < 0) {
+ debug("SF: write cmd failed\n");
+ return ret;
+ }
+
+ ret = spi_flash_cmd_wait_ready(flash, timeout);
+ if (ret < 0) {
+ debug("SF: write %s timed out\n",
+ timeout == SPI_FLASH_PROG_TIMEOUT ?
+ "program" : "page erase");
+ return ret;
+ }
+
+ spi_release_bus(spi);
+
+ return ret;
+}
+
+int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
+{
+ u32 erase_size, erase_addr;
+ u8 cmd[SPI_FLASH_CMD_LEN];
+ int ret = -1;
+
+ erase_size = flash->erase_size;
+ if (offset % erase_size || len % erase_size) {
+ debug("SF: Erase offset/length not multiple of erase size\n");
+ return -1;
+ }
+
+ cmd[0] = flash->erase_cmd;
+ while (len) {
+ erase_addr = offset;
+
+#ifdef CONFIG_SF_DUAL_FLASH
+ if (flash->dual_flash > SF_SINGLE_FLASH)
+ spi_flash_dual_flash(flash, &erase_addr);
+#endif
+#ifdef CONFIG_SPI_FLASH_BAR
+ ret = spi_flash_bank(flash, erase_addr);
+ if (ret < 0)
+ return ret;
+#endif
+ spi_flash_addr(erase_addr, cmd);
+
+ debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
+ cmd[2], cmd[3], erase_addr);
+
+ ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
+ if (ret < 0) {
+ debug("SF: erase failed\n");
+ break;
+ }
+
+ offset += erase_size;
+ len -= erase_size;
+ }
+
+ return ret;
+}
+
+int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
+ size_t len, const void *buf)
+{
+ unsigned long byte_addr, page_size;
+ u32 write_addr;
+ size_t chunk_len, actual;
+ u8 cmd[SPI_FLASH_CMD_LEN];
+ int ret = -1;
+
+ page_size = flash->page_size;
+
+ cmd[0] = flash->write_cmd;
+ for (actual = 0; actual < len; actual += chunk_len) {
+ write_addr = offset;
+
+#ifdef CONFIG_SF_DUAL_FLASH
+ if (flash->dual_flash > SF_SINGLE_FLASH)
+ spi_flash_dual_flash(flash, &write_addr);
+#endif
+#ifdef CONFIG_SPI_FLASH_BAR
+ ret = spi_flash_bank(flash, write_addr);
+ if (ret < 0)
+ return ret;
+#endif
+ byte_addr = offset % page_size;
+ chunk_len = min(len - actual, page_size - byte_addr);
+
+ if (flash->spi->max_write_size)
+ chunk_len = min(chunk_len, flash->spi->max_write_size);
+
+ spi_flash_addr(write_addr, cmd);
+
+ debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
+ buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
+
+ ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
+ buf + actual, chunk_len);
+ if (ret < 0) {
+ debug("SF: write failed\n");
+ break;
+ }
+
+ offset += chunk_len;
+ }
+
+ return ret;
+}
+
+int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
+ size_t cmd_len, void *data, size_t data_len)
+{
+ struct spi_slave *spi = flash->spi;
+ int ret;
+
+ ret = spi_claim_bus(flash->spi);
+ if (ret) {
+ debug("SF: unable to claim SPI bus\n");
+ return ret;
+ }
+
+ ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
+ if (ret < 0) {
+ debug("SF: read cmd failed\n");
+ return ret;
+ }
+
+ spi_release_bus(spi);
+
+ return ret;
+}
+
+int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
+ size_t len, void *data)
+{
+ u8 *cmd, cmdsz;
+ u32 remain_len, read_len, read_addr;
+ int bank_sel = 0;
+ int ret = -1;
+
+ /* Handle memory-mapped SPI */
+ if (flash->memory_map) {
+ ret = spi_claim_bus(flash->spi);
+ if (ret) {
+ debug("SF: unable to claim SPI bus\n");
+ return ret;
+ }
+ spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP);
+ memcpy(data, flash->memory_map + offset, len);
+ spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END);
+ spi_release_bus(flash->spi);
+ return 0;
+ }
+
+ cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+ cmd = calloc(1, cmdsz);
+ if (!cmd) {
+ debug("SF: Failed to allocate cmd\n");
+ return -ENOMEM;
+ }
+
+ cmd[0] = flash->read_cmd;
+ while (len) {
+ read_addr = offset;
+
+#ifdef CONFIG_SF_DUAL_FLASH
+ if (flash->dual_flash > SF_SINGLE_FLASH)
+ spi_flash_dual_flash(flash, &read_addr);
+#endif
+#ifdef CONFIG_SPI_FLASH_BAR
+ bank_sel = spi_flash_bank(flash, read_addr);
+ if (bank_sel < 0)
+ return ret;
+#endif
+ remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
+ (bank_sel + 1)) - offset;
+ if (len < remain_len)
+ read_len = len;
+ else
+ read_len = remain_len;
+
+ spi_flash_addr(read_addr, cmd);
+
+ ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
+ if (ret < 0) {
+ debug("SF: read failed\n");
+ break;
+ }
+
+ offset += read_len;
+ len -= read_len;
+ data += read_len;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_SPI_FLASH_SST
+static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
+{
+ int ret;
+ u8 cmd[4] = {
+ CMD_SST_BP,
+ offset >> 16,
+ offset >> 8,
+ offset,
+ };
+
+ debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
+ spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset);
+
+ ret = spi_flash_cmd_write_enable(flash);
+ if (ret)
+ return ret;
+
+ ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1);
+ if (ret)
+ return ret;
+
+ return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+}
+
+int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
+ const void *buf)
+{
+ size_t actual, cmd_len;
+ int ret;
+ u8 cmd[4];
+
+ ret = spi_claim_bus(flash->spi);
+ if (ret) {
+ debug("SF: Unable to claim SPI bus\n");
+ return ret;
+ }
+
+ /* If the data is not word aligned, write out leading single byte */
+ actual = offset % 2;
+ if (actual) {
+ ret = sst_byte_write(flash, offset, buf);
+ if (ret)
+ goto done;
+ }
+ offset += actual;
+
+ ret = spi_flash_cmd_write_enable(flash);
+ if (ret)
+ goto done;
+
+ cmd_len = 4;
+ cmd[0] = CMD_SST_AAI_WP;
+ cmd[1] = offset >> 16;
+ cmd[2] = offset >> 8;
+ cmd[3] = offset;
+
+ for (; actual < len - 1; actual += 2) {
+ debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
+ spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual,
+ cmd[0], offset);
+
+ ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len,
+ buf + actual, 2);
+ if (ret) {
+ debug("SF: sst word program failed\n");
+ break;
+ }
+
+ ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+ if (ret)
+ break;
+
+ cmd_len = 1;
+ offset += 2;
+ }
+
+ if (!ret)
+ ret = spi_flash_cmd_write_disable(flash);
+
+ /* If there is a single trailing byte, write it out */
+ if (!ret && actual != len)
+ ret = sst_byte_write(flash, offset, buf + actual);
+
+ done:
+ debug("SF: sst: program %s %zu bytes @ 0x%zx\n",
+ ret ? "failure" : "success", len, offset - actual);
+
+ spi_release_bus(flash->spi);
+ return ret;
+}
+#endif
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/sf_params.c b/qemu/roms/u-boot/drivers/mtd/spi/sf_params.c
new file mode 100644
index 000000000..eb372b757
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/sf_params.c
@@ -0,0 +1,131 @@
+/*
+ * SPI flash Params table
+ *
+ * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi_flash.h>
+
+#include "sf_internal.h"
+
+/* SPI/QSPI flash device params structure */
+const struct spi_flash_params spi_flash_params_table[] = {
+#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */
+ {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, 0, SECT_4K},
+ {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, 0, SECT_4K},
+ {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, 0, SECT_4K},
+ {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, 0, SECT_4K},
+ {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, 0, SECT_4K},
+ {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, 0, SECT_4K},
+ {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, 0, SECT_4K},
+ {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, 0, SECT_4K},
+#endif
+#ifdef CONFIG_SPI_FLASH_EON /* EON */
+ {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0, 0},
+ {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, 0, SECT_4K},
+ {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0, 0},
+ {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0, 0},
+#endif
+#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */
+ {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, 0, SECT_4K},
+ {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, 0, SECT_4K},
+#endif
+#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */
+ {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0, 0},
+ {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0, 0},
+ {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0, 0},
+ {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0, 0},
+ {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0, 0},
+ {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0, 0},
+ {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
+ {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP},
+ {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP},
+ {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
+#endif
+#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */
+ {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0, 0},
+ {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0, 0},
+ {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0, 0},
+ {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0, 0},
+ {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, RD_FULL, WR_QPP},
+ {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, RD_FULL, WR_QPP},
+ {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, RD_FULL, WR_QPP},
+ {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, RD_FULL, WR_QPP},
+ {"S25FL128S_256K", 0x012018, 0x4d00, 256 * 1024, 64, RD_FULL, WR_QPP},
+ {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, RD_FULL, WR_QPP},
+ {"S25FL256S_256K", 0x010219, 0x4d00, 256 * 1024, 128, RD_FULL, WR_QPP},
+ {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_FULL, WR_QPP},
+ {"S25FL512S_256K", 0x010220, 0x4d00, 256 * 1024, 256, RD_FULL, WR_QPP},
+ {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, RD_FULL, WR_QPP},
+#endif
+#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */
+ {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0, 0},
+ {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0, 0},
+ {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0, 0},
+ {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0, 0},
+ {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0, 0},
+ {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0, 0},
+ {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0, 0},
+ {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0, 0},
+ {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
+ {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
+ {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
+ {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
+ {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
+ {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
+ {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K},
+ {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K},
+ {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP | E_FSR | SECT_4K},
+ {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP | E_FSR | SECT_4K},
+ {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
+ {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
+#endif
+#ifdef CONFIG_SPI_FLASH_SST /* SST */
+ {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP},
+ {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP},
+ {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, 0, SECT_4K | SST_WP},
+ {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, 0, SECT_4K | SST_WP},
+ {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, 0, SECT_4K},
+ {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, 0, SECT_4K | SST_WP},
+ {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, 0, SECT_4K | SST_WP},
+ {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, 0, SECT_4K | SST_WP},
+ {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP},
+ {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP},
+#endif
+#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */
+ {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0, 0},
+ {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0, 0},
+ {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0, 0},
+ {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, 0, SECT_4K},
+ {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, 0, SECT_4K},
+ {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, 0, SECT_4K},
+ {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 0, SECT_4K},
+ {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K},
+ {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K},
+ {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
+ {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
+ {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K},
+ {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K},
+ {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K},
+ {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K},
+ {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
+ {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
+ {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K},
+#endif
+ /*
+ * Note:
+ * Below paired flash devices has similar spi_flash params.
+ * (S25FL129P_64K, S25FL128S_64K)
+ * (W25Q80BL, W25Q80BV)
+ * (W25Q16CL, W25Q16DV)
+ * (W25Q32BV, W25Q32FV_SPI)
+ * (W25Q64CV, W25Q64FV_SPI)
+ * (W25Q128BV, W25Q128FV_SPI)
+ * (W25Q32DW, W25Q32FV_QPI)
+ * (W25Q64DW, W25Q64FV_QPI)
+ * (W25Q128FW, W25Q128FV_QPI)
+ */
+};
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/sf_probe.c b/qemu/roms/u-boot/drivers/mtd/spi/sf_probe.c
new file mode 100644
index 000000000..0a46fe38d
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/sf_probe.c
@@ -0,0 +1,391 @@
+/*
+ * SPI flash probing
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
+ * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <asm/io.h>
+
+#include "sf_internal.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Read commands array */
+static u8 spi_read_cmds_array[] = {
+ CMD_READ_ARRAY_SLOW,
+ CMD_READ_DUAL_OUTPUT_FAST,
+ CMD_READ_DUAL_IO_FAST,
+ CMD_READ_QUAD_OUTPUT_FAST,
+ CMD_READ_QUAD_IO_FAST,
+};
+
+#ifdef CONFIG_SPI_FLASH_MACRONIX
+static int spi_flash_set_qeb_mxic(struct spi_flash *flash)
+{
+ u8 qeb_status;
+ int ret;
+
+ ret = spi_flash_cmd_read_status(flash, &qeb_status);
+ if (ret < 0)
+ return ret;
+
+ if (qeb_status & STATUS_QEB_MXIC) {
+ debug("SF: mxic: QEB is already set\n");
+ } else {
+ ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+#endif
+
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+static int spi_flash_set_qeb_winspan(struct spi_flash *flash)
+{
+ u8 qeb_status;
+ int ret;
+
+ ret = spi_flash_cmd_read_config(flash, &qeb_status);
+ if (ret < 0)
+ return ret;
+
+ if (qeb_status & STATUS_QEB_WINSPAN) {
+ debug("SF: winspan: QEB is already set\n");
+ } else {
+ ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+#endif
+
+static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0)
+{
+ switch (idcode0) {
+#ifdef CONFIG_SPI_FLASH_MACRONIX
+ case SPI_FLASH_CFI_MFR_MACRONIX:
+ return spi_flash_set_qeb_mxic(flash);
+#endif
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+ case SPI_FLASH_CFI_MFR_SPANSION:
+ case SPI_FLASH_CFI_MFR_WINBOND:
+ return spi_flash_set_qeb_winspan(flash);
+#endif
+#ifdef CONFIG_SPI_FLASH_STMICRO
+ case SPI_FLASH_CFI_MFR_STMICRO:
+ debug("SF: QEB is volatile for %02x flash\n", idcode0);
+ return 0;
+#endif
+ default:
+ printf("SF: Need set QEB func for %02x flash\n", idcode0);
+ return -1;
+ }
+}
+
+static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
+ u8 *idcode)
+{
+ const struct spi_flash_params *params;
+ struct spi_flash *flash;
+ u8 cmd;
+ u16 jedec = idcode[1] << 8 | idcode[2];
+ u16 ext_jedec = idcode[3] << 8 | idcode[4];
+
+ params = spi_flash_params_table;
+ for (; params->name != NULL; params++) {
+ if ((params->jedec >> 16) == idcode[0]) {
+ if ((params->jedec & 0xFFFF) == jedec) {
+ if (params->ext_jedec == 0)
+ break;
+ else if (params->ext_jedec == ext_jedec)
+ break;
+ }
+ }
+ }
+
+ if (!params->name) {
+ printf("SF: Unsupported flash IDs: ");
+ printf("manuf %02x, jedec %04x, ext_jedec %04x\n",
+ idcode[0], jedec, ext_jedec);
+ return NULL;
+ }
+
+ flash = calloc(1, sizeof(*flash));
+ if (!flash) {
+ debug("SF: Failed to allocate spi_flash\n");
+ return NULL;
+ }
+
+ /* Assign spi data */
+ flash->spi = spi;
+ flash->name = params->name;
+ flash->memory_map = spi->memory_map;
+ flash->dual_flash = flash->spi->option;
+
+ /* Assign spi_flash ops */
+ flash->write = spi_flash_cmd_write_ops;
+#ifdef CONFIG_SPI_FLASH_SST
+ if (params->flags & SST_WP)
+ flash->write = sst_write_wp;
+#endif
+ flash->erase = spi_flash_cmd_erase_ops;
+ flash->read = spi_flash_cmd_read_ops;
+
+ /* Compute the flash size */
+ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
+ /*
+ * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the
+ * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with
+ * the 0x4d00 Extended JEDEC code have 512b pages. All of the others
+ * have 256b pages.
+ */
+ if (ext_jedec == 0x4d00) {
+ if ((jedec == 0x0215) || (jedec == 0x216))
+ flash->page_size = 256;
+ else
+ flash->page_size = 512;
+ } else {
+ flash->page_size = 256;
+ }
+ flash->page_size <<= flash->shift;
+ flash->sector_size = params->sector_size << flash->shift;
+ flash->size = flash->sector_size * params->nr_sectors << flash->shift;
+#ifdef CONFIG_SF_DUAL_FLASH
+ if (flash->dual_flash & SF_DUAL_STACKED_FLASH)
+ flash->size <<= 1;
+#endif
+
+ /* Compute erase sector and command */
+ if (params->flags & SECT_4K) {
+ flash->erase_cmd = CMD_ERASE_4K;
+ flash->erase_size = 4096 << flash->shift;
+ } else if (params->flags & SECT_32K) {
+ flash->erase_cmd = CMD_ERASE_32K;
+ flash->erase_size = 32768 << flash->shift;
+ } else {
+ flash->erase_cmd = CMD_ERASE_64K;
+ flash->erase_size = flash->sector_size;
+ }
+
+ /* Look for the fastest read cmd */
+ cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx);
+ if (cmd) {
+ cmd = spi_read_cmds_array[cmd - 1];
+ flash->read_cmd = cmd;
+ } else {
+ /* Go for default supported read cmd */
+ flash->read_cmd = CMD_READ_ARRAY_FAST;
+ }
+
+ /* Not require to look for fastest only two write cmds yet */
+ if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP)
+ flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
+ else
+ /* Go for default supported write cmd */
+ flash->write_cmd = CMD_PAGE_PROGRAM;
+
+ /* Set the quad enable bit - only for quad commands */
+ if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
+ (flash->read_cmd == CMD_READ_QUAD_IO_FAST) ||
+ (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
+ if (spi_flash_set_qeb(flash, idcode[0])) {
+ debug("SF: Fail to set QEB for %02x\n", idcode[0]);
+ return NULL;
+ }
+ }
+
+ /* Read dummy_byte: dummy byte is determined based on the
+ * dummy cycles of a particular command.
+ * Fast commands - dummy_byte = dummy_cycles/8
+ * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8
+ * For I/O commands except cmd[0] everything goes on no.of lines
+ * based on particular command but incase of fast commands except
+ * data all go on single line irrespective of command.
+ */
+ switch (flash->read_cmd) {
+ case CMD_READ_QUAD_IO_FAST:
+ flash->dummy_byte = 2;
+ break;
+ case CMD_READ_ARRAY_SLOW:
+ flash->dummy_byte = 0;
+ break;
+ default:
+ flash->dummy_byte = 1;
+ }
+
+ /* Poll cmd selection */
+ flash->poll_cmd = CMD_READ_STATUS;
+#ifdef CONFIG_SPI_FLASH_STMICRO
+ if (params->flags & E_FSR)
+ flash->poll_cmd = CMD_FLAG_STATUS;
+#endif
+
+ /* Configure the BAR - discover bank cmds and read current bank */
+#ifdef CONFIG_SPI_FLASH_BAR
+ u8 curr_bank = 0;
+ if (flash->size > SPI_FLASH_16MB_BOUN) {
+ flash->bank_read_cmd = (idcode[0] == 0x01) ?
+ CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR;
+ flash->bank_write_cmd = (idcode[0] == 0x01) ?
+ CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR;
+
+ if (spi_flash_read_common(flash, &flash->bank_read_cmd, 1,
+ &curr_bank, 1)) {
+ debug("SF: fail to read bank addr register\n");
+ return NULL;
+ }
+ flash->bank_curr = curr_bank;
+ } else {
+ flash->bank_curr = curr_bank;
+ }
+#endif
+
+ /* Flash powers up read-only, so clear BP# bits */
+#if defined(CONFIG_SPI_FLASH_ATMEL) || \
+ defined(CONFIG_SPI_FLASH_MACRONIX) || \
+ defined(CONFIG_SPI_FLASH_SST)
+ spi_flash_cmd_write_status(flash, 0);
+#endif
+
+ return flash;
+}
+
+#ifdef CONFIG_OF_CONTROL
+int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
+{
+ fdt_addr_t addr;
+ fdt_size_t size;
+ int node;
+
+ /* If there is no node, do nothing */
+ node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
+ if (node < 0)
+ return 0;
+
+ addr = fdtdec_get_addr_size(blob, node, "memory-map", &size);
+ if (addr == FDT_ADDR_T_NONE) {
+ debug("%s: Cannot decode address\n", __func__);
+ return 0;
+ }
+
+ if (flash->size != size) {
+ debug("%s: Memory map must cover entire device\n", __func__);
+ return -1;
+ }
+ flash->memory_map = map_sysmem(addr, size);
+
+ return 0;
+}
+#endif /* CONFIG_OF_CONTROL */
+
+static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
+{
+ struct spi_flash *flash = NULL;
+ u8 idcode[5];
+ int ret;
+
+ /* Setup spi_slave */
+ if (!spi) {
+ printf("SF: Failed to set up slave\n");
+ return NULL;
+ }
+
+ /* Claim spi bus */
+ ret = spi_claim_bus(spi);
+ if (ret) {
+ debug("SF: Failed to claim SPI bus: %d\n", ret);
+ goto err_claim_bus;
+ }
+
+ /* Read the ID codes */
+ ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
+ if (ret) {
+ printf("SF: Failed to get idcodes\n");
+ goto err_read_id;
+ }
+
+#ifdef DEBUG
+ printf("SF: Got idcodes\n");
+ print_buffer(0, idcode, 1, sizeof(idcode), 0);
+#endif
+
+ /* Validate params from spi_flash_params table */
+ flash = spi_flash_validate_params(spi, idcode);
+ if (!flash)
+ goto err_read_id;
+
+#ifdef CONFIG_OF_CONTROL
+ if (spi_flash_decode_fdt(gd->fdt_blob, flash)) {
+ debug("SF: FDT decode error\n");
+ goto err_read_id;
+ }
+#endif
+#ifndef CONFIG_SPL_BUILD
+ printf("SF: Detected %s with page size ", flash->name);
+ print_size(flash->page_size, ", erase size ");
+ print_size(flash->erase_size, ", total ");
+ print_size(flash->size, "");
+ if (flash->memory_map)
+ printf(", mapped at %p", flash->memory_map);
+ puts("\n");
+#endif
+#ifndef CONFIG_SPI_FLASH_BAR
+ if (((flash->dual_flash == SF_SINGLE_FLASH) &&
+ (flash->size > SPI_FLASH_16MB_BOUN)) ||
+ ((flash->dual_flash > SF_SINGLE_FLASH) &&
+ (flash->size > SPI_FLASH_16MB_BOUN << 1))) {
+ puts("SF: Warning - Only lower 16MiB accessible,");
+ puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
+ }
+#endif
+
+ /* Release spi bus */
+ spi_release_bus(spi);
+
+ return flash;
+
+err_read_id:
+ spi_release_bus(spi);
+err_claim_bus:
+ spi_free_slave(spi);
+ return NULL;
+}
+
+struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int spi_mode)
+{
+ struct spi_slave *spi;
+
+ spi = spi_setup_slave(bus, cs, max_hz, spi_mode);
+ return spi_flash_probe_slave(spi);
+}
+
+#ifdef CONFIG_OF_SPI_FLASH
+struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node,
+ int spi_node)
+{
+ struct spi_slave *spi;
+
+ spi = spi_setup_slave_fdt(blob, slave_node, spi_node);
+ return spi_flash_probe_slave(spi);
+}
+#endif
+
+void spi_flash_free(struct spi_flash *flash)
+{
+ spi_free_slave(flash->spi);
+ free(flash);
+}
diff --git a/qemu/roms/u-boot/drivers/mtd/spi/spi_spl_load.c b/qemu/roms/u-boot/drivers/mtd/spi/spi_spl_load.c
new file mode 100644
index 000000000..1954b7e88
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/mtd/spi/spi_spl_load.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 OMICRON electronics GmbH
+ *
+ * based on drivers/mtd/nand/nand_spl_load.c
+ *
+ * Copyright (C) 2011
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi_flash.h>
+#include <spl.h>
+
+#ifdef CONFIG_SPL_OS_BOOT
+/*
+ * Load the kernel, check for a valid header we can parse, and if found load
+ * the kernel and then device tree.
+ */
+static int spi_load_image_os(struct spi_flash *flash,
+ struct image_header *header)
+{
+ /* Read for a header, parse or error out. */
+ spi_flash_read(flash, CONFIG_SYS_SPI_KERNEL_OFFS, 0x40,
+ (void *)header);
+
+ if (image_get_magic(header) != IH_MAGIC)
+ return -1;
+
+ spl_parse_image_header(header);
+
+ spi_flash_read(flash, CONFIG_SYS_SPI_KERNEL_OFFS,
+ spl_image.size, (void *)spl_image.load_addr);
+
+ /* Read device tree. */
+ spi_flash_read(flash, CONFIG_SYS_SPI_ARGS_OFFS,
+ CONFIG_SYS_SPI_ARGS_SIZE,
+ (void *)CONFIG_SYS_SPL_ARGS_ADDR);
+
+ return 0;
+}
+#endif
+
+/*
+ * The main entry for SPI booting. It's necessary that SDRAM is already
+ * configured and available since this code loads the main U-Boot image
+ * from SPI into SDRAM and starts it from there.
+ */
+void spl_spi_load_image(void)
+{
+ struct spi_flash *flash;
+ struct image_header *header;
+
+ /*
+ * Load U-Boot image from SPI flash into RAM
+ */
+
+ flash = spi_flash_probe(CONFIG_SPL_SPI_BUS, CONFIG_SPL_SPI_CS,
+ CONFIG_SF_DEFAULT_SPEED, SPI_MODE_3);
+ if (!flash) {
+ puts("SPI probe failed.\n");
+ hang();
+ }
+
+ /* use CONFIG_SYS_TEXT_BASE as temporary storage area */
+ header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+
+#ifdef CONFIG_SPL_OS_BOOT
+ if (spl_start_uboot() || spi_load_image_os(flash, header))
+#endif
+ {
+ /* Load u-boot, mkimage header is 64 bytes. */
+ spi_flash_read(flash, CONFIG_SYS_SPI_U_BOOT_OFFS, 0x40,
+ (void *)header);
+ spl_parse_image_header(header);
+ spi_flash_read(flash, CONFIG_SYS_SPI_U_BOOT_OFFS,
+ spl_image.size, (void *)spl_image.load_addr);
+ }
+}