summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/arch-mvebu/spi.h4
-rw-r--r--doc/device-tree-bindings/mtd/spi/spi-flash.txt2
-rw-r--r--drivers/mtd/spi/Makefile2
-rw-r--r--drivers/mtd/spi/sandbox.c11
-rw-r--r--drivers/mtd/spi/sf.c4
-rw-r--r--drivers/mtd/spi/sf_dataflash.c178
-rw-r--r--drivers/mtd/spi/sf_internal.h72
-rw-r--r--drivers/mtd/spi/sf_params.c149
-rw-r--r--drivers/mtd/spi/spi_flash.c234
-rw-r--r--drivers/mtd/spi/spi_flash_ids.c184
-rw-r--r--drivers/mtd/spi/sunxi_spi_spl.c3
-rw-r--r--drivers/spi/kirkwood_spi.c15
-rw-r--r--include/linux/err.h5
-rw-r--r--include/spi.h6
14 files changed, 409 insertions, 460 deletions
diff --git a/arch/arm/include/asm/arch-mvebu/spi.h b/arch/arm/include/asm/arch-mvebu/spi.h
index 78869a2..3545aed 100644
--- a/arch/arm/include/asm/arch-mvebu/spi.h
+++ b/arch/arm/include/asm/arch-mvebu/spi.h
@@ -52,6 +52,10 @@ struct kwspi_registers {
#define KWSPI_ADRLEN_3BYTE (2 << 8)
#define KWSPI_ADRLEN_4BYTE (3 << 8)
#define KWSPI_ADRLEN_MASK (3 << 8)
+#define KWSPI_CPOL (1 << 11)
+#define KWSPI_CPHA (1 << 12)
+#define KWSPI_TXLSBF (1 << 13)
+#define KWSPI_RXLSBF (1 << 14)
#define KWSPI_IRQUNMASK 1 /* unmask SPI interrupt */
#define KWSPI_IRQMASK 0 /* mask SPI interrupt */
diff --git a/doc/device-tree-bindings/mtd/spi/spi-flash.txt b/doc/device-tree-bindings/mtd/spi/spi-flash.txt
index 85522d8..3327890 100644
--- a/doc/device-tree-bindings/mtd/spi/spi-flash.txt
+++ b/doc/device-tree-bindings/mtd/spi/spi-flash.txt
@@ -6,7 +6,7 @@ Required properties:
- compatible : Should be the manufacturer and the name of the chip. Bear in
mind that the DT binding is not U-Boot-only, but in case of
U-Boot, see spi_flash_params_table table in
- drivers/mtd/spi/sf_params.c for the list of supported chips.
+ drivers/mtd/spi/spi_flash_ids.c for the list of supported chips.
- reg : Chip-Select number
- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index f3dc409..fcda023 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o
obj-$(CONFIG_SPL_SPI_SUNXI) += sunxi_spi_spl.o
endif
-obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi_flash.o sf_params.o sf.o
+obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi_flash.o spi_flash_ids.o sf.o
obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o
obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o
obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
index f59134f..4944059 100644
--- a/drivers/mtd/spi/sandbox.c
+++ b/drivers/mtd/spi/sandbox.c
@@ -88,7 +88,7 @@ struct sandbox_spi_flash {
/* The current flash status (see STAT_XXX defines above) */
u16 status;
/* Data describing the flash we're emulating */
- const struct spi_flash_params *data;
+ const struct spi_flash_info *data;
/* The file on disk to serv up data from */
int fd;
};
@@ -112,7 +112,7 @@ static int sandbox_sf_probe(struct udevice *dev)
struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
const char *file;
size_t len, idname_len;
- const struct spi_flash_params *data;
+ const struct spi_flash_info *data;
struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev);
struct sandbox_state *state = state_get_current();
struct udevice *bus = dev->parent;
@@ -168,7 +168,7 @@ static int sandbox_sf_probe(struct udevice *dev)
}
debug("%s: device='%s'\n", __func__, spec);
- for (data = spi_flash_params_table; data->name; data++) {
+ for (data = spi_flash_ids; data->name; data++) {
len = strlen(data->name);
if (idname_len != len)
continue;
@@ -289,7 +289,7 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
/* we only support erase here */
if (sbsf->cmd == CMD_ERASE_CHIP) {
sbsf->erase_size = sbsf->data->sector_size *
- sbsf->data->nr_sectors;
+ sbsf->data->n_sectors;
} else if (sbsf->cmd == CMD_ERASE_4K && (flags & SECT_4K)) {
sbsf->erase_size = 4 << 10;
} else if (sbsf->cmd == CMD_ERASE_64K && !(flags & SECT_4K)) {
@@ -359,7 +359,8 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen,
debug(" id: off:%u tx:", sbsf->off);
if (sbsf->off < IDCODE_LEN) {
/* Extract correct byte from ID 0x00aabbcc */
- id = sbsf->data->jedec >>
+ id = ((JEDEC_MFR(sbsf->data) << 16) |
+ JEDEC_ID(sbsf->data)) >>
(8 * (IDCODE_LEN - 1 - sbsf->off));
} else {
id = 0;
diff --git a/drivers/mtd/spi/sf.c b/drivers/mtd/spi/sf.c
index 664e860..d5e175c 100644
--- a/drivers/mtd/spi/sf.c
+++ b/drivers/mtd/spi/sf.c
@@ -18,10 +18,6 @@ static int spi_flash_read_write(struct spi_slave *spi,
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;
diff --git a/drivers/mtd/spi/sf_dataflash.c b/drivers/mtd/spi/sf_dataflash.c
index b2a56da..bcddfa0 100644
--- a/drivers/mtd/spi/sf_dataflash.c
+++ b/drivers/mtd/spi/sf_dataflash.c
@@ -1,12 +1,12 @@
/*
- *
* Atmel DataFlash probing
*
* Copyright (C) 2004-2009, 2015 Freescale Semiconductor, Inc.
* Haikun Wang (haikun.wang@freescale.com)
*
* SPDX-License-Identifier: GPL-2.0+
-*/
+ */
+
#include <common.h>
#include <dm.h>
#include <errno.h>
@@ -67,15 +67,12 @@
#define OP_WRITE_SECURITY_REVC 0x9A
#define OP_WRITE_SECURITY 0x9B /* revision D */
-
struct dataflash {
uint8_t command[16];
unsigned short page_offset; /* offset in flash address */
};
-/*
- * Return the status of the DataFlash device.
- */
+/* Return the status of the DataFlash device */
static inline int dataflash_status(struct spi_slave *spi)
{
int ret;
@@ -114,9 +111,7 @@ static int dataflash_waitready(struct spi_slave *spi)
return -ETIME;
}
-/*
- * Erase pages of flash.
- */
+/* Erase pages of flash */
static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len)
{
struct dataflash *dataflash;
@@ -147,7 +142,7 @@ static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len)
status = spi_claim_bus(spi);
if (status) {
- debug("SPI DATAFLASH: unable to claim SPI bus\n");
+ debug("dataflash: unable to claim SPI bus\n");
return status;
}
@@ -232,7 +227,7 @@ static int spi_dataflash_read(struct udevice *dev, u32 offset, size_t len,
status = spi_claim_bus(spi);
if (status) {
- debug("SPI DATAFLASH: unable to claim SPI bus\n");
+ debug("dataflash: unable to claim SPI bus\n");
return status;
}
@@ -290,7 +285,7 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len,
status = spi_claim_bus(spi);
if (status) {
- debug("SPI DATAFLASH: unable to claim SPI bus\n");
+ debug("dataflash: unable to claim SPI bus\n");
return status;
}
@@ -387,7 +382,7 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len,
/* Check result of the compare operation */
if (status & (1 << 6)) {
- printf("SPI DataFlash: write compare page %u, err %d\n",
+ printf("dataflash: write compare page %u, err %d\n",
pageaddr, status);
remaining = 0;
status = -EIO;
@@ -501,9 +496,10 @@ static struct flash_info dataflash_data[] = {
{ "at45db642d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS},
};
-static struct flash_info *jedec_probe(struct spi_slave *spi, u8 *id)
+static struct flash_info *jedec_probe(struct spi_slave *spi)
{
int tmp;
+ uint8_t id[5];
uint32_t jedec;
struct flash_info *info;
int status;
@@ -517,6 +513,11 @@ static struct flash_info *jedec_probe(struct spi_slave *spi, u8 *id)
* That's not an error; only rev C and newer chips handle it, and
* only Atmel sells these chips.
*/
+ tmp = spi_flash_cmd(spi, CMD_READ_ID, id, sizeof(id));
+ if (tmp < 0) {
+ printf("dataflash: error %d reading JEDEC ID\n", tmp);
+ return ERR_PTR(tmp);
+ }
if (id[0] != 0x1f)
return NULL;
@@ -533,7 +534,7 @@ static struct flash_info *jedec_probe(struct spi_slave *spi, u8 *id)
if (info->flags & SUP_POW2PS) {
status = dataflash_status(spi);
if (status < 0) {
- debug("SPI DataFlash: status error %d\n",
+ debug("dataflash: status error %d\n",
status);
return NULL;
}
@@ -555,10 +556,8 @@ static struct flash_info *jedec_probe(struct spi_slave *spi, u8 *id)
* size (it might be binary) even when we can tell which density
* class is involved (legacy chip id scheme).
*/
- printf("SPI DataFlash: Unsupported flash IDs: ");
- printf("manuf %02x, jedec %04x, ext_jedec %04x\n",
- id[0], jedec, id[3] << 8 | id[4]);
- return NULL;
+ printf("dataflash: JEDEC id %06x not handled\n", jedec);
+ return ERR_PTR(-ENODEV);
}
/*
@@ -580,21 +579,15 @@ static int spi_dataflash_probe(struct udevice *dev)
struct spi_slave *spi = dev_get_parent_priv(dev);
struct spi_flash *spi_flash;
struct flash_info *info;
- u8 idcode[5];
- int ret, status = 0;
+ int status;
spi_flash = dev_get_uclass_priv(dev);
+ spi_flash->spi = spi;
spi_flash->dev = dev;
- ret = spi_claim_bus(spi);
- if (ret)
- return ret;
-
- ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
- if (ret) {
- printf("SPI DataFlash: Failed to get idcodes\n");
- goto err_read_cmd;
- }
+ status = spi_claim_bus(spi);
+ if (status)
+ return status;
/*
* Try to detect dataflash by JEDEC ID.
@@ -603,79 +596,70 @@ static int spi_dataflash_probe(struct udevice *dev)
* Both support the security register, though with different
* write procedures.
*/
- info = jedec_probe(spi, idcode);
- if (info != NULL)
- add_dataflash(dev, info->name, info->nr_pages,
- info->pagesize, info->pageoffset,
- (info->flags & SUP_POW2PS) ? 'd' : 'c');
- else {
- /*
- * Older chips support only legacy commands, identifing
- * capacity using bits in the status byte.
- */
- status = dataflash_status(spi);
- if (status <= 0 || status == 0xff) {
- printf("SPI DataFlash: read status error %d\n", status);
- if (status == 0 || status == 0xff)
- status = -ENODEV;
- goto err_read_cmd;
- }
- /*
- * if there's a device there, assume it's dataflash.
- * board setup should have set spi->max_speed_max to
- * match f(car) for continuous reads, mode 0 or 3.
- */
- switch (status & 0x3c) {
- case 0x0c: /* 0 0 1 1 x x */
- status = add_dataflash(dev, "AT45DB011B",
- 512, 264, 9, 0);
- break;
- case 0x14: /* 0 1 0 1 x x */
- status = add_dataflash(dev, "AT45DB021B",
- 1024, 264, 9, 0);
- break;
- case 0x1c: /* 0 1 1 1 x x */
- status = add_dataflash(dev, "AT45DB041x",
- 2048, 264, 9, 0);
- break;
- case 0x24: /* 1 0 0 1 x x */
- status = add_dataflash(dev, "AT45DB081B",
- 4096, 264, 9, 0);
- break;
- case 0x2c: /* 1 0 1 1 x x */
- status = add_dataflash(dev, "AT45DB161x",
- 4096, 528, 10, 0);
- break;
- case 0x34: /* 1 1 0 1 x x */
- status = add_dataflash(dev, "AT45DB321x",
- 8192, 528, 10, 0);
- break;
- case 0x38: /* 1 1 1 x x x */
- case 0x3c:
- status = add_dataflash(dev, "AT45DB642x",
- 8192, 1056, 11, 0);
- break;
- /* obsolete AT45DB1282 not (yet?) supported */
- default:
- dev_info(&spi->dev, "unsupported device (%x)\n",
- status & 0x3c);
- status = -ENODEV;
- goto err_read_cmd;
- }
+ info = jedec_probe(spi);
+ if (IS_ERR(info))
+ goto err_jedec_probe;
+ if (info != NULL) {
+ status = add_dataflash(dev, info->name, info->nr_pages,
+ info->pagesize, info->pageoffset,
+ (info->flags & SUP_POW2PS) ? 'd' : 'c');
+ if (status < 0)
+ goto err_status;
}
- /* Assign spi data */
- spi_flash->spi = spi;
- spi_flash->memory_map = spi->memory_map;
- spi_flash->dual_flash = spi->option;
+ /*
+ * Older chips support only legacy commands, identifing
+ * capacity using bits in the status byte.
+ */
+ status = dataflash_status(spi);
+ if (status <= 0 || status == 0xff) {
+ printf("dataflash: read status error %d\n", status);
+ if (status == 0 || status == 0xff)
+ status = -ENODEV;
+ goto err_jedec_probe;
+ }
- spi_release_bus(spi);
+ /*
+ * if there's a device there, assume it's dataflash.
+ * board setup should have set spi->max_speed_max to
+ * match f(car) for continuous reads, mode 0 or 3.
+ */
+ switch (status & 0x3c) {
+ case 0x0c: /* 0 0 1 1 x x */
+ status = add_dataflash(dev, "AT45DB011B", 512, 264, 9, 0);
+ break;
+ case 0x14: /* 0 1 0 1 x x */
+ status = add_dataflash(dev, "AT45DB021B", 1024, 264, 9, 0);
+ break;
+ case 0x1c: /* 0 1 1 1 x x */
+ status = add_dataflash(dev, "AT45DB041x", 2048, 264, 9, 0);
+ break;
+ case 0x24: /* 1 0 0 1 x x */
+ status = add_dataflash(dev, "AT45DB081B", 4096, 264, 9, 0);
+ break;
+ case 0x2c: /* 1 0 1 1 x x */
+ status = add_dataflash(dev, "AT45DB161x", 4096, 528, 10, 0);
+ break;
+ case 0x34: /* 1 1 0 1 x x */
+ status = add_dataflash(dev, "AT45DB321x", 8192, 528, 10, 0);
+ break;
+ case 0x38: /* 1 1 1 x x x */
+ case 0x3c:
+ status = add_dataflash(dev, "AT45DB642x", 8192, 1056, 11, 0);
+ break;
+ /* obsolete AT45DB1282 not (yet?) supported */
+ default:
+ printf("dataflash: unsupported device (%x)\n", status & 0x3c);
+ status = -ENODEV;
+ goto err_status;
+ }
- return 0;
+ return status;
-err_read_cmd:
+err_status:
+ spi_free_slave(spi);
+err_jedec_probe:
spi_release_bus(spi);
-
return status;
}
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index cde4cfb..2463686 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -23,6 +23,7 @@ enum spi_dual_flash {
enum spi_nor_option_flags {
SNOR_F_SST_WR = BIT(0),
SNOR_F_USE_FSR = BIT(1),
+ SNOR_F_USE_UPAGE = BIT(3),
};
#define SPI_FLASH_3B_ADDR_LEN 3
@@ -98,42 +99,45 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
const void *buf);
#endif
-#ifdef CONFIG_SPI_FLASH_SPANSION
-/* Used for Spansion S25FS-S family flash only. */
-#define CMD_SPANSION_RDAR 0x65 /* Read any device register */
-#define CMD_SPANSION_WRAR 0x71 /* Write any device register */
-#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: Isn't necessarily a sector size from vendor,
- * the size listed here is what works with CMD_ERASE_64K
- * @nr_sectors: No.of sectors on this device
- * @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;
-
- u16 flags;
-#define SECT_4K BIT(0)
-#define E_FSR BIT(1)
-#define SST_WR BIT(2)
-#define WR_QPP BIT(3)
-#define RD_QUAD BIT(4)
-#define RD_DUAL BIT(5)
-#define RD_QUADIO BIT(6)
-#define RD_DUALIO BIT(7)
+#define JEDEC_MFR(info) ((info)->id[0])
+#define JEDEC_ID(info) (((info)->id[1]) << 8 | ((info)->id[2]))
+#define JEDEC_EXT(info) (((info)->id[3]) << 8 | ((info)->id[4]))
+#define SPI_FLASH_MAX_ID_LEN 6
+
+struct spi_flash_info {
+ /* Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) */
+ const char *name;
+
+ /*
+ * This array stores the ID bytes.
+ * The first three bytes are the JEDIC ID.
+ * JEDEC ID zero means "no ID" (mostly older chips).
+ */
+ u8 id[SPI_FLASH_MAX_ID_LEN];
+ u8 id_len;
+
+ /*
+ * The size listed here is what works with SPINOR_OP_SE, which isn't
+ * necessarily called a "sector" by the vendor.
+ */
+ u32 sector_size;
+ u32 n_sectors;
+
+ u16 page_size;
+
+ u16 flags;
+#define SECT_4K BIT(0) /* CMD_ERASE_4K works uniformly */
+#define E_FSR BIT(1) /* use flag status register for */
+#define SST_WR BIT(2) /* use SST byte/word programming */
+#define WR_QPP BIT(3) /* use Quad Page Program */
+#define RD_QUAD BIT(4) /* use Quad Read */
+#define RD_DUAL BIT(5) /* use Dual Read */
+#define RD_QUADIO BIT(6) /* use Quad IO Read */
+#define RD_DUALIO BIT(7) /* use Dual IO Read */
#define RD_FULL (RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO)
};
-extern const struct spi_flash_params spi_flash_params_table[];
+extern const struct spi_flash_info spi_flash_ids[];
/* 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);
@@ -182,7 +186,7 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
* - SPI claim
* - spi_flash_cmd_write_enable
* - spi_flash_cmd_write
- * - spi_flash_cmd_wait_ready
+ * - spi_flash_wait_till_ready
* - SPI release
*/
int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c
deleted file mode 100644
index 5b50114..0000000
--- a/drivers/mtd/spi/sf_params.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * SPI flash Params table
- *
- * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <spi.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, SECT_4K},
- {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, SECT_4K},
- {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, SECT_4K},
- {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, SECT_4K},
- {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, SECT_4K},
- {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, SECT_4K},
- {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, SECT_4K},
- {"AT25DF321A", 0x1f4701, 0x0, 64 * 1024, 64, SECT_4K},
- {"AT25DF321", 0x1f4700, 0x0, 64 * 1024, 64, SECT_4K},
- {"AT26DF081A", 0x1f4501, 0x0, 64 * 1024, 16, SECT_4K},
-#endif
-#ifdef CONFIG_SPI_FLASH_EON /* EON */
- {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0},
- {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, SECT_4K},
- {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0},
- {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0},
-#endif
-#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */
- {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, SECT_4K},
- {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, SECT_4K},
-#endif
-#ifdef CONFIG_SPI_FLASH_ISSI /* ISSI */
- {"IS25LP032", 0x9d6016, 0x0, 64 * 1024, 64, 0},
- {"IS25LP064", 0x9d6017, 0x0, 64 * 1024, 128, 0},
- {"IS25LP128", 0x9d6018, 0x0, 64 * 1024, 256, 0},
-#endif
-#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */
- {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0},
- {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0},
- {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0},
- {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0},
- {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0},
- {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 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},
- {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0},
- {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0},
- {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0},
- {"S25FL116K", 0x014015, 0x0, 64 * 1024, 128, 0},
- {"S25FL164K", 0x014017, 0x0140, 64 * 1024, 128, 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},
- {"S25FS512S", 0x010220, 0x4D00, 128 * 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},
- {"S25FL512S_512K", 0x010220, 0x4f00, 256 * 1024, 256, RD_FULL | WR_QPP},
-#endif
-#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */
- {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0},
- {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0},
- {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0},
- {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0},
- {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0},
- {"M25PE16", 0x208015, 0x1000, 64 * 1024, 32, 0},
- {"M25PX16", 0x207115, 0x1000, 64 * 1024, 32, RD_QUAD | RD_DUAL},
- {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0},
- {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0},
- {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0},
- {"M25PX64", 0x207117, 0x0, 64 * 1024, 128, SECT_4K},
- {"N25Q016A", 0x20bb15, 0x0, 64 * 1024, 32, SECT_4K},
- {"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, SECT_4K | SST_WR},
- {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | SST_WR},
- {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | SST_WR},
- {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | SST_WR},
- {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, SECT_4K},
- {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | SST_WR},
- {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | SST_WR},
- {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | SST_WR},
- {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WR},
- {"SST25WF040B", 0x621613, 0x0, 64 * 1024, 8, SECT_4K},
- {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WR},
-#endif
-#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */
- {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0},
- {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0},
- {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0},
- {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, SECT_4K},
- {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, SECT_4K},
- {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, SECT_4K},
- {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 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
- {}, /* Empty entry to terminate the list */
- /*
- * 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/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 7f6e9ae..2576c2c 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -144,7 +144,7 @@ static int write_evcr(struct spi_flash *flash, u8 evcr)
#endif
#ifdef CONFIG_SPI_FLASH_BAR
-static int spi_flash_write_bar(struct spi_flash *flash, u32 offset)
+static int write_bar(struct spi_flash *flash, u32 offset)
{
u8 cmd, bank_sel;
int ret;
@@ -165,7 +165,7 @@ bar_end:
return flash->bank_curr;
}
-static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0)
+static int read_bar(struct spi_flash *flash, const struct spi_flash_info *info)
{
u8 curr_bank = 0;
int ret;
@@ -173,7 +173,7 @@ static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0)
if (flash->size <= SPI_FLASH_16MB_BOUN)
goto bar_end;
- switch (idcode0) {
+ switch (JEDEC_MFR(info)) {
case SPI_FLASH_CFI_MFR_SPANSION:
flash->bank_read_cmd = CMD_BANKADDR_BRRD;
flash->bank_write_cmd = CMD_BANKADDR_BRWR;
@@ -199,15 +199,13 @@ bar_end:
#ifdef CONFIG_SF_DUAL_FLASH
static void spi_flash_dual(struct spi_flash *flash, u32 *addr)
{
- struct spi_slave *spi = flash->spi;
-
switch (flash->dual_flash) {
case SF_DUAL_STACKED_FLASH:
if (*addr >= (flash->size >> 1)) {
*addr -= flash->size >> 1;
- spi->flags |= SPI_XFER_U_PAGE;
+ flash->flags |= SNOR_F_USE_UPAGE;
} else {
- spi->flags &= ~SPI_XFER_U_PAGE;
+ flash->flags &= ~SNOR_F_USE_UPAGE;
}
break;
case SF_DUAL_PARALLEL_FLASH:
@@ -262,8 +260,8 @@ static int spi_flash_ready(struct spi_flash *flash)
return sr && fsr;
}
-static int spi_flash_cmd_wait_ready(struct spi_flash *flash,
- unsigned long timeout)
+static int spi_flash_wait_till_ready(struct spi_flash *flash,
+ unsigned long timeout)
{
unsigned long timebase;
int ret;
@@ -311,7 +309,7 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
return ret;
}
- ret = spi_flash_cmd_wait_ready(flash, timeout);
+ ret = spi_flash_wait_till_ready(flash, timeout);
if (ret < 0) {
debug("SF: write %s timed out\n",
timeout == SPI_FLASH_PROG_TIMEOUT ?
@@ -353,7 +351,7 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
spi_flash_dual(flash, &erase_addr);
#endif
#ifdef CONFIG_SPI_FLASH_BAR
- ret = spi_flash_write_bar(flash, erase_addr);
+ ret = write_bar(flash, erase_addr);
if (ret < 0)
return ret;
#endif
@@ -404,7 +402,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
spi_flash_dual(flash, &write_addr);
#endif
#ifdef CONFIG_SPI_FLASH_BAR
- ret = spi_flash_write_bar(flash, write_addr);
+ ret = write_bar(flash, write_addr);
if (ret < 0)
return ret;
#endif
@@ -508,7 +506,7 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
spi_flash_dual(flash, &read_addr);
#endif
#ifdef CONFIG_SPI_FLASH_BAR
- ret = spi_flash_write_bar(flash, read_addr);
+ ret = write_bar(flash, read_addr);
if (ret < 0)
return ret;
bank_sel = flash->bank_curr;
@@ -560,7 +558,7 @@ static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
if (ret)
return ret;
- return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+ return spi_flash_wait_till_ready(flash, SPI_FLASH_PROG_TIMEOUT);
}
int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
@@ -608,7 +606,7 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
break;
}
- ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+ ret = spi_flash_wait_till_ready(flash, SPI_FLASH_PROG_TIMEOUT);
if (ret)
break;
@@ -924,9 +922,35 @@ static int micron_quad_enable(struct spi_flash *flash)
}
#endif
-static int set_quad_mode(struct spi_flash *flash, u8 idcode0)
+static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
{
- switch (idcode0) {
+ int tmp;
+ u8 id[SPI_FLASH_MAX_ID_LEN];
+ const struct spi_flash_info *info;
+
+ tmp = spi_flash_cmd(flash->spi, CMD_READ_ID, id, SPI_FLASH_MAX_ID_LEN);
+ if (tmp < 0) {
+ printf("SF: error %d reading JEDEC ID\n", tmp);
+ return ERR_PTR(tmp);
+ }
+
+ info = spi_flash_ids;
+ for (; info->name != NULL; info++) {
+ if (info->id_len) {
+ if (!memcmp(info->id, id, info->id_len))
+ return info;
+ }
+ }
+
+ printf("SF: unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
+ id[0], id[1], id[2]);
+ return ERR_PTR(-ENODEV);
+}
+
+static int set_quad_mode(struct spi_flash *flash,
+ const struct spi_flash_info *info)
+{
+ switch (JEDEC_MFR(info)) {
#ifdef CONFIG_SPI_FLASH_MACRONIX
case SPI_FLASH_CFI_MFR_MACRONIX:
return macronix_quad_enable(flash);
@@ -941,7 +965,8 @@ static int set_quad_mode(struct spi_flash *flash, u8 idcode0)
return micron_quad_enable(flash);
#endif
default:
- printf("SF: Need set QEB func for %02x flash\n", idcode0);
+ printf("SF: Need set QEB func for %02x flash\n",
+ JEDEC_MFR(info));
return -1;
}
}
@@ -971,138 +996,28 @@ int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
}
#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
-#ifdef CONFIG_SPI_FLASH_SPANSION
-static int spansion_s25fss_disable_4KB_erase(struct spi_slave *spi)
-{
- u8 cmd[4];
- u32 offset = 0x800004; /* CR3V register offset */
- u8 cr3v;
- int ret;
-
- cmd[0] = CMD_SPANSION_RDAR;
- cmd[1] = offset >> 16;
- cmd[2] = offset >> 8;
- cmd[3] = offset >> 0;
-
- ret = spi_flash_cmd_read(spi, cmd, 4, &cr3v, 1);
- if (ret)
- return -EIO;
- /* CR3V bit3: 4-KB Erase */
- if (cr3v & 0x8)
- return 0;
-
- cmd[0] = CMD_SPANSION_WRAR;
- cr3v |= 0x8;
- ret = spi_flash_cmd_write(spi, cmd, 4, &cr3v, 1);
- if (ret)
- return -EIO;
-
- cmd[0] = CMD_SPANSION_RDAR;
- ret = spi_flash_cmd_read(spi, cmd, 4, &cr3v, 1);
- if (ret)
- return -EIO;
- if (!(cr3v & 0x8))
- return -EFAULT;
-
- return 0;
-}
-#endif
-
int spi_flash_scan(struct spi_flash *flash)
{
struct spi_slave *spi = flash->spi;
- const struct spi_flash_params *params;
- u16 jedec, ext_jedec;
- u8 idcode[5];
- int ret;
-
- /* Read the ID codes */
- ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
- if (ret) {
- printf("SF: Failed to get idcodes\n");
- return ret;
- }
-
-#ifdef DEBUG
- printf("SF: Got idcodes\n");
- print_buffer(0, idcode, 1, sizeof(idcode), 0);
-#endif
-
- jedec = idcode[1] << 8 | idcode[2];
- 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]) {
- 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 -EPROTONOSUPPORT;
- }
-
-#ifdef CONFIG_SPI_FLASH_SPANSION
- /*
- * The S25FS-S family physical sectors may be configured as a
- * hybrid combination of eight 4-kB parameter sectors
- * at the top or bottom of the address space with all
- * but one of the remaining sectors being uniform size.
- * The Parameter Sector Erase commands (20h or 21h) must
- * be used to erase the 4-kB parameter sectors individually.
- * The Sector (uniform sector) Erase commands (D8h or DCh)
- * must be used to erase any of the remaining
- * sectors, including the portion of highest or lowest address
- * sector that is not overlaid by the parameter sectors.
- * The uniform sector erase command has no effect on parameter sectors.
- */
- if ((jedec == 0x0219 || (jedec == 0x0220)) &&
- (ext_jedec & 0xff00) == 0x4d00) {
- int ret;
- u8 id[6];
-
- /* Read the ID codes again, 6 bytes */
- ret = spi_flash_cmd(flash->spi, CMD_READ_ID, id, sizeof(id));
- if (ret)
- return -EIO;
+ const struct spi_flash_info *info = NULL;
+ int ret = -1;
- ret = memcmp(id, idcode, 5);
- if (ret)
- return -EIO;
+ info = spi_flash_read_id(flash);
+ if (IS_ERR_OR_NULL(info))
+ return -ENOENT;
- /* 0x81: S25FS-S family 0x80: S25FL-S family */
- if (id[5] == 0x81) {
- ret = spansion_s25fss_disable_4KB_erase(spi);
- if (ret)
- return ret;
- }
- }
-#endif
/* Flash powers up read-only, so clear BP# bits */
- if (idcode[0] == SPI_FLASH_CFI_MFR_ATMEL ||
- idcode[0] == SPI_FLASH_CFI_MFR_MACRONIX ||
- idcode[0] == SPI_FLASH_CFI_MFR_SST)
+ if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_ATMEL ||
+ JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_MACRONIX ||
+ JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_SST)
write_sr(flash, 0);
- /* Assign spi data */
- flash->name = params->name;
+ flash->name = info->name;
flash->memory_map = spi->memory_map;
- flash->dual_flash = spi->option;
- /* Assign spi flash flags */
- if (params->flags & SST_WR)
+ if (info->flags & SST_WR)
flash->flags |= SNOR_F_SST_WR;
- /* Assign spi_flash ops */
#ifndef CONFIG_DM_SPI_FLASH
flash->write = spi_flash_cmd_write_ops;
#if defined(CONFIG_SPI_FLASH_SST)
@@ -1117,39 +1032,33 @@ int spi_flash_scan(struct spi_flash *flash)
flash->read = spi_flash_cmd_read_ops;
#endif
- /* lock hooks are flash specific - assign them based on idcode0 */
- switch (idcode[0]) {
#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
- case SPI_FLASH_CFI_MFR_STMICRO:
- case SPI_FLASH_CFI_MFR_SST:
+ /* NOR protection support for STmicro/Micron chips and similar */
+ if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_STMICRO ||
+ JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_SST) {
flash->flash_lock = stm_lock;
flash->flash_unlock = stm_unlock;
flash->flash_is_locked = stm_is_locked;
-#endif
- break;
- default:
- debug("SF: Lock ops not supported for %02x flash\n", idcode[0]);
}
+#endif
/* Compute the flash size */
flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
+ flash->page_size = info->page_size;
/*
* 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) || (jedec == 0x220))
- flash->page_size = 256;
- else
+ if (JEDEC_EXT(info) == 0x4d00) {
+ if ((JEDEC_ID(info) != 0x0215) &&
+ (JEDEC_ID(info) != 0x0216))
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;
+ flash->sector_size = info->sector_size << flash->shift;
+ flash->size = flash->sector_size * info->n_sectors << flash->shift;
#ifdef CONFIG_SF_DUAL_FLASH
if (flash->dual_flash & SF_DUAL_STACKED_FLASH)
flash->size <<= 1;
@@ -1157,7 +1066,7 @@ int spi_flash_scan(struct spi_flash *flash)
#ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS
/* Compute erase sector and command */
- if (params->flags & SECT_4K) {
+ if (info->flags & SECT_4K) {
flash->erase_cmd = CMD_ERASE_4K;
flash->erase_size = 4096 << flash->shift;
} else
@@ -1174,13 +1083,13 @@ int spi_flash_scan(struct spi_flash *flash)
flash->read_cmd = CMD_READ_ARRAY_FAST;
if (spi->mode & SPI_RX_SLOW)
flash->read_cmd = CMD_READ_ARRAY_SLOW;
- else if (spi->mode & SPI_RX_QUAD && params->flags & RD_QUAD)
+ else if (spi->mode & SPI_RX_QUAD && info->flags & RD_QUAD)
flash->read_cmd = CMD_READ_QUAD_OUTPUT_FAST;
- else if (spi->mode & SPI_RX_DUAL && params->flags & RD_DUAL)
+ else if (spi->mode & SPI_RX_DUAL && info->flags & RD_DUAL)
flash->read_cmd = CMD_READ_DUAL_OUTPUT_FAST;
/* Look for write commands */
- if (params->flags & WR_QPP && spi->mode & SPI_TX_QUAD)
+ if (info->flags & WR_QPP && spi->mode & SPI_TX_QUAD)
flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
else
/* Go for default supported write cmd */
@@ -1190,9 +1099,10 @@ int spi_flash_scan(struct spi_flash *flash)
if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
(flash->read_cmd == CMD_READ_QUAD_IO_FAST) ||
(flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
- ret = set_quad_mode(flash, idcode[0]);
+ ret = set_quad_mode(flash, info);
if (ret) {
- debug("SF: Fail to set QEB for %02x\n", idcode[0]);
+ debug("SF: Fail to set QEB for %02x\n",
+ JEDEC_MFR(info));
return -EINVAL;
}
}
@@ -1217,13 +1127,13 @@ int spi_flash_scan(struct spi_flash *flash)
}
#ifdef CONFIG_SPI_FLASH_STMICRO
- if (params->flags & E_FSR)
+ if (info->flags & E_FSR)
flash->flags |= SNOR_F_USE_FSR;
#endif
/* Configure the BAR - discover bank cmds and read current bank */
#ifdef CONFIG_SPI_FLASH_BAR
- ret = spi_flash_read_bar(flash, idcode[0]);
+ ret = read_bar(flash, info);
if (ret < 0)
return ret;
#endif
diff --git a/drivers/mtd/spi/spi_flash_ids.c b/drivers/mtd/spi/spi_flash_ids.c
new file mode 100644
index 0000000..edca94e
--- /dev/null
+++ b/drivers/mtd/spi/spi_flash_ids.c
@@ -0,0 +1,184 @@
+/*
+ * SPI Flash ID's.
+ *
+ * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
+ * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+#include "sf_internal.h"
+
+/* Used when the "_ext_id" is two bytes at most */
+#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
+ .id = { \
+ ((_jedec_id) >> 16) & 0xff, \
+ ((_jedec_id) >> 8) & 0xff, \
+ (_jedec_id) & 0xff, \
+ ((_ext_id) >> 8) & 0xff, \
+ (_ext_id) & 0xff, \
+ }, \
+ .id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \
+ .sector_size = (_sector_size), \
+ .n_sectors = (_n_sectors), \
+ .page_size = 256, \
+ .flags = (_flags),
+
+#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
+ .id = { \
+ ((_jedec_id) >> 16) & 0xff, \
+ ((_jedec_id) >> 8) & 0xff, \
+ (_jedec_id) & 0xff, \
+ ((_ext_id) >> 16) & 0xff, \
+ ((_ext_id) >> 8) & 0xff, \
+ (_ext_id) & 0xff, \
+ }, \
+ .id_len = 6, \
+ .sector_size = (_sector_size), \
+ .n_sectors = (_n_sectors), \
+ .page_size = 256, \
+ .flags = (_flags),
+
+const struct spi_flash_info spi_flash_ids[] = {
+#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */
+ {"at45db011d", INFO(0x1f2200, 0x0, 64 * 1024, 4, SECT_4K) },
+ {"at45db021d", INFO(0x1f2300, 0x0, 64 * 1024, 8, SECT_4K) },
+ {"at45db041d", INFO(0x1f2400, 0x0, 64 * 1024, 8, SECT_4K) },
+ {"at45db081d", INFO(0x1f2500, 0x0, 64 * 1024, 16, SECT_4K) },
+ {"at45db161d", INFO(0x1f2600, 0x0, 64 * 1024, 32, SECT_4K) },
+ {"at45db321d", INFO(0x1f2700, 0x0, 64 * 1024, 64, SECT_4K) },
+ {"at45db641d", INFO(0x1f2800, 0x0, 64 * 1024, 128, SECT_4K) },
+ {"at25df321a", INFO(0x1f4701, 0x0, 64 * 1024, 64, SECT_4K) },
+ {"at25df321", INFO(0x1f4700, 0x0, 64 * 1024, 64, SECT_4K) },
+ {"at26df081a", INFO(0x1f4501, 0x0, 64 * 1024, 16, SECT_4K) },
+#endif
+#ifdef CONFIG_SPI_FLASH_EON /* EON */
+ {"en25q32b", INFO(0x1c3016, 0x0, 64 * 1024, 64, 0) },
+ {"en25q64", INFO(0x1c3017, 0x0, 64 * 1024, 128, SECT_4K) },
+ {"en25q128b", INFO(0x1c3018, 0x0, 64 * 1024, 256, 0) },
+ {"en25s64", INFO(0x1c3817, 0x0, 64 * 1024, 128, 0) },
+#endif
+#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */
+ {"gd25q64b", INFO(0xc84017, 0x0, 64 * 1024, 128, SECT_4K) },
+ {"gd25lq32", INFO(0xc86016, 0x0, 64 * 1024, 64, SECT_4K) },
+#endif
+#ifdef CONFIG_SPI_FLASH_ISSI /* ISSI */
+ {"is25lp032", INFO(0x9d6016, 0x0, 64 * 1024, 64, 0) },
+ {"is25lp064", INFO(0x9d6017, 0x0, 64 * 1024, 128, 0) },
+ {"is25lp128", INFO(0x9d6018, 0x0, 64 * 1024, 256, 0) },
+#endif
+#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */
+ {"mx25l2006e", INFO(0xc22012, 0x0, 64 * 1024, 4, 0) },
+ {"mx25l4005", INFO(0xc22013, 0x0, 64 * 1024, 8, 0) },
+ {"mx25l8005", INFO(0xc22014, 0x0, 64 * 1024, 16, 0) },
+ {"mx25l1605d", INFO(0xc22015, 0x0, 64 * 1024, 32, 0) },
+ {"mx25l3205d", INFO(0xc22016, 0x0, 64 * 1024, 64, 0) },
+ {"mx25l6405d", INFO(0xc22017, 0x0, 64 * 1024, 128, 0) },
+ {"mx25l12805", INFO(0xc22018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP) },
+ {"mx25l25635f", INFO(0xc22019, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP) },
+ {"mx25l51235f", INFO(0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP) },
+ {"mx25l12855e", INFO(0xc22618, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP) },
+ {"mx66u51235f", INFO(0xc2253a, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP) },
+ {"mx66l1g45g", INFO(0xc2201b, 0x0, 64 * 1024, 2048, RD_FULL | WR_QPP) },
+#endif
+#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */
+ {"s25fl008a", INFO(0x010213, 0x0, 64 * 1024, 16, 0) },
+ {"s25fl016a", INFO(0x010214, 0x0, 64 * 1024, 32, 0) },
+ {"s25fl032a", INFO(0x010215, 0x0, 64 * 1024, 64, 0) },
+ {"s25fl064a", INFO(0x010216, 0x0, 64 * 1024, 128, 0) },
+ {"s25fl116k", INFO(0x014015, 0x0, 64 * 1024, 128, 0) },
+ {"s25fl164k", INFO(0x014017, 0x0140, 64 * 1024, 128, 0) },
+ {"s25fl128p_256k", INFO(0x012018, 0x0300, 256 * 1024, 64, RD_FULL | WR_QPP) },
+ {"s25fl128p_64k", INFO(0x012018, 0x0301, 64 * 1024, 256, RD_FULL | WR_QPP) },
+ {"s25fl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, RD_FULL | WR_QPP) },
+ {"s25fl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, RD_FULL | WR_QPP) },
+ {"s25fl128s_256k", INFO(0x012018, 0x4d00, 256 * 1024, 64, RD_FULL | WR_QPP) },
+ {"s25fl128s_64k", INFO(0x012018, 0x4d01, 64 * 1024, 256, RD_FULL | WR_QPP) },
+ {"s25fl256s_256k", INFO(0x010219, 0x4d00, 256 * 1024, 128, RD_FULL | WR_QPP) },
+ {"s25fl256s_64k", INFO(0x010219, 0x4d01, 64 * 1024, 512, RD_FULL | WR_QPP) },
+ {"s25fs256s_64k", INFO6(0x010219, 0x4d0181, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
+ {"s25fs512s", INFO6(0x010220, 0x4d0081, 128 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
+ {"s25fl512s_256k", INFO(0x010220, 0x4d00, 256 * 1024, 256, RD_FULL | WR_QPP) },
+ {"s25fl512s_64k", INFO(0x010220, 0x4d01, 64 * 1024, 1024, RD_FULL | WR_QPP) },
+ {"s25fl512s_512k", INFO(0x010220, 0x4f00, 256 * 1024, 256, RD_FULL | WR_QPP) },
+#endif
+#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */
+ {"m25p10", INFO(0x202011, 0x0, 32 * 1024, 4, 0) },
+ {"m25p20", INFO(0x202012, 0x0, 64 * 1024, 4, 0) },
+ {"m25p40", INFO(0x202013, 0x0, 64 * 1024, 8, 0) },
+ {"m25p80", INFO(0x202014, 0x0, 64 * 1024, 16, 0) },
+ {"m25p16", INFO(0x202015, 0x0, 64 * 1024, 32, 0) },
+ {"m25pE16", INFO(0x208015, 0x1000, 64 * 1024, 32, 0) },
+ {"m25pX16", INFO(0x207115, 0x1000, 64 * 1024, 32, RD_QUAD | RD_DUAL) },
+ {"m25p32", INFO(0x202016, 0x0, 64 * 1024, 64, 0) },
+ {"m25p64", INFO(0x202017, 0x0, 64 * 1024, 128, 0) },
+ {"m25p128", INFO(0x202018, 0x0, 256 * 1024, 64, 0) },
+ {"m25pX64", INFO(0x207117, 0x0, 64 * 1024, 128, SECT_4K) },
+ {"n25q016a", INFO(0x20bb15, 0x0, 64 * 1024, 32, SECT_4K) },
+ {"n25q32", INFO(0x20ba16, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K) },
+ {"n25q32a", INFO(0x20bb16, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K) },
+ {"n25q64", INFO(0x20ba17, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K) },
+ {"n25q64a", INFO(0x20bb17, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K) },
+ {"n25q128", INFO(0x20ba18, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP) },
+ {"n25q128a", INFO(0x20bb18, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP) },
+ {"n25q256", INFO(0x20ba19, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
+ {"n25q256a", INFO(0x20bb19, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
+ {"n25q512", INFO(0x20ba20, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+ {"n25q512a", INFO(0x20bb20, 0x0, 64 * 1024, 1024, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+ {"n25q1024", INFO(0x20ba21, 0x0, 64 * 1024, 2048, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+ {"n25q1024a", INFO(0x20bb21, 0x0, 64 * 1024, 2048, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+ {"mt25qu02g", INFO(0x20bb22, 0x0, 64 * 1024, 4096, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+ {"mt25ql02g", INFO(0x20ba22, 0x0, 64 * 1024, 4096, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
+#endif
+#ifdef CONFIG_SPI_FLASH_SST /* SST */
+ {"sst25vf040b", INFO(0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WR) },
+ {"sst25vf080b", INFO(0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | SST_WR) },
+ {"sst25vf016b", INFO(0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | SST_WR) },
+ {"sst25vf032b", INFO(0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | SST_WR) },
+ {"sst25vf064c", INFO(0xbf254b, 0x0, 64 * 1024, 128, SECT_4K) },
+ {"sst25wf512", INFO(0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | SST_WR) },
+ {"sst25wf010", INFO(0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | SST_WR) },
+ {"sst25wf020", INFO(0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | SST_WR) },
+ {"sst25wf040", INFO(0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WR) },
+ {"sst25wf040b", INFO(0x621613, 0x0, 64 * 1024, 8, SECT_4K) },
+ {"sst25wf080", INFO(0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WR) },
+#endif
+#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */
+ {"w25p80", INFO(0xef2014, 0x0, 64 * 1024, 16, 0) },
+ {"w25p16", INFO(0xef2015, 0x0, 64 * 1024, 32, 0) },
+ {"w25p32", INFO(0xef2016, 0x0, 64 * 1024, 64, 0) },
+ {"w25x40", INFO(0xef3013, 0x0, 64 * 1024, 8, SECT_4K) },
+ {"w25x16", INFO(0xef3015, 0x0, 64 * 1024, 32, SECT_4K) },
+ {"w25x32", INFO(0xef3016, 0x0, 64 * 1024, 64, SECT_4K) },
+ {"w25x64", INFO(0xef3017, 0x0, 64 * 1024, 128, SECT_4K) },
+ {"w25q80bl", INFO(0xef4014, 0x0, 64 * 1024, 16, RD_FULL | WR_QPP | SECT_4K) },
+ {"w25q16cl", INFO(0xef4015, 0x0, 64 * 1024, 32, RD_FULL | WR_QPP | SECT_4K) },
+ {"w25q32bv", INFO(0xef4016, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K) },
+ {"w25q64cv", INFO(0xef4017, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K) },
+ {"w25q128bv", INFO(0xef4018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP | SECT_4K) },
+ {"w25q256", INFO(0xef4019, 0x0, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
+ {"w25q80bw", INFO(0xef5014, 0x0, 64 * 1024, 16, RD_FULL | WR_QPP | SECT_4K) },
+ {"w25q16dw", INFO(0xef6015, 0x0, 64 * 1024, 32, RD_FULL | WR_QPP | SECT_4K) },
+ {"w25q32dw", INFO(0xef6016, 0x0, 64 * 1024, 64, RD_FULL | WR_QPP | SECT_4K) },
+ {"w25q64dw", INFO(0xef6017, 0x0, 64 * 1024, 128, RD_FULL | WR_QPP | SECT_4K) },
+ {"w25q128fw", INFO(0xef6018, 0x0, 64 * 1024, 256, RD_FULL | WR_QPP | SECT_4K) },
+#endif
+ {}, /* Empty entry to terminate the list */
+ /*
+ * 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/drivers/mtd/spi/sunxi_spi_spl.c b/drivers/mtd/spi/sunxi_spi_spl.c
index 67c7edd..7502314 100644
--- a/drivers/mtd/spi/sunxi_spi_spl.c
+++ b/drivers/mtd/spi/sunxi_spi_spl.c
@@ -158,9 +158,10 @@ static void spi0_disable_clock(void)
(1 << AHB_RESET_SPI0_SHIFT));
}
-static int spi0_init(void)
+static void spi0_init(void)
{
unsigned int pin_function = SUNXI_GPC_SPI0;
+
if (IS_ENABLED(CONFIG_MACH_SUN50I))
pin_function = SUN50I_GPC_SPI0;
diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c
index 6851ba9..791f3e8 100644
--- a/drivers/spi/kirkwood_spi.c
+++ b/drivers/spi/kirkwood_spi.c
@@ -271,6 +271,21 @@ static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
{
+ struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+ struct kwspi_registers *reg = plat->spireg;
+ u32 data = readl(&reg->cfg);
+
+ data &= ~(KWSPI_CPHA | KWSPI_CPOL | KWSPI_RXLSBF | KWSPI_TXLSBF);
+
+ if (mode & SPI_CPHA)
+ data |= KWSPI_CPHA;
+ if (mode & SPI_CPOL)
+ data |= KWSPI_CPOL;
+ if (mode & SPI_LSB_FIRST)
+ data |= (KWSPI_RXLSBF | KWSPI_TXLSBF);
+
+ writel(data, &reg->cfg);
+
return 0;
}
diff --git a/include/linux/err.h b/include/linux/err.h
index e4d22d5..22e5756 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -36,6 +36,11 @@ static inline long IS_ERR(const void *ptr)
return IS_ERR_VALUE((unsigned long)ptr);
}
+static inline bool IS_ERR_OR_NULL(const void *ptr)
+{
+ return !ptr || IS_ERR_VALUE((unsigned long)ptr);
+}
+
/**
* ERR_CAST - Explicitly cast an error-valued pointer to another pointer type
* @ptr: The pointer to cast.
diff --git a/include/spi.h b/include/spi.h
index 4c17983..deb65ef 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -30,10 +30,6 @@
#define SPI_RX_DUAL BIT(12) /* receive with 2 wires */
#define SPI_RX_QUAD BIT(13) /* receive with 4 wires */
-/* SPI bus connection options - see enum spi_dual_flash */
-#define SPI_CONN_DUAL_SHARED (1 << 0)
-#define SPI_CONN_DUAL_SEPARATED (1 << 1)
-
/* Header byte that marks the start of the message */
#define SPI_PREAMBLE_END_BYTE 0xec
@@ -93,7 +89,6 @@ struct dm_spi_slave_platdata {
* @max_write_size: If non-zero, the maximum number of bytes which can
* be written at once, excluding command bytes.
* @memory_map: Address of read-only SPI flash access.
- * @option: Varies SPI bus options - separate, shared bus.
* @flags: Indication of SPI flags.
*/
struct spi_slave {
@@ -117,7 +112,6 @@ struct spi_slave {
#define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END)
#define SPI_XFER_MMAP BIT(2) /* Memory Mapped start */
#define SPI_XFER_MMAP_END BIT(3) /* Memory Mapped End */
-#define SPI_XFER_U_PAGE BIT(4)
};
/**