diff options
author | Tom Rini <trini@ti.com> | 2014-10-22 13:51:45 -0400 |
---|---|---|
committer | Tom Rini <trini@ti.com> | 2014-10-22 13:51:45 -0400 |
commit | 68e80fdda1336068f40915388bbdacfd2b75233a (patch) | |
tree | deb28e65fdd601e47bf5564f67da3035a840e284 /drivers/mtd | |
parent | 35d4fed320d577a4446531d7b9350ce40065c4b0 (diff) | |
parent | 8a9cd5ad6f89ab721a352cbb9264bea5ede68789 (diff) | |
download | u-boot-imx-68e80fdda1336068f40915388bbdacfd2b75233a.zip u-boot-imx-68e80fdda1336068f40915388bbdacfd2b75233a.tar.gz u-boot-imx-68e80fdda1336068f40915388bbdacfd2b75233a.tar.bz2 |
Merge git://git.denx.de/u-boot-dm
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/spi/Makefile | 7 | ||||
-rw-r--r-- | drivers/mtd/spi/ramtron.c | 1 | ||||
-rw-r--r-- | drivers/mtd/spi/sandbox.c | 338 | ||||
-rw-r--r-- | drivers/mtd/spi/sf-uclass.c | 63 | ||||
-rw-r--r-- | drivers/mtd/spi/sf_internal.h | 67 | ||||
-rw-r--r-- | drivers/mtd/spi/sf_params.c | 1 | ||||
-rw-r--r-- | drivers/mtd/spi/sf_probe.c | 154 | ||||
-rw-r--r-- | drivers/mtd/spi/spi_spl_load.c | 1 |
8 files changed, 543 insertions, 89 deletions
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 9e18fb4..15789a0 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -5,13 +5,18 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_DM_SPI_FLASH) += sf-uclass.o + ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SPL_SPI_LOAD) += spi_spl_load.o obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o endif +#ifndef CONFIG_DM_SPI +obj-$(CONFIG_SPI_FLASH) += sf_probe.o +#endif obj-$(CONFIG_CMD_SF) += sf.o -obj-$(CONFIG_SPI_FLASH) += sf_params.o sf_probe.o sf_ops.o +obj-$(CONFIG_SPI_FLASH) += sf_ops.o sf_params.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/drivers/mtd/spi/ramtron.c b/drivers/mtd/spi/ramtron.c index d50da37..a23032c 100644 --- a/drivers/mtd/spi/ramtron.c +++ b/drivers/mtd/spi/ramtron.c @@ -35,6 +35,7 @@ #include <common.h> #include <malloc.h> +#include <spi.h> #include <spi_flash.h> #include "sf_internal.h" diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 98e0a34..1cf2f98 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -9,6 +9,7 @@ */ #include <common.h> +#include <dm.h> #include <malloc.h> #include <spi.h> #include <os.h> @@ -19,6 +20,11 @@ #include <asm/getopt.h> #include <asm/spi.h> #include <asm/state.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/uclass-internal.h> + +DECLARE_GLOBAL_DATA_PTR; /* * The different states that our SPI flash transitions between. @@ -34,12 +40,14 @@ enum sandbox_sf_state { 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*/ + SF_WRITE_STATUS, /* write the flash's status register */ }; 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", + "READ_STATUS1", "WRITE_STATUS", }; return states[state]; } @@ -58,6 +66,7 @@ static u8 sandbox_sf_0xff[0x1000]; /* Internal state data for each SPI flash */ struct sandbox_spi_flash { + unsigned int cs; /* Chip select we are attached to */ /* * As we receive data over the SPI bus, our flash transitions * between states. For example, we start off in the SF_CMD @@ -84,71 +93,124 @@ struct sandbox_spi_flash { int fd; }; -static int sandbox_sf_setup(void **priv, const char *spec) +struct sandbox_spi_flash_plat_data { + const char *filename; + const char *device_name; + int bus; + int cs; +}; + +/** + * This is a very strange probe function. If it has platform data (which may + * have come from the device tree) then this function gets the filename and + * device type from there. Failing that it looks at the command line + * parameter. + */ +static int sandbox_sf_probe(struct udevice *dev) { /* spec = idcode:file */ - struct sandbox_spi_flash *sbsf; + struct sandbox_spi_flash *sbsf = dev_get_priv(dev); const char *file; size_t len, idname_len; const struct spi_flash_params *data; - - file = strchr(spec, ':'); - if (!file) { - printf("sandbox_sf: unable to parse file\n"); - goto error; + struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev); + struct sandbox_state *state = state_get_current(); + struct udevice *bus = dev->parent; + const char *spec = NULL; + int ret = 0; + int cs = -1; + int i; + + debug("%s: bus %d, looking for emul=%p: ", __func__, bus->seq, dev); + if (bus->seq >= 0 && bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS) { + for (i = 0; i < CONFIG_SANDBOX_SPI_MAX_CS; i++) { + if (state->spi[bus->seq][i].emul == dev) + cs = i; + } + } + if (cs == -1) { + printf("Error: Unknown chip select for device '%s'", + dev->name); + return -EINVAL; + } + debug("found at cs %d\n", cs); + + if (!pdata->filename) { + struct sandbox_state *state = state_get_current(); + + assert(bus->seq != -1); + if (bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS) + spec = state->spi[bus->seq][cs].spec; + if (!spec) + return -ENOENT; + + file = strchr(spec, ':'); + if (!file) { + printf("sandbox_sf: unable to parse file\n"); + ret = -EINVAL; + goto error; + } + idname_len = file - spec; + pdata->filename = file + 1; + pdata->device_name = spec; + ++file; + } else { + spec = strchr(pdata->device_name, ','); + if (spec) + spec++; + else + spec = pdata->device_name; + idname_len = strlen(spec); } - idname_len = file - spec; - ++file; + debug("%s: device='%s'\n", __func__, spec); for (data = spi_flash_params_table; data->name; data++) { len = strlen(data->name); if (idname_len != len) continue; - if (!memcmp(spec, data->name, len)) + if (!strncasecmp(spec, data->name, len)) break; } if (!data->name) { printf("sandbox_sf: unknown flash '%*s'\n", (int)idname_len, spec); + ret = -EINVAL; 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); + sbsf->fd = os_open(pdata->filename, 02); if (sbsf->fd == -1) { free(sbsf); - printf("sandbox_sf: unable to open file '%s'\n", file); + printf("sandbox_sf: unable to open file '%s'\n", + pdata->filename); + ret = -EIO; goto error; } sbsf->data = data; + sbsf->cs = cs; - *priv = sbsf; return 0; error: - return 1; + return ret; } -static void sandbox_sf_free(void *priv) +static int sandbox_sf_remove(struct udevice *dev) { - struct sandbox_spi_flash *sbsf = priv; + struct sandbox_spi_flash *sbsf = dev_get_priv(dev); os_close(sbsf->fd); - free(sbsf); + + return 0; } -static void sandbox_sf_cs_activate(void *priv) +static void sandbox_sf_cs_activate(struct udevice *dev) { - struct sandbox_spi_flash *sbsf = priv; + struct sandbox_spi_flash *sbsf = dev_get_priv(dev); debug("sandbox_sf: CS activated; state is fresh!\n"); @@ -160,11 +222,24 @@ static void sandbox_sf_cs_activate(void *priv) sbsf->cmd = SF_CMD; } -static void sandbox_sf_cs_deactivate(void *priv) +static void sandbox_sf_cs_deactivate(struct udevice *dev) { debug("sandbox_sf: CS deactivated; cmd done processing!\n"); } +/* + * There are times when the data lines are allowed to tristate. What + * is actually sensed on the line depends on the hardware. It could + * always be 0xFF/0x00 (if there are pull ups/downs), or things could + * float and so we'd get garbage back. This func encapsulates that + * scenario so we can worry about the details here. + */ +static void sandbox_spi_tristate(u8 *buf, uint len) +{ + /* XXX: make this into a user config option ? */ + memset(buf, 0xff, len); +} + /* 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) @@ -172,7 +247,8 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx, 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); + if (tx) + sandbox_spi_tristate(tx, 1); sbsf->cmd = rx[0]; switch (sbsf->cmd) { @@ -200,6 +276,9 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx, debug(" write enabled\n"); sbsf->status |= STAT_WEL; break; + case CMD_WRITE_STATUS: + sbsf->state = SF_WRITE_STATUS; + break; default: { int flags = sbsf->data->flags; @@ -216,7 +295,7 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx, sbsf->erase_size = 64 << 10; } else { debug(" cmd unknown: %#x\n", sbsf->cmd); - return 1; + return -EIO; } sbsf->state = SF_ADDR; break; @@ -246,20 +325,27 @@ int sandbox_erase_part(struct sandbox_spi_flash *sbsf, int size) return 0; } -static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx, - uint bytes) +static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, + const void *rxp, void *txp, unsigned long flags) { - struct sandbox_spi_flash *sbsf = priv; + struct sandbox_spi_flash *sbsf = dev_get_priv(dev); + const uint8_t *rx = rxp; + uint8_t *tx = txp; uint cnt, pos = 0; + int bytes = bitlen / 8; int ret; debug("sandbox_sf: state:%x(%s) bytes:%u\n", sbsf->state, sandbox_sf_state_name(sbsf->state), bytes); + if ((flags & SPI_XFER_BEGIN)) + sandbox_sf_cs_activate(dev); + if (sbsf->state == SF_CMD) { /* Figure out the initial state */ - if (sandbox_sf_process_cmd(sbsf, rx, tx)) - return 1; + ret = sandbox_sf_process_cmd(sbsf, rx, tx); + if (ret) + return ret; ++pos; } @@ -290,7 +376,9 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx, sbsf->off = (sbsf->off << 8) | rx[pos]; debug("addr:%06x\n", sbsf->off); - sandbox_spi_tristate(&tx[pos++], 1); + if (tx) + sandbox_spi_tristate(&tx[pos], 1); + pos++; /* See if we're done processing */ if (sbsf->addr_bytes < @@ -300,7 +388,7 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx, /* Next state! */ if (os_lseek(sbsf->fd, sbsf->off, OS_SEEK_SET) < 0) { puts("sandbox_sf: os_lseek() failed"); - return 1; + return -EIO; } switch (sbsf->cmd) { case CMD_READ_ARRAY_FAST: @@ -326,10 +414,11 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx, cnt = bytes - pos; debug(" tx: read(%u)\n", cnt); + assert(tx); ret = os_read(sbsf->fd, tx + pos, cnt); if (ret < 0) { - puts("sandbox_spi: os_read() failed\n"); - return 1; + puts("sandbox_sf: os_read() failed\n"); + return -EIO; } pos += ret; break; @@ -345,6 +434,10 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx, memset(tx + pos, sbsf->status >> 8, cnt); pos += cnt; break; + case SF_WRITE_STATUS: + debug(" write status: %#x (ignored)\n", rx[pos]); + pos = bytes; + break; case SF_WRITE: /* * XXX: need to handle exotic behavior: @@ -359,11 +452,12 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx, cnt = bytes - pos; debug(" rx: write(%u)\n", cnt); - sandbox_spi_tristate(&tx[pos], cnt); + if (tx) + 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; + return -EIO; } pos += ret; sbsf->status &= ~STAT_WEL; @@ -388,7 +482,8 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx, sbsf->erase_size); cnt = bytes - pos; - sandbox_spi_tristate(&tx[pos], cnt); + if (tx) + sandbox_spi_tristate(&tx[pos], cnt); pos += cnt; /* @@ -410,17 +505,33 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx, } done: - return pos == bytes ? 0 : 1; + if (flags & SPI_XFER_END) + sandbox_sf_cs_deactivate(dev); + return pos == bytes ? 0 : -EIO; +} + +int sandbox_sf_ofdata_to_platdata(struct udevice *dev) +{ + struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev); + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + + pdata->filename = fdt_getprop(blob, node, "sandbox,filename", NULL); + pdata->device_name = fdt_getprop(blob, node, "compatible", NULL); + if (!pdata->filename || !pdata->device_name) { + debug("%s: Missing properties, filename=%s, device_name=%s\n", + __func__, pdata->filename, pdata->device_name); + return -EINVAL; + } + + return 0; } -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, +static const struct dm_spi_emul_ops sandbox_sf_emul_ops = { .xfer = sandbox_sf_xfer, }; +#ifdef CONFIG_SPI_FLASH static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state, const char *arg) { @@ -438,8 +549,141 @@ static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state, * 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>"); + +int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs, + struct udevice *bus, int of_offset, const char *spec) +{ + struct udevice *emul; + char name[20], *str; + struct driver *drv; + int ret; + + /* now the emulator */ + strncpy(name, spec, sizeof(name) - 6); + name[sizeof(name) - 6] = '\0'; + strcat(name, "-emul"); + str = strdup(name); + if (!str) + return -ENOMEM; + drv = lists_driver_lookup_name("sandbox_sf_emul"); + if (!drv) { + puts("Cannot find sandbox_sf_emul driver\n"); + return -ENOENT; + } + ret = device_bind(bus, drv, str, NULL, of_offset, &emul); + if (ret) { + printf("Cannot create emul device for spec '%s' (err=%d)\n", + spec, ret); + return ret; + } + state->spi[busnum][cs].emul = emul; + + return 0; +} + +void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs) +{ + state->spi[busnum][cs].emul = NULL; +} + +static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum, + int cs, const char *spec) +{ + struct udevice *bus, *slave; + int ret; + + ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, true, &bus); + if (ret) { + printf("Invalid bus %d for spec '%s' (err=%d)\n", busnum, + spec, ret); + return ret; + } + ret = device_find_child_by_seq(bus, cs, true, &slave); + if (!ret) { + printf("Chip select %d already exists for spec '%s'\n", cs, + spec); + return -EEXIST; + } + + ret = spi_bind_device(bus, cs, "spi_flash_std", spec, &slave); + if (ret) + return ret; + + return sandbox_sf_bind_emul(state, busnum, cs, bus, -1, spec); +} + +int sandbox_spi_get_emul(struct sandbox_state *state, + struct udevice *bus, struct udevice *slave, + struct udevice **emulp) +{ + struct sandbox_spi_info *info; + int busnum = bus->seq; + int cs = spi_chip_select(slave); + int ret; + + info = &state->spi[busnum][cs]; + if (!info->emul) { + /* Use the same device tree node as the SPI flash device */ + debug("%s: busnum=%u, cs=%u: binding SPI flash emulation: ", + __func__, busnum, cs); + ret = sandbox_sf_bind_emul(state, busnum, cs, bus, + slave->of_offset, slave->name); + if (ret) { + debug("failed (err=%d)\n", ret); + return ret; + } + debug("OK\n"); + } + *emulp = info->emul; + + return 0; +} + +int dm_scan_other(bool pre_reloc_only) +{ + struct sandbox_state *state = state_get_current(); + int busnum, cs; + + if (pre_reloc_only) + return 0; + for (busnum = 0; busnum < CONFIG_SANDBOX_SPI_MAX_BUS; busnum++) { + for (cs = 0; cs < CONFIG_SANDBOX_SPI_MAX_CS; cs++) { + const char *spec = state->spi[busnum][cs].spec; + int ret; + + if (spec) { + ret = sandbox_sf_bind_bus_cs(state, busnum, + cs, spec); + if (ret) { + debug("%s: Bind failed for bus %d, cs %d\n", + __func__, busnum, cs); + return ret; + } + } + } + } + + return 0; +} +#endif + +static const struct udevice_id sandbox_sf_ids[] = { + { .compatible = "sandbox,spi-flash" }, + { } +}; + +U_BOOT_DRIVER(sandbox_sf_emul) = { + .name = "sandbox_sf_emul", + .id = UCLASS_SPI_EMUL, + .of_match = sandbox_sf_ids, + .ofdata_to_platdata = sandbox_sf_ofdata_to_platdata, + .probe = sandbox_sf_probe, + .remove = sandbox_sf_remove, + .priv_auto_alloc_size = sizeof(struct sandbox_spi_flash), + .platdata_auto_alloc_size = sizeof(struct sandbox_spi_flash_plat_data), + .ops = &sandbox_sf_emul_ops, +}; diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c new file mode 100644 index 0000000..376d815 --- /dev/null +++ b/drivers/mtd/spi/sf-uclass.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <spi.h> +#include <spi_flash.h> +#include <dm/device-internal.h> +#include "sf_internal.h" + +/* + * TODO(sjg@chromium.org): This is an old-style function. We should remove + * it when all SPI flash drivers use dm + */ +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct udevice *dev; + + if (spi_flash_probe_bus_cs(bus, cs, max_hz, spi_mode, &dev)) + return NULL; + + return dev->uclass_priv; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_flash_remove(flash->spi->dev); +} + +int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode, + struct udevice **devp) +{ + struct spi_slave *slave; + struct udevice *bus; + char name[20], *str; + int ret; + + snprintf(name, sizeof(name), "%d:%d", busnum, cs); + str = strdup(name); + ret = spi_get_bus_and_cs(busnum, cs, max_hz, spi_mode, + "spi_flash_std", str, &bus, &slave); + if (ret) + return ret; + + *devp = slave->dev; + return 0; +} + +int spi_flash_remove(struct udevice *dev) +{ + return device_remove(dev); +} + +UCLASS_DRIVER(spi_flash) = { + .id = UCLASS_SPI_FLASH, + .name = "spi_flash", + .per_device_auto_alloc_size = sizeof(struct spi_flash), +}; diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 19d4914..5b7670c 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -10,6 +10,36 @@ #ifndef _SF_INTERNAL_H_ #define _SF_INTERNAL_H_ +#include <linux/types.h> +#include <linux/compiler.h> + +/* Dual SPI flash memories - see SPI_COMM_DUAL_... */ +enum spi_dual_flash { + SF_SINGLE_FLASH = 0, + SF_DUAL_STACKED_FLASH = 1 << 0, + SF_DUAL_PARALLEL_FLASH = 1 << 1, +}; + +/* Enum list - Full read commands */ +enum spi_read_cmds { + ARRAY_SLOW = 1 << 0, + DUAL_OUTPUT_FAST = 1 << 1, + DUAL_IO_FAST = 1 << 2, + QUAD_OUTPUT_FAST = 1 << 3, + QUAD_IO_FAST = 1 << 4, +}; + +#define RD_EXTN (ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST) +#define RD_FULL (RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST) + +/* sf param flags */ +enum { + SECT_4K = 1 << 0, + SECT_32K = 1 << 1, + E_FSR = 1 << 2, + WR_QPP = 1 << 3, +}; + #define SPI_FLASH_3B_ADDR_LEN 3 #define SPI_FLASH_CMD_LEN (1 + SPI_FLASH_3B_ADDR_LEN) #define SPI_FLASH_16MB_BOUN 0x1000000 @@ -30,12 +60,12 @@ #define CMD_WRITE_STATUS 0x01 #define CMD_PAGE_PROGRAM 0x02 #define CMD_WRITE_DISABLE 0x04 -#define CMD_READ_STATUS 0x05 +#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 +#define CMD_READ_CONFIG 0x35 +#define CMD_FLAG_STATUS 0x70 /* Read commands */ #define CMD_READ_ARRAY_SLOW 0x03 @@ -57,7 +87,7 @@ /* Common status */ #define STATUS_WIP (1 << 0) #define STATUS_QEB_WINSPAN (1 << 1) -#define STATUS_QEB_MXIC (1 << 6) +#define STATUS_QEB_MXIC (1 << 6) #define STATUS_PEC (1 << 7) #ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN @@ -66,19 +96,42 @@ /* 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_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 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 */ +# 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 +/** + * struct spi_flash_params - SPI/QSPI flash device params structure + * + * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) + * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id]) + * @ext_jedec: Device ext_jedec ID + * @sector_size: Sector size of this device + * @nr_sectors: No.of sectors on this device + * @e_rd_cmd: Enum list for read commands + * @flags: Important param, for flash specific behaviour + */ +struct spi_flash_params { + const char *name; + u32 jedec; + u16 ext_jedec; + u32 sector_size; + u32 nr_sectors; + u8 e_rd_cmd; + u16 flags; +}; + +extern const struct spi_flash_params spi_flash_params_table[]; + /* 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); diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c index 453edf0..61545ca 100644 --- a/drivers/mtd/spi/sf_params.c +++ b/drivers/mtd/spi/sf_params.c @@ -7,6 +7,7 @@ */ #include <common.h> +#include <spi.h> #include <spi_flash.h> #include "sf_internal.h" diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 4d148d1..2636426 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -9,6 +9,8 @@ */ #include <common.h> +#include <dm.h> +#include <errno.h> #include <fdtdec.h> #include <malloc.h> #include <spi.h> @@ -95,15 +97,15 @@ static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) } } -static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, - u8 *idcode) +static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, + struct spi_flash *flash) { 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]; + /* Validate params from spi_flash_params table */ params = spi_flash_params_table; for (; params->name != NULL; params++) { if ((params->jedec >> 16) == idcode[0]) { @@ -120,13 +122,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, 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; + return -EPROTONOSUPPORT; } /* Assign spi data */ @@ -136,13 +132,15 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, flash->dual_flash = flash->spi->option; /* Assign spi_flash ops */ +#ifndef CONFIG_DM_SPI_FLASH flash->write = spi_flash_cmd_write_ops; -#ifdef CONFIG_SPI_FLASH_SST +#if defined(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; +#endif /* Compute the flash size */ flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; @@ -227,15 +225,18 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, #ifdef CONFIG_SPI_FLASH_BAR u8 curr_bank = 0; if (flash->size > SPI_FLASH_16MB_BOUN) { + int ret; + 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)) { + ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1, + &curr_bank, 1); + if (ret) { debug("SF: fail to read bank addr register\n"); - return NULL; + return ret; } flash->bank_curr = curr_bank; } else { @@ -250,7 +251,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, spi_flash_cmd_write_status(flash, 0); #endif - return flash; + return 0; } #ifdef CONFIG_OF_CONTROL @@ -309,23 +310,29 @@ static int spi_enable_wp_pin(struct spi_flash *flash) } #endif -static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi) +/** + * spi_flash_probe_slave() - Probe for a SPI flash device on a bus + * + * @spi: Bus to probe + * @flashp: Pointer to place to put flash info, which may be NULL if the + * space should be allocated + */ +int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) { - 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; + return -ENODEV; } /* Claim spi bus */ ret = spi_claim_bus(spi); if (ret) { debug("SF: Failed to claim SPI bus: %d\n", ret); - goto err_claim_bus; + return ret; } /* Read the ID codes */ @@ -340,10 +347,10 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi) 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) + if (spi_flash_validate_params(spi, idcode, flash)) { + ret = -EINVAL; goto err_read_id; + } /* Set the quad enable bit - only for quad commands */ if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || @@ -351,13 +358,15 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi) (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; + ret = -EINVAL; + goto err_read_id; } } #ifdef CONFIG_OF_CONTROL if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { debug("SF: FDT decode error\n"); + ret = -EINVAL; goto err_read_id; } #endif @@ -385,32 +394,51 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi) /* Release spi bus */ spi_release_bus(spi); - return flash; + return 0; err_read_id: spi_release_bus(spi); -err_claim_bus: - spi_free_slave(spi); - return NULL; + return ret; } -struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, +#ifndef CONFIG_DM_SPI_FLASH +struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) +{ + struct spi_flash *flash; + + /* Allocate space if needed (not used by sf-uclass */ + flash = calloc(1, sizeof(*flash)); + if (!flash) { + debug("SF: Failed to allocate spi_flash\n"); + return NULL; + } + + if (spi_flash_probe_slave(bus, flash)) { + spi_free_slave(bus); + free(flash); + return NULL; + } + + return flash; +} + +struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, unsigned int max_hz, unsigned int spi_mode) { - struct spi_slave *spi; + struct spi_slave *bus; - spi = spi_setup_slave(bus, cs, max_hz, spi_mode); - return spi_flash_probe_slave(spi); + bus = spi_setup_slave(busnum, cs, max_hz, spi_mode); + return spi_flash_probe_tail(bus); } #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; + struct spi_slave *bus; - spi = spi_setup_slave_fdt(blob, slave_node, spi_node); - return spi_flash_probe_slave(spi); + bus = spi_setup_slave_fdt(blob, slave_node, spi_node); + return spi_flash_probe_tail(bus); } #endif @@ -419,3 +447,61 @@ void spi_flash_free(struct spi_flash *flash) spi_free_slave(flash->spi); free(flash); } + +#else /* defined CONFIG_DM_SPI_FLASH */ + +static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len, + void *buf) +{ + struct spi_flash *flash = dev->uclass_priv; + + return spi_flash_cmd_read_ops(flash, offset, len, buf); +} + +int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, + const void *buf) +{ + struct spi_flash *flash = dev->uclass_priv; + + return spi_flash_cmd_write_ops(flash, offset, len, buf); +} + +int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) +{ + struct spi_flash *flash = dev->uclass_priv; + + return spi_flash_cmd_erase_ops(flash, offset, len); +} + +int spi_flash_std_probe(struct udevice *dev) +{ + struct spi_slave *slave = dev_get_parentdata(dev); + struct spi_flash *flash; + + flash = dev->uclass_priv; + flash->dev = dev; + debug("%s: slave=%p, cs=%d\n", __func__, slave, slave->cs); + return spi_flash_probe_slave(slave, flash); +} + +static const struct dm_spi_flash_ops spi_flash_std_ops = { + .read = spi_flash_std_read, + .write = spi_flash_std_write, + .erase = spi_flash_std_erase, +}; + +static const struct udevice_id spi_flash_std_ids[] = { + { .compatible = "spi-flash" }, + { } +}; + +U_BOOT_DRIVER(spi_flash_std) = { + .name = "spi_flash_std", + .id = UCLASS_SPI_FLASH, + .of_match = spi_flash_std_ids, + .probe = spi_flash_std_probe, + .priv_auto_alloc_size = sizeof(struct spi_flash), + .ops = &spi_flash_std_ops, +}; + +#endif /* CONFIG_DM_SPI_FLASH */ diff --git a/drivers/mtd/spi/spi_spl_load.c b/drivers/mtd/spi/spi_spl_load.c index 59cca0f..2e0c871 100644 --- a/drivers/mtd/spi/spi_spl_load.c +++ b/drivers/mtd/spi/spi_spl_load.c @@ -10,6 +10,7 @@ */ #include <common.h> +#include <spi.h> #include <spi_flash.h> #include <spl.h> |