summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/spi')
-rw-r--r--drivers/mtd/spi/Makefile7
-rw-r--r--drivers/mtd/spi/ramtron.c1
-rw-r--r--drivers/mtd/spi/sandbox.c338
-rw-r--r--drivers/mtd/spi/sf-uclass.c63
-rw-r--r--drivers/mtd/spi/sf_internal.h67
-rw-r--r--drivers/mtd/spi/sf_params.c1
-rw-r--r--drivers/mtd/spi/sf_probe.c154
-rw-r--r--drivers/mtd/spi/spi_spl_load.c1
8 files changed, 543 insertions, 89 deletions
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 9e18fb41de..15789a07d8 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 d50da37c89..a23032cca5 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 98e0a34d4e..1cf2f98310 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 0000000000..376d815026
--- /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 19d49146eb..5b7670c9aa 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 453edf0149..61545cacaa 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 4d148d1ace..26364269be 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 59cca0f4d9..2e0c871219 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>
OpenPOWER on IntegriCloud