* [PATCH v3 0/4] mtd: spi-nor: split SFDP, ID database, and fixups
@ 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay
0 siblings, 0 replies; 15+ messages in thread
From: Takahiro Kuwano @ 2026-10-16 1:43 UTC (permalink / raw)
To: u-boot
Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam,
Eugen Hristev, Takahiro Kuwano
The spi-nor-core.c contains optional logics like SFDP and manufcaturer
specific fixups. The spi-nor-ids.c has single large ID database. There
are many #ifdef directives in those files and that negatively affects
readability and maintainability.
This series, as the first step of cleanup, move SFDP logic, IDs, and
fixups to newly source files. Reworking, renaming, and reformating
existing code is not a scope of this series and further cleanup will be
taken place in follow-up patches.
Here is the code size impact when applying this series.
Measured by my AMD Zynq-7000 (ARM32) environment with SFDP and all
manufcaturers are enabled.
SPI-NOR:
text data bss dec hex filename
BEFORE 720685 14084 0 734769 b3631 u-boot
AFTER 721827 14156 0 735983 b3aef u-boot
DELTA +1142 +72
TINY:
text data bss dec hex filename
BEFORE 77399 3128 248 80775 13b87 spl/u-boot-spl
AFTER 77589 3200 248 81037 13c8d spl/u-boot-spl
DELTA +190 +72
Changes in v3:
- Expose manufacturers table so that sandbox can look up
- Update sandbox to handle manufacturers table
- Link to v2: https://lore.kernel.org/u-boot/20260924-split-sfdp-id-v2-0-aafc70e0b657@infineon.com/
Changes in v2:
- Rebase on top of next
- Link to v1: https://lore.kernel.org/u-boot/20260612-split-id-table-into-vendor-files-v1-0-dfaaa82cc6f0@infineon.com/
Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com>
---
Takahiro Kuwano (4):
mtd: spi-nor: move SFDP logic out of the core
mtd: spi-nor: import manufacturer driver concept from Linux
mtd: spi-nor: move flash info entries to manufacturer drivers
mtd: spi-nor: move fixups to manufacturer drivers
drivers/mtd/spi/Makefile | 18 +
drivers/mtd/spi/atmel.c | 28 +
drivers/mtd/spi/dosilicon.c | 25 +
drivers/mtd/spi/eon.c | 23 +
drivers/mtd/spi/fujitsu.c | 27 +
drivers/mtd/spi/gigadevice.c | 140 ++
drivers/mtd/spi/issi.c | 84 ++
drivers/mtd/spi/macronix.c | 154 +++
drivers/mtd/spi/micron-st.c | 169 +++
drivers/mtd/spi/puya.c | 56 +
drivers/mtd/spi/sandbox.c | 33 +-
drivers/mtd/spi/sf_internal.h | 136 +-
drivers/mtd/spi/sfdp.c | 720 ++++++++++
drivers/mtd/spi/sfdp.h | 152 +++
drivers/mtd/spi/siliconkaiser.c | 18 +
drivers/mtd/spi/spansion.c | 700 ++++++++++
drivers/mtd/spi/spi-nor-core.c | 2751 +++++++--------------------------------
drivers/mtd/spi/spi-nor-ids.c | 753 +----------
drivers/mtd/spi/spi-nor-tiny.c | 11 +-
drivers/mtd/spi/sst.c | 34 +
drivers/mtd/spi/winbond.c | 250 ++++
drivers/mtd/spi/xmc.c | 27 +
drivers/mtd/spi/xtx.c | 54 +
drivers/mtd/spi/zbit.c | 19 +
include/linux/mtd/spi-nor.h | 2 +
25 files changed, 3404 insertions(+), 2980 deletions(-)
---
base-commit: ed869863c7e2aca50d57a05d843830dd843138c4
change-id: 20261016-split-sfdp-id-v3-f5602435a540
Best regards,
--
Takahiro Kuwano <takahiro.kuwano@infineon.com>
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v3 0/4] mtd: spi-nor: split SFDP, ID database, and fixups @ 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay 0 siblings, 0 replies; 15+ messages in thread From: Takahiro Kuwano via B4 Relay @ 2026-10-16 1:43 UTC (permalink / raw) To: u-boot Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev, Takahiro Kuwano The spi-nor-core.c contains optional logics like SFDP and manufcaturer specific fixups. The spi-nor-ids.c has single large ID database. There are many #ifdef directives in those files and that negatively affects readability and maintainability. This series, as the first step of cleanup, move SFDP logic, IDs, and fixups to newly source files. Reworking, renaming, and reformating existing code is not a scope of this series and further cleanup will be taken place in follow-up patches. Here is the code size impact when applying this series. Measured by my AMD Zynq-7000 (ARM32) environment with SFDP and all manufcaturers are enabled. SPI-NOR: text data bss dec hex filename BEFORE 720685 14084 0 734769 b3631 u-boot AFTER 721827 14156 0 735983 b3aef u-boot DELTA +1142 +72 TINY: text data bss dec hex filename BEFORE 77399 3128 248 80775 13b87 spl/u-boot-spl AFTER 77589 3200 248 81037 13c8d spl/u-boot-spl DELTA +190 +72 Changes in v3: - Expose manufacturers table so that sandbox can look up - Update sandbox to handle manufacturers table - Link to v2: https://lore.kernel.org/u-boot/20260924-split-sfdp-id-v2-0-aafc70e0b657@infineon.com/ Changes in v2: - Rebase on top of next - Link to v1: https://lore.kernel.org/u-boot/20260612-split-id-table-into-vendor-files-v1-0-dfaaa82cc6f0@infineon.com/ Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com> --- Takahiro Kuwano (4): mtd: spi-nor: move SFDP logic out of the core mtd: spi-nor: import manufacturer driver concept from Linux mtd: spi-nor: move flash info entries to manufacturer drivers mtd: spi-nor: move fixups to manufacturer drivers drivers/mtd/spi/Makefile | 18 + drivers/mtd/spi/atmel.c | 28 + drivers/mtd/spi/dosilicon.c | 25 + drivers/mtd/spi/eon.c | 23 + drivers/mtd/spi/fujitsu.c | 27 + drivers/mtd/spi/gigadevice.c | 140 ++ drivers/mtd/spi/issi.c | 84 ++ drivers/mtd/spi/macronix.c | 154 +++ drivers/mtd/spi/micron-st.c | 169 +++ drivers/mtd/spi/puya.c | 56 + drivers/mtd/spi/sandbox.c | 33 +- drivers/mtd/spi/sf_internal.h | 136 +- drivers/mtd/spi/sfdp.c | 720 ++++++++++ drivers/mtd/spi/sfdp.h | 152 +++ drivers/mtd/spi/siliconkaiser.c | 18 + drivers/mtd/spi/spansion.c | 700 ++++++++++ drivers/mtd/spi/spi-nor-core.c | 2751 +++++++-------------------------------- drivers/mtd/spi/spi-nor-ids.c | 753 +---------- drivers/mtd/spi/spi-nor-tiny.c | 11 +- drivers/mtd/spi/sst.c | 34 + drivers/mtd/spi/winbond.c | 250 ++++ drivers/mtd/spi/xmc.c | 27 + drivers/mtd/spi/xtx.c | 54 + drivers/mtd/spi/zbit.c | 19 + include/linux/mtd/spi-nor.h | 2 + 25 files changed, 3404 insertions(+), 2980 deletions(-) --- base-commit: ed869863c7e2aca50d57a05d843830dd843138c4 change-id: 20261016-split-sfdp-id-v3-f5602435a540 Best regards, -- Takahiro Kuwano <takahiro.kuwano@infineon.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 1/4] mtd: spi-nor: move SFDP logic out of the core 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay @ 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay -1 siblings, 0 replies; 15+ messages in thread From: Takahiro Kuwano @ 2026-10-16 1:43 UTC (permalink / raw) To: u-boot Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev, Takahiro Kuwano Move SFDP parsing functions and definitions to newly introduced sfdp.c/sfdp.h. The new module (sfdp.c) is compiled along with spi-nor-core depending on SPI_FLASH_SFDP_SUPPORT configuration option. The quad_enable hooks and some helper functions are exposed from core and some need to be guarded by CONFIG_SPI_FLASH_TINY to avoid name conflict with local functions in tiny. Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com> --- drivers/mtd/spi/Makefile | 1 + drivers/mtd/spi/sf_internal.h | 50 +++ drivers/mtd/spi/sfdp.c | 711 +++++++++++++++++++++++++++++++++ drivers/mtd/spi/sfdp.h | 152 +++++++ drivers/mtd/spi/spi-nor-core.c | 879 +---------------------------------------- 5 files changed, 919 insertions(+), 874 deletions(-) diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 9a96be11e6d..1828e5fadfe 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -14,6 +14,7 @@ ifeq ($(CONFIG_$(PHASE_)SPI_FLASH_TINY),y) spi-nor-y += spi-nor-tiny.o else spi-nor-y += spi-nor-core.o +spi-nor-$(CONFIG_SPI_FLASH_SFDP_SUPPORT) += sfdp.o endif obj-$(CONFIG_SPI_FLASH) += spi-nor.o diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 8d2249ce354..576617beb70 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -13,9 +13,35 @@ #include <linux/types.h> #include <linux/compiler.h> +#include "sfdp.h" + #define SPI_NOR_MAX_ID_LEN 6 #define SPI_NOR_MAX_ADDR_WIDTH 4 +/** + * struct spi_nor_fixups - SPI NOR fixup hooks + * @post_bfpt: called after the BFPT table has been parsed + * @post_sfdp: called after SFDP has been parsed. Typically used to tweak + * various parameters that could not be extracted by other means + * (i.e. when information provided by the SFDP tables are incomplete + * or wrong). + * @late_init: used to initialize flash parameters that are not declared in the + * JESD216 SFDP standard, or where SFDP tables not defined at all. + * + * Those hooks can be used to tweak the SPI NOR configuration when the SFDP + * table is broken or not available. + */ +struct spi_nor_fixups { + int (*post_bfpt)(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params); + void (*post_sfdp)(struct spi_nor *nor, + struct spi_nor_flash_parameter *params); + void (*late_init)(struct spi_nor *nor, + struct spi_nor_flash_parameter *params); +}; + struct flash_info { #if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) char *name; @@ -93,4 +119,28 @@ static inline void spi_flash_mtd_unregister(struct spi_flash *flash) } #endif +#if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT) +int spi_nor_parse_sfdp(struct spi_nor *nor, + struct spi_nor_flash_parameter *params); +#else +static inline int spi_nor_parse_sfdp(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + return -EINVAL; +} +#endif + +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) +void spi_nor_set_read_settings(struct spi_nor_read_command *read, + u8 num_mode_clocks, + u8 num_wait_states, + u8 opcode, + enum spi_nor_protocol proto); +int spansion_read_cr_quad_enable(struct spi_nor *nor); +int macronix_quad_enable(struct spi_nor *nor); +#endif + +int spi_nor_hwcaps_read2cmd(u32 hwcaps); +int spansion_no_read_cr_quad_enable(struct spi_nor *nor); + #endif /* _SF_INTERNAL_H_ */ diff --git a/drivers/mtd/spi/sfdp.c b/drivers/mtd/spi/sfdp.c new file mode 100644 index 00000000000..fd545796d50 --- /dev/null +++ b/drivers/mtd/spi/sfdp.c @@ -0,0 +1,711 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005, Intec Automation Inc. + * Copyright (C) 2014, Freescale Semiconductor, Inc. + */ + +#include <stddef.h> +#include <string.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <linux/errno.h> +#include <linux/sizes.h> +#include <linux/bitfield.h> +#include <linux/mtd/spi-nor.h> +#include <spi.h> + +#include "sf_internal.h" + +/* + * Serial Flash Discoverable Parameters (SFDP) parsing. + */ + +/** + * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters. + * @nor: pointer to a 'struct spi_nor' + * @addr: offset in the SFDP area to start reading data from + * @len: number of bytes to read + * @buf: buffer where the SFDP data are copied into (dma-safe memory) + * + * Whatever the actual numbers of bytes for address and dummy cycles are + * for (Fast) Read commands, the Read SFDP (5Ah) instruction is always + * followed by a 3-byte address and 8 dummy clock cycles. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, + size_t len, void *buf) +{ + u8 addr_width, read_opcode, read_dummy; + int ret; + + read_opcode = nor->read_opcode; + addr_width = nor->addr_width; + read_dummy = nor->read_dummy; + + nor->read_opcode = SPINOR_OP_RDSFDP; + nor->addr_width = 3; + nor->read_dummy = 8; + + while (len) { + /* Both chips are identical, so should be the SFDP data */ + if (nor->flags & SNOR_F_HAS_PARALLEL) + nor->spi->flags |= SPI_XFER_LOWER; + + ret = nor->read(nor, addr, len, (u8 *)buf); + if (!ret || ret > len) { + ret = -EIO; + goto read_err; + } + if (ret < 0) + goto read_err; + + buf += ret; + addr += ret; + len -= ret; + } + ret = 0; + +read_err: + nor->read_opcode = read_opcode; + nor->addr_width = addr_width; + nor->read_dummy = read_dummy; + + return ret; +} + +/** + * spi_nor_read_sfdp_dma_unsafe() - read Serial Flash Discoverable Parameters. + * @nor: pointer to a 'struct spi_nor' + * @addr: offset in the SFDP area to start reading data from + * @len: number of bytes to read + * @buf: buffer where the SFDP data are copied into + * + * Wrap spi_nor_read_sfdp() using a kmalloc'ed bounce buffer as @buf is now not + * guaranteed to be dma-safe. + * + * Return: -ENOMEM if kmalloc() fails, the return code of spi_nor_read_sfdp() + * otherwise. + */ +static int spi_nor_read_sfdp_dma_unsafe(struct spi_nor *nor, u32 addr, + size_t len, void *buf) +{ + void *dma_safe_buf; + int ret; + + dma_safe_buf = kmalloc(len, GFP_KERNEL); + if (!dma_safe_buf) + return -ENOMEM; + + ret = spi_nor_read_sfdp(nor, addr, len, dma_safe_buf); + memcpy(buf, dma_safe_buf, len); + kfree(dma_safe_buf); + + return ret; +} + +/* Fast Read settings. */ + +static void +spi_nor_set_read_settings_from_bfpt(struct spi_nor_read_command *read, + u16 half, + enum spi_nor_protocol proto) +{ + read->num_mode_clocks = (half >> 5) & 0x07; + read->num_wait_states = (half >> 0) & 0x1f; + read->opcode = (half >> 8) & 0xff; + read->proto = proto; +} + +struct sfdp_bfpt_read { + /* The Fast Read x-y-z hardware capability in params->hwcaps.mask. */ + u32 hwcaps; + + /* + * The <supported_bit> bit in <supported_dword> BFPT DWORD tells us + * whether the Fast Read x-y-z command is supported. + */ + u32 supported_dword; + u32 supported_bit; + + /* + * The half-word at offset <setting_shift> in <setting_dword> BFPT DWORD + * encodes the op code, the number of mode clocks and the number of wait + * states to be used by Fast Read x-y-z command. + */ + u32 settings_dword; + u32 settings_shift; + + /* The SPI protocol for this Fast Read x-y-z command. */ + enum spi_nor_protocol proto; +}; + +static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = { + /* Fast Read 1-1-2 */ + { + SNOR_HWCAPS_READ_1_1_2, + BFPT_DWORD(1), BIT(16), /* Supported bit */ + BFPT_DWORD(4), 0, /* Settings */ + SNOR_PROTO_1_1_2, + }, + + /* Fast Read 1-2-2 */ + { + SNOR_HWCAPS_READ_1_2_2, + BFPT_DWORD(1), BIT(20), /* Supported bit */ + BFPT_DWORD(4), 16, /* Settings */ + SNOR_PROTO_1_2_2, + }, + + /* Fast Read 2-2-2 */ + { + SNOR_HWCAPS_READ_2_2_2, + BFPT_DWORD(5), BIT(0), /* Supported bit */ + BFPT_DWORD(6), 16, /* Settings */ + SNOR_PROTO_2_2_2, + }, + + /* Fast Read 1-1-4 */ + { + SNOR_HWCAPS_READ_1_1_4, + BFPT_DWORD(1), BIT(22), /* Supported bit */ + BFPT_DWORD(3), 16, /* Settings */ + SNOR_PROTO_1_1_4, + }, + + /* Fast Read 1-4-4 */ + { + SNOR_HWCAPS_READ_1_4_4, + BFPT_DWORD(1), BIT(21), /* Supported bit */ + BFPT_DWORD(3), 0, /* Settings */ + SNOR_PROTO_1_4_4, + }, + + /* Fast Read 4-4-4 */ + { + SNOR_HWCAPS_READ_4_4_4, + BFPT_DWORD(5), BIT(4), /* Supported bit */ + BFPT_DWORD(7), 16, /* Settings */ + SNOR_PROTO_4_4_4, + }, +}; + +struct sfdp_bfpt_erase { + /* + * The half-word at offset <shift> in DWORD <dwoard> encodes the + * op code and erase sector size to be used by Sector Erase commands. + */ + u32 dword; + u32 shift; +}; + +static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = { + /* Erase Type 1 in DWORD8 bits[15:0] */ + {BFPT_DWORD(8), 0}, + + /* Erase Type 2 in DWORD8 bits[31:16] */ + {BFPT_DWORD(8), 16}, + + /* Erase Type 3 in DWORD9 bits[15:0] */ + {BFPT_DWORD(9), 0}, + + /* Erase Type 4 in DWORD9 bits[31:16] */ + {BFPT_DWORD(9), 16}, +}; + +static int +spi_nor_post_bfpt_fixups(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + if (nor->fixups && nor->fixups->post_bfpt) + return nor->fixups->post_bfpt(nor, bfpt_header, bfpt, params); + + return 0; +} + +/** + * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table. + * @nor: pointer to a 'struct spi_nor' + * @bfpt_header: pointer to the 'struct sfdp_parameter_header' describing + * the Basic Flash Parameter Table length and version + * @params: pointer to the 'struct spi_nor_flash_parameter' to be + * filled + * + * The Basic Flash Parameter Table is the main and only mandatory table as + * defined by the SFDP (JESD216) specification. + * It provides us with the total size (memory density) of the data array and + * the number of address bytes for Fast Read, Page Program and Sector Erase + * commands. + * For Fast READ commands, it also gives the number of mode clock cycles and + * wait states (regrouped in the number of dummy clock cycles) for each + * supported instruction op code. + * For Page Program, the page size is now available since JESD216 rev A, however + * the supported instruction op codes are still not provided. + * For Sector Erase commands, this table stores the supported instruction op + * codes and the associated sector sizes. + * Finally, the Quad Enable Requirements (QER) are also available since JESD216 + * rev A. The QER bits encode the manufacturer dependent procedure to be + * executed to set the Quad Enable (QE) bit in some internal register of the + * Quad SPI memory. Indeed the QE bit, when it exists, must be set before + * sending any Quad SPI command to the memory. Actually, setting the QE bit + * tells the memory to reassign its WP# and HOLD#/RESET# pins to functions IO2 + * and IO3 hence enabling 4 (Quad) I/O lines. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_bfpt(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + struct spi_nor_flash_parameter *params) +{ + struct mtd_info *mtd = &nor->mtd; + struct sfdp_bfpt bfpt; + size_t len; + int i, cmd, err; + u32 addr; + u16 half; + + /* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */ + if (bfpt_header->length < BFPT_DWORD_MAX_JESD216) + return -EINVAL; + + /* Read the Basic Flash Parameter Table. */ + len = min_t(size_t, sizeof(bfpt), + bfpt_header->length * sizeof(u32)); + addr = SFDP_PARAM_HEADER_PTP(bfpt_header); + memset(&bfpt, 0, sizeof(bfpt)); + err = spi_nor_read_sfdp_dma_unsafe(nor, addr, len, &bfpt); + if (err < 0) + return err; + + /* Fix endianness of the BFPT DWORDs. */ + for (i = 0; i < BFPT_DWORD_MAX; i++) + bfpt.dwords[i] = le32_to_cpu(bfpt.dwords[i]); + + /* Number of address bytes. */ + switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) { + case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY: + case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4: + nor->addr_width = 3; + nor->addr_mode_nbytes = 3; + break; + + case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY: + nor->addr_width = 4; + nor->addr_mode_nbytes = 4; + break; + + default: + break; + } + + /* Flash Memory Density (in bits). */ + params->size = bfpt.dwords[BFPT_DWORD(2)]; + if (params->size & BIT(31)) { + params->size &= ~BIT(31); + + /* + * Prevent overflows on params->size. Anyway, a NOR of 2^64 + * bits is unlikely to exist so this error probably means + * the BFPT we are reading is corrupted/wrong. + */ + if (params->size > 63) + return -EINVAL; + + params->size = 1ULL << params->size; + } else { + params->size++; + } + params->size >>= 3; /* Convert to bytes. */ + + /* Fast Read settings. */ + for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { + const struct sfdp_bfpt_read *rd = &sfdp_bfpt_reads[i]; + struct spi_nor_read_command *read; + + if (!(bfpt.dwords[rd->supported_dword] & rd->supported_bit)) { + params->hwcaps.mask &= ~rd->hwcaps; + continue; + } + + params->hwcaps.mask |= rd->hwcaps; + cmd = spi_nor_hwcaps_read2cmd(rd->hwcaps); + read = ¶ms->reads[cmd]; + half = bfpt.dwords[rd->settings_dword] >> rd->settings_shift; + spi_nor_set_read_settings_from_bfpt(read, half, rd->proto); + } + + /* Sector Erase settings. */ + for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) { + const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i]; + u32 erasesize; + u8 opcode; + + half = bfpt.dwords[er->dword] >> er->shift; + erasesize = half & 0xff; + + /* erasesize == 0 means this Erase Type is not supported. */ + if (!erasesize) + continue; + + erasesize = 1U << erasesize; + opcode = (half >> 8) & 0xff; +#ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS + if (erasesize == SZ_4K) { + nor->erase_opcode = opcode; + mtd->erasesize = erasesize; + break; + } +#endif + if (!mtd->erasesize || mtd->erasesize < erasesize) { + nor->erase_opcode = opcode; + mtd->erasesize = erasesize; + } + } + + /* Stop here if not JESD216 rev A or later. */ + if (bfpt_header->length == BFPT_DWORD_MAX_JESD216) + return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, + params); + + /* Page size: this field specifies 'N' so the page size = 2^N bytes. */ + params->page_size = bfpt.dwords[BFPT_DWORD(11)]; + params->page_size &= BFPT_DWORD11_PAGE_SIZE_MASK; + params->page_size >>= BFPT_DWORD11_PAGE_SIZE_SHIFT; + params->page_size = 1U << params->page_size; + + /* Quad Enable Requirements. */ + switch (bfpt.dwords[BFPT_DWORD(15)] & BFPT_DWORD15_QER_MASK) { + case BFPT_DWORD15_QER_NONE: + params->quad_enable = NULL; + break; +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) + case BFPT_DWORD15_QER_SR2_BIT1_BUGGY: + case BFPT_DWORD15_QER_SR2_BIT1_NO_RD: + params->quad_enable = spansion_no_read_cr_quad_enable; + break; +#endif +#if defined(CONFIG_SPI_FLASH_MACRONIX) || defined(CONFIG_SPI_FLASH_ISSI) + case BFPT_DWORD15_QER_SR1_BIT6: + params->quad_enable = macronix_quad_enable; + break; +#endif +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) + case BFPT_DWORD15_QER_SR2_BIT1: + params->quad_enable = spansion_read_cr_quad_enable; + break; +#endif + default: + dev_dbg(nor->dev, "BFPT QER reserved value used\n"); + break; + } + + /* Soft Reset support. */ + if (bfpt.dwords[BFPT_DWORD(16)] & BFPT_DWORD16_SOFT_RST) + nor->flags |= SNOR_F_SOFT_RESET; + + /* Stop here if JESD216 rev B. */ + if (bfpt_header->length == BFPT_DWORD_MAX_JESD216B) + return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, + params); + + /* 8D-8D-8D command extension. */ + switch (bfpt.dwords[BFPT_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) { + case BFPT_DWORD18_CMD_EXT_REP: + nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; + break; + + case BFPT_DWORD18_CMD_EXT_INV: + nor->cmd_ext_type = SPI_NOR_EXT_INVERT; + break; + + case BFPT_DWORD18_CMD_EXT_RES: + return -EINVAL; + + case BFPT_DWORD18_CMD_EXT_16B: + dev_err(nor->dev, "16-bit opcodes not supported\n"); + return -ENOTSUPP; + } + + return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params); +} + +/** + * spi_nor_parse_microchip_sfdp() - parse the Microchip manufacturer specific + * SFDP table. + * @nor: pointer to a 'struct spi_nor'. + * @param_header: pointer to the SFDP parameter header. + * + * Return: 0 on success, -errno otherwise. + */ +static int +spi_nor_parse_microchip_sfdp(struct spi_nor *nor, + const struct sfdp_parameter_header *param_header) +{ + size_t size; + u32 addr; + int ret; + + size = param_header->length * sizeof(u32); + addr = SFDP_PARAM_HEADER_PTP(param_header); + + nor->manufacturer_sfdp = devm_kmalloc(nor->dev, size, GFP_KERNEL); + if (!nor->manufacturer_sfdp) + return -ENOMEM; + + ret = spi_nor_read_sfdp(nor, addr, size, nor->manufacturer_sfdp); + + return ret; +} + +/** + * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table + * @nor: pointer to a 'struct spi_nor' + * @profile1_header: pointer to the 'struct sfdp_parameter_header' describing + * the 4-Byte Address Instruction Table length and version. + * @params: pointer to the 'struct spi_nor_flash_parameter' to be. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_profile1(struct spi_nor *nor, + const struct sfdp_parameter_header *profile1_header, + struct spi_nor_flash_parameter *params) +{ + u32 *table, opcode, addr; + size_t len; + int ret, i; + u8 dummy; + + len = profile1_header->length * sizeof(*table); + table = kmalloc(len, GFP_KERNEL); + if (!table) + return -ENOMEM; + + addr = SFDP_PARAM_HEADER_PTP(profile1_header); + ret = spi_nor_read_sfdp(nor, addr, len, table); + if (ret) + goto out; + + /* Fix endianness of the table DWORDs. */ + for (i = 0; i < profile1_header->length; i++) + table[i] = le32_to_cpu(table[i]); + + /* Get 8D-8D-8D fast read opcode and dummy cycles. */ + opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, table[0]); + + /* + * We don't know what speed the controller is running at. Find the + * dummy cycles for the fastest frequency the flash can run at to be + * sure we are never short of dummy cycles. A value of 0 means the + * frequency is not supported. + * + * Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let + * flashes set the correct value if needed in their fixup hooks. + */ + dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, table[3]); + if (!dummy) + dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ, table[4]); + if (!dummy) + dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ, table[4]); + if (!dummy) + dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ, table[4]); + if (!dummy) + dummy = PROFILE1_DUMMY_DEFAULT; + + /* Round up to an even value to avoid tripping controllers up. */ + dummy = ROUND_UP_TO(dummy, 2); + + /* Update the fast read settings. */ + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], + 0, dummy, opcode, + SNOR_PROTO_8_8_8_DTR); + + /* + * Set the Read Status Register dummy cycles and dummy address bytes. + */ + if (table[0] & PROFILE1_DWORD1_RDSR_DUMMY) + params->rdsr_dummy = 8; + else + params->rdsr_dummy = 4; + + if (table[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES) + params->rdsr_addr_nbytes = 4; + else + params->rdsr_addr_nbytes = 0; + +out: + kfree(table); + return ret; +} + +/** + * spi_nor_parse_sccr() - Parse the Status, Control and Configuration Register + * Map. + * @nor: pointer to a 'struct spi_nor' + * @sccr_header: pointer to the 'struct sfdp_parameter_header' describing + * the SCCR Map table length and version. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_sccr(struct spi_nor *nor, + const struct sfdp_parameter_header *sccr_header) +{ + u32 *table, addr; + size_t len; + int ret, i; + + len = sccr_header->length * sizeof(*table); + table = kmalloc(len, GFP_KERNEL); + if (!table) + return -ENOMEM; + + addr = SFDP_PARAM_HEADER_PTP(sccr_header); + ret = spi_nor_read_sfdp(nor, addr, len, table); + if (ret) + goto out; + + /* Fix endianness of the table DWORDs. */ + for (i = 0; i < sccr_header->length; i++) + table[i] = le32_to_cpu(table[i]); + + if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[21])) + nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; + +out: + kfree(table); + return ret; +} + +/** + * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. + * @nor: pointer to a 'struct spi_nor' + * @params: pointer to the 'struct spi_nor_flash_parameter' to be + * filled + * + * The Serial Flash Discoverable Parameters are described by the JEDEC JESD216 + * specification. This is a standard which tends to supported by almost all + * (Q)SPI memory manufacturers. Those hard-coded tables allow us to learn at + * runtime the main parameters needed to perform basic SPI flash operations such + * as Fast Read, Page Program or Sector Erase commands. + * + * Return: 0 on success, -errno otherwise. + */ +int spi_nor_parse_sfdp(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + const struct sfdp_parameter_header *param_header, *bfpt_header; + struct sfdp_parameter_header *param_headers = NULL; + struct sfdp_header header; + size_t psize; + int i, err; + + /* Get the SFDP header. */ + err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(header), &header); + if (err < 0) + return err; + + /* Check the SFDP header version. */ + if (le32_to_cpu(header.signature) != SFDP_SIGNATURE || + header.major != SFDP_JESD216_MAJOR) + return -EINVAL; + + /* + * Verify that the first and only mandatory parameter header is a + * Basic Flash Parameter Table header as specified in JESD216. + */ + bfpt_header = &header.bfpt_header; + if (SFDP_PARAM_HEADER_ID(bfpt_header) != SFDP_BFPT_ID || + bfpt_header->major != SFDP_JESD216_MAJOR) + return -EINVAL; + + /* + * Allocate memory then read all parameter headers with a single + * Read SFDP command. These parameter headers will actually be parsed + * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supported optional + * tables. + * Hence we read the parameter headers once for all to reduce the + * processing time. Also we use kmalloc() instead of devm_kmalloc() + * because we don't need to keep these parameter headers: the allocated + * memory is always released with kfree() before exiting this function. + */ + if (header.nph) { + psize = header.nph * sizeof(*param_headers); + + param_headers = kmalloc(psize, GFP_KERNEL); + if (!param_headers) + return -ENOMEM; + + err = spi_nor_read_sfdp(nor, sizeof(header), + psize, param_headers); + if (err < 0) { + dev_err(nor->dev, + "failed to read SFDP parameter headers\n"); + goto exit; + } + } + + /* + * Check other parameter headers to get the latest revision of + * the basic flash parameter table. + */ + for (i = 0; i < header.nph; i++) { + param_header = ¶m_headers[i]; + + if (SFDP_PARAM_HEADER_ID(param_header) == SFDP_BFPT_ID && + param_header->major == SFDP_JESD216_MAJOR && + (param_header->minor > bfpt_header->minor || + (param_header->minor == bfpt_header->minor && + param_header->length > bfpt_header->length))) + bfpt_header = param_header; + } + + err = spi_nor_parse_bfpt(nor, bfpt_header, params); + if (err) + goto exit; + + /* Parse other parameter headers. */ + for (i = 0; i < header.nph; i++) { + param_header = ¶m_headers[i]; + + switch (SFDP_PARAM_HEADER_ID(param_header)) { + case SFDP_SECTOR_MAP_ID: + dev_info(nor->dev, + "non-uniform erase sector maps are not supported yet.\n"); + break; + + case SFDP_SST_ID: + err = spi_nor_parse_microchip_sfdp(nor, param_header); + break; + + case SFDP_PROFILE1_ID: + err = spi_nor_parse_profile1(nor, param_header, params); + break; + + case SFDP_SCCR_MAP_ID: + err = spi_nor_parse_sccr(nor, param_header); + break; + + default: + break; + } + + if (err) { + dev_warn(nor->dev, + "Failed to parse optional parameter table: %04x\n", + SFDP_PARAM_HEADER_ID(param_header)); + /* + * Let's not drop all information we extracted so far + * if optional table parsers fail. In case of failing, + * each optional parser is responsible to roll back to + * the previously known spi_nor data. + */ + err = 0; + } + } + +exit: + kfree(param_headers); + return err; +} diff --git a/drivers/mtd/spi/sfdp.h b/drivers/mtd/spi/sfdp.h new file mode 100644 index 00000000000..f85ac71490b --- /dev/null +++ b/drivers/mtd/spi/sfdp.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005, Intec Automation Inc. + * Copyright (C) 2014, Freescale Semiconductor, Inc. + */ + +#ifndef _SPI_NOR_SFDP_H_ +#define _SPI_NOR_SFDP_H_ + +#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) + +struct sfdp_parameter_header { + u8 id_lsb; + u8 minor; + u8 major; + u8 length; /* in double words */ + u8 parameter_table_pointer[3]; /* byte address */ + u8 id_msb; +}; + +#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb) +#define SFDP_PARAM_HEADER_PTP(p) \ + (((p)->parameter_table_pointer[2] << 16) | \ + ((p)->parameter_table_pointer[1] << 8) | \ + ((p)->parameter_table_pointer[0] << 0)) + +#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ +#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ +#define SFDP_SST_ID 0x01bf /* Manufacturer specific Table */ +#define SFDP_PROFILE1_ID 0xff05 /* xSPI Profile 1.0 Table */ +#define SFDP_SCCR_MAP_ID 0xff87 /* + * Status, Control and Configuration + * Register Map. + */ + +#define SFDP_SIGNATURE 0x50444653U +#define SFDP_JESD216_MAJOR 1 +#define SFDP_JESD216_MINOR 0 +#define SFDP_JESD216A_MINOR 5 +#define SFDP_JESD216B_MINOR 6 + +struct sfdp_header { + u32 signature; /* Ox50444653U <=> "SFDP" */ + u8 minor; + u8 major; + u8 nph; /* 0-base number of parameter headers */ + u8 unused; + + /* Basic Flash Parameter Table. */ + struct sfdp_parameter_header bfpt_header; +}; + +/* Basic Flash Parameter Table */ + +/* + * JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs. + * They are indexed from 1 but C arrays are indexed from 0. + */ +#define BFPT_DWORD(i) ((i) - 1) +#define BFPT_DWORD_MAX 20 + +/* The first version of JESB216 defined only 9 DWORDs. */ +#define BFPT_DWORD_MAX_JESD216 9 +#define BFPT_DWORD_MAX_JESD216B 16 + +/* 1st DWORD. */ +#define BFPT_DWORD1_FAST_READ_1_1_2 BIT(16) +#define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17) +#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY (0x0UL << 17) +#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (0x1UL << 17) +#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY (0x2UL << 17) +#define BFPT_DWORD1_DTR BIT(19) +#define BFPT_DWORD1_FAST_READ_1_2_2 BIT(20) +#define BFPT_DWORD1_FAST_READ_1_4_4 BIT(21) +#define BFPT_DWORD1_FAST_READ_1_1_4 BIT(22) + +/* 5th DWORD. */ +#define BFPT_DWORD5_FAST_READ_2_2_2 BIT(0) +#define BFPT_DWORD5_FAST_READ_4_4_4 BIT(4) + +/* 11th DWORD. */ +#define BFPT_DWORD11_PAGE_SIZE_SHIFT 4 +#define BFPT_DWORD11_PAGE_SIZE_MASK GENMASK(7, 4) + +/* 15th DWORD. */ + +/* + * (from JESD216 rev B) + * Quad Enable Requirements (QER): + * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4 + * reads based on instruction. DQ3/HOLD# functions are hold during + * instruction phase. + * - 001b: QE is bit 1 of status register 2. It is set via Write Status with + * two data bytes where bit 1 of the second byte is one. + * [...] + * Writing only one byte to the status register has the side-effect of + * clearing status register 2, including the QE bit. The 100b code is + * used if writing one byte to the status register does not modify + * status register 2. + * - 010b: QE is bit 6 of status register 1. It is set via Write Status with + * one data byte where bit 6 is one. + * [...] + * - 011b: QE is bit 7 of status register 2. It is set via Write status + * register 2 instruction 3Eh with one data byte where bit 7 is one. + * [...] + * The status register 2 is read using instruction 3Fh. + * - 100b: QE is bit 1 of status register 2. It is set via Write Status with + * two data bytes where bit 1 of the second byte is one. + * [...] + * In contrast to the 001b code, writing one byte to the status + * register does not modify status register 2. + * - 101b: QE is bit 1 of status register 2. Status register 1 is read using + * Read Status instruction 05h. Status register2 is read using + * instruction 35h. QE is set via Writ Status instruction 01h with + * two data bytes where bit 1 of the second byte is one. + * [...] + */ +#define BFPT_DWORD15_QER_MASK GENMASK(22, 20) +#define BFPT_DWORD15_QER_NONE (0x0UL << 20) /* Micron */ +#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) +#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20) /* Macronix */ +#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20) +#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20) +#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */ + +#define BFPT_DWORD16_SOFT_RST BIT(12) +#define BFPT_DWORD16_EX4B_PWRCYC BIT(21) + +#define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29) +#define BFPT_DWORD18_CMD_EXT_REP (0x0UL << 29) /* Repeat */ +#define BFPT_DWORD18_CMD_EXT_INV (0x1UL << 29) /* Invert */ +#define BFPT_DWORD18_CMD_EXT_RES (0x2UL << 29) /* Reserved */ +#define BFPT_DWORD18_CMD_EXT_16B (0x3UL << 29) /* 16-bit opcode */ + +/* xSPI Profile 1.0 table (from JESD216D.01). */ +#define PROFILE1_DWORD1_RD_FAST_CMD GENMASK(15, 8) +#define PROFILE1_DWORD1_RDSR_DUMMY BIT(28) +#define PROFILE1_DWORD1_RDSR_ADDR_BYTES BIT(29) +#define PROFILE1_DWORD4_DUMMY_200MHZ GENMASK(11, 7) +#define PROFILE1_DWORD5_DUMMY_166MHZ GENMASK(31, 27) +#define PROFILE1_DWORD5_DUMMY_133MHZ GENMASK(21, 17) +#define PROFILE1_DWORD5_DUMMY_100MHZ GENMASK(11, 7) +#define PROFILE1_DUMMY_DEFAULT 20 + +/* Status, Control and Configuration Register Map(SCCR) */ +#define SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE BIT(31) + +struct sfdp_bfpt { + u32 dwords[BFPT_DWORD_MAX]; +}; + +#endif /* _SPI_NOR_SFDP_H_ */ diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 937d79af64e..b99a1a45d8f 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -50,171 +50,6 @@ */ #define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ) -#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) - -struct sfdp_parameter_header { - u8 id_lsb; - u8 minor; - u8 major; - u8 length; /* in double words */ - u8 parameter_table_pointer[3]; /* byte address */ - u8 id_msb; -}; - -#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb) -#define SFDP_PARAM_HEADER_PTP(p) \ - (((p)->parameter_table_pointer[2] << 16) | \ - ((p)->parameter_table_pointer[1] << 8) | \ - ((p)->parameter_table_pointer[0] << 0)) - -#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ -#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ -#define SFDP_SST_ID 0x01bf /* Manufacturer specific Table */ -#define SFDP_PROFILE1_ID 0xff05 /* xSPI Profile 1.0 Table */ -#define SFDP_SCCR_MAP_ID 0xff87 /* - * Status, Control and Configuration - * Register Map. - */ - -#define SFDP_SIGNATURE 0x50444653U -#define SFDP_JESD216_MAJOR 1 -#define SFDP_JESD216_MINOR 0 -#define SFDP_JESD216A_MINOR 5 -#define SFDP_JESD216B_MINOR 6 - -struct sfdp_header { - u32 signature; /* Ox50444653U <=> "SFDP" */ - u8 minor; - u8 major; - u8 nph; /* 0-base number of parameter headers */ - u8 unused; - - /* Basic Flash Parameter Table. */ - struct sfdp_parameter_header bfpt_header; -}; - -/* Basic Flash Parameter Table */ - -/* - * JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs. - * They are indexed from 1 but C arrays are indexed from 0. - */ -#define BFPT_DWORD(i) ((i) - 1) -#define BFPT_DWORD_MAX 20 - -/* The first version of JESB216 defined only 9 DWORDs. */ -#define BFPT_DWORD_MAX_JESD216 9 -#define BFPT_DWORD_MAX_JESD216B 16 - -/* 1st DWORD. */ -#define BFPT_DWORD1_FAST_READ_1_1_2 BIT(16) -#define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17) -#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY (0x0UL << 17) -#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (0x1UL << 17) -#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY (0x2UL << 17) -#define BFPT_DWORD1_DTR BIT(19) -#define BFPT_DWORD1_FAST_READ_1_2_2 BIT(20) -#define BFPT_DWORD1_FAST_READ_1_4_4 BIT(21) -#define BFPT_DWORD1_FAST_READ_1_1_4 BIT(22) - -/* 5th DWORD. */ -#define BFPT_DWORD5_FAST_READ_2_2_2 BIT(0) -#define BFPT_DWORD5_FAST_READ_4_4_4 BIT(4) - -/* 11th DWORD. */ -#define BFPT_DWORD11_PAGE_SIZE_SHIFT 4 -#define BFPT_DWORD11_PAGE_SIZE_MASK GENMASK(7, 4) - -/* 15th DWORD. */ - -/* - * (from JESD216 rev B) - * Quad Enable Requirements (QER): - * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4 - * reads based on instruction. DQ3/HOLD# functions are hold during - * instruction phase. - * - 001b: QE is bit 1 of status register 2. It is set via Write Status with - * two data bytes where bit 1 of the second byte is one. - * [...] - * Writing only one byte to the status register has the side-effect of - * clearing status register 2, including the QE bit. The 100b code is - * used if writing one byte to the status register does not modify - * status register 2. - * - 010b: QE is bit 6 of status register 1. It is set via Write Status with - * one data byte where bit 6 is one. - * [...] - * - 011b: QE is bit 7 of status register 2. It is set via Write status - * register 2 instruction 3Eh with one data byte where bit 7 is one. - * [...] - * The status register 2 is read using instruction 3Fh. - * - 100b: QE is bit 1 of status register 2. It is set via Write Status with - * two data bytes where bit 1 of the second byte is one. - * [...] - * In contrast to the 001b code, writing one byte to the status - * register does not modify status register 2. - * - 101b: QE is bit 1 of status register 2. Status register 1 is read using - * Read Status instruction 05h. Status register2 is read using - * instruction 35h. QE is set via Writ Status instruction 01h with - * two data bytes where bit 1 of the second byte is one. - * [...] - */ -#define BFPT_DWORD15_QER_MASK GENMASK(22, 20) -#define BFPT_DWORD15_QER_NONE (0x0UL << 20) /* Micron */ -#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) -#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20) /* Macronix */ -#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20) -#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20) -#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */ - -#define BFPT_DWORD16_SOFT_RST BIT(12) -#define BFPT_DWORD16_EX4B_PWRCYC BIT(21) - -#define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29) -#define BFPT_DWORD18_CMD_EXT_REP (0x0UL << 29) /* Repeat */ -#define BFPT_DWORD18_CMD_EXT_INV (0x1UL << 29) /* Invert */ -#define BFPT_DWORD18_CMD_EXT_RES (0x2UL << 29) /* Reserved */ -#define BFPT_DWORD18_CMD_EXT_16B (0x3UL << 29) /* 16-bit opcode */ - -/* xSPI Profile 1.0 table (from JESD216D.01). */ -#define PROFILE1_DWORD1_RD_FAST_CMD GENMASK(15, 8) -#define PROFILE1_DWORD1_RDSR_DUMMY BIT(28) -#define PROFILE1_DWORD1_RDSR_ADDR_BYTES BIT(29) -#define PROFILE1_DWORD4_DUMMY_200MHZ GENMASK(11, 7) -#define PROFILE1_DWORD5_DUMMY_166MHZ GENMASK(31, 27) -#define PROFILE1_DWORD5_DUMMY_133MHZ GENMASK(21, 17) -#define PROFILE1_DWORD5_DUMMY_100MHZ GENMASK(11, 7) -#define PROFILE1_DUMMY_DEFAULT 20 - -/* Status, Control and Configuration Register Map(SCCR) */ -#define SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE BIT(31) - -struct sfdp_bfpt { - u32 dwords[BFPT_DWORD_MAX]; -}; - -/** - * struct spi_nor_fixups - SPI NOR fixup hooks - * @post_bfpt: called after the BFPT table has been parsed - * @post_sfdp: called after SFDP has been parsed. Typically used to tweak - * various parameters that could not be extracted by other means - * (i.e. when information provided by the SFDP tables are incomplete - * or wrong). - * @late_init: used to initialize flash parameters that are not declared in the - * JESD216 SFDP standard, or where SFDP tables not defined at all. - * - * Those hooks can be used to tweak the SPI NOR configuration when the SFDP - * table is broken or not available. - */ -struct spi_nor_fixups { - int (*post_bfpt)(struct spi_nor *nor, - const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params); - void (*post_sfdp)(struct spi_nor *nor, - struct spi_nor_flash_parameter *params); - void (*late_init)(struct spi_nor *nor, - struct spi_nor_flash_parameter *params); -}; #define SPI_NOR_SRST_SLEEP_LEN 200 @@ -2121,7 +1956,7 @@ write_err: * * Return: 0 on success, -errno otherwise. */ -static int macronix_quad_enable(struct spi_nor *nor) +int macronix_quad_enable(struct spi_nor *nor) { int ret, val; @@ -2247,7 +2082,7 @@ static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr) * * Return: 0 on success, -errno otherwise. */ -static int spansion_read_cr_quad_enable(struct spi_nor *nor) +int spansion_read_cr_quad_enable(struct spi_nor *nor) { u8 sr_cr[2]; int ret; @@ -2301,7 +2136,7 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor) * * Return: 0 on success, -errno otherwise. */ -static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) +int spansion_no_read_cr_quad_enable(struct spi_nor *nor) { u8 sr_cr[2]; int ret; @@ -2321,7 +2156,7 @@ static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) #endif /* CONFIG_SPI_FLASH_SFDP_SUPPORT */ #endif /* CONFIG_SPI_FLASH_SPANSION */ -static void +void spi_nor_set_read_settings(struct spi_nor_read_command *read, u8 num_mode_clocks, u8 num_wait_states, @@ -2343,710 +2178,6 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, pp->proto = proto; } -#if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT) -/* - * Serial Flash Discoverable Parameters (SFDP) parsing. - */ - -/** - * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters. - * @nor: pointer to a 'struct spi_nor' - * @addr: offset in the SFDP area to start reading data from - * @len: number of bytes to read - * @buf: buffer where the SFDP data are copied into (dma-safe memory) - * - * Whatever the actual numbers of bytes for address and dummy cycles are - * for (Fast) Read commands, the Read SFDP (5Ah) instruction is always - * followed by a 3-byte address and 8 dummy clock cycles. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, - size_t len, void *buf) -{ - u8 addr_width, read_opcode, read_dummy; - int ret; - - read_opcode = nor->read_opcode; - addr_width = nor->addr_width; - read_dummy = nor->read_dummy; - - nor->read_opcode = SPINOR_OP_RDSFDP; - nor->addr_width = 3; - nor->read_dummy = 8; - - while (len) { - /* Both chips are identical, so should be the SFDP data */ - if (nor->flags & SNOR_F_HAS_PARALLEL) - nor->spi->flags |= SPI_XFER_LOWER; - - ret = nor->read(nor, addr, len, (u8 *)buf); - if (!ret || ret > len) { - ret = -EIO; - goto read_err; - } - if (ret < 0) - goto read_err; - - buf += ret; - addr += ret; - len -= ret; - } - ret = 0; - -read_err: - nor->read_opcode = read_opcode; - nor->addr_width = addr_width; - nor->read_dummy = read_dummy; - - return ret; -} - -/** - * spi_nor_read_sfdp_dma_unsafe() - read Serial Flash Discoverable Parameters. - * @nor: pointer to a 'struct spi_nor' - * @addr: offset in the SFDP area to start reading data from - * @len: number of bytes to read - * @buf: buffer where the SFDP data are copied into - * - * Wrap spi_nor_read_sfdp() using a kmalloc'ed bounce buffer as @buf is now not - * guaranteed to be dma-safe. - * - * Return: -ENOMEM if kmalloc() fails, the return code of spi_nor_read_sfdp() - * otherwise. - */ -static int spi_nor_read_sfdp_dma_unsafe(struct spi_nor *nor, u32 addr, - size_t len, void *buf) -{ - void *dma_safe_buf; - int ret; - - dma_safe_buf = kmalloc(len, GFP_KERNEL); - if (!dma_safe_buf) - return -ENOMEM; - - ret = spi_nor_read_sfdp(nor, addr, len, dma_safe_buf); - memcpy(buf, dma_safe_buf, len); - kfree(dma_safe_buf); - - return ret; -} - -/* Fast Read settings. */ - -static void -spi_nor_set_read_settings_from_bfpt(struct spi_nor_read_command *read, - u16 half, - enum spi_nor_protocol proto) -{ - read->num_mode_clocks = (half >> 5) & 0x07; - read->num_wait_states = (half >> 0) & 0x1f; - read->opcode = (half >> 8) & 0xff; - read->proto = proto; -} - -struct sfdp_bfpt_read { - /* The Fast Read x-y-z hardware capability in params->hwcaps.mask. */ - u32 hwcaps; - - /* - * The <supported_bit> bit in <supported_dword> BFPT DWORD tells us - * whether the Fast Read x-y-z command is supported. - */ - u32 supported_dword; - u32 supported_bit; - - /* - * The half-word at offset <setting_shift> in <setting_dword> BFPT DWORD - * encodes the op code, the number of mode clocks and the number of wait - * states to be used by Fast Read x-y-z command. - */ - u32 settings_dword; - u32 settings_shift; - - /* The SPI protocol for this Fast Read x-y-z command. */ - enum spi_nor_protocol proto; -}; - -static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = { - /* Fast Read 1-1-2 */ - { - SNOR_HWCAPS_READ_1_1_2, - BFPT_DWORD(1), BIT(16), /* Supported bit */ - BFPT_DWORD(4), 0, /* Settings */ - SNOR_PROTO_1_1_2, - }, - - /* Fast Read 1-2-2 */ - { - SNOR_HWCAPS_READ_1_2_2, - BFPT_DWORD(1), BIT(20), /* Supported bit */ - BFPT_DWORD(4), 16, /* Settings */ - SNOR_PROTO_1_2_2, - }, - - /* Fast Read 2-2-2 */ - { - SNOR_HWCAPS_READ_2_2_2, - BFPT_DWORD(5), BIT(0), /* Supported bit */ - BFPT_DWORD(6), 16, /* Settings */ - SNOR_PROTO_2_2_2, - }, - - /* Fast Read 1-1-4 */ - { - SNOR_HWCAPS_READ_1_1_4, - BFPT_DWORD(1), BIT(22), /* Supported bit */ - BFPT_DWORD(3), 16, /* Settings */ - SNOR_PROTO_1_1_4, - }, - - /* Fast Read 1-4-4 */ - { - SNOR_HWCAPS_READ_1_4_4, - BFPT_DWORD(1), BIT(21), /* Supported bit */ - BFPT_DWORD(3), 0, /* Settings */ - SNOR_PROTO_1_4_4, - }, - - /* Fast Read 4-4-4 */ - { - SNOR_HWCAPS_READ_4_4_4, - BFPT_DWORD(5), BIT(4), /* Supported bit */ - BFPT_DWORD(7), 16, /* Settings */ - SNOR_PROTO_4_4_4, - }, -}; - -struct sfdp_bfpt_erase { - /* - * The half-word at offset <shift> in DWORD <dwoard> encodes the - * op code and erase sector size to be used by Sector Erase commands. - */ - u32 dword; - u32 shift; -}; - -static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = { - /* Erase Type 1 in DWORD8 bits[15:0] */ - {BFPT_DWORD(8), 0}, - - /* Erase Type 2 in DWORD8 bits[31:16] */ - {BFPT_DWORD(8), 16}, - - /* Erase Type 3 in DWORD9 bits[15:0] */ - {BFPT_DWORD(9), 0}, - - /* Erase Type 4 in DWORD9 bits[31:16] */ - {BFPT_DWORD(9), 16}, -}; - -static int spi_nor_hwcaps_read2cmd(u32 hwcaps); - -static int -spi_nor_post_bfpt_fixups(struct spi_nor *nor, - const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) -{ - if (nor->fixups && nor->fixups->post_bfpt) - return nor->fixups->post_bfpt(nor, bfpt_header, bfpt, params); - - return 0; -} - -/** - * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table. - * @nor: pointer to a 'struct spi_nor' - * @bfpt_header: pointer to the 'struct sfdp_parameter_header' describing - * the Basic Flash Parameter Table length and version - * @params: pointer to the 'struct spi_nor_flash_parameter' to be - * filled - * - * The Basic Flash Parameter Table is the main and only mandatory table as - * defined by the SFDP (JESD216) specification. - * It provides us with the total size (memory density) of the data array and - * the number of address bytes for Fast Read, Page Program and Sector Erase - * commands. - * For Fast READ commands, it also gives the number of mode clock cycles and - * wait states (regrouped in the number of dummy clock cycles) for each - * supported instruction op code. - * For Page Program, the page size is now available since JESD216 rev A, however - * the supported instruction op codes are still not provided. - * For Sector Erase commands, this table stores the supported instruction op - * codes and the associated sector sizes. - * Finally, the Quad Enable Requirements (QER) are also available since JESD216 - * rev A. The QER bits encode the manufacturer dependent procedure to be - * executed to set the Quad Enable (QE) bit in some internal register of the - * Quad SPI memory. Indeed the QE bit, when it exists, must be set before - * sending any Quad SPI command to the memory. Actually, setting the QE bit - * tells the memory to reassign its WP# and HOLD#/RESET# pins to functions IO2 - * and IO3 hence enabling 4 (Quad) I/O lines. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_parse_bfpt(struct spi_nor *nor, - const struct sfdp_parameter_header *bfpt_header, - struct spi_nor_flash_parameter *params) -{ - struct mtd_info *mtd = &nor->mtd; - struct sfdp_bfpt bfpt; - size_t len; - int i, cmd, err; - u32 addr; - u16 half; - - /* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */ - if (bfpt_header->length < BFPT_DWORD_MAX_JESD216) - return -EINVAL; - - /* Read the Basic Flash Parameter Table. */ - len = min_t(size_t, sizeof(bfpt), - bfpt_header->length * sizeof(u32)); - addr = SFDP_PARAM_HEADER_PTP(bfpt_header); - memset(&bfpt, 0, sizeof(bfpt)); - err = spi_nor_read_sfdp_dma_unsafe(nor, addr, len, &bfpt); - if (err < 0) - return err; - - /* Fix endianness of the BFPT DWORDs. */ - for (i = 0; i < BFPT_DWORD_MAX; i++) - bfpt.dwords[i] = le32_to_cpu(bfpt.dwords[i]); - - /* Number of address bytes. */ - switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) { - case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY: - case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4: - nor->addr_width = 3; - nor->addr_mode_nbytes = 3; - break; - - case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY: - nor->addr_width = 4; - nor->addr_mode_nbytes = 4; - break; - - default: - break; - } - - /* Flash Memory Density (in bits). */ - params->size = bfpt.dwords[BFPT_DWORD(2)]; - if (params->size & BIT(31)) { - params->size &= ~BIT(31); - - /* - * Prevent overflows on params->size. Anyway, a NOR of 2^64 - * bits is unlikely to exist so this error probably means - * the BFPT we are reading is corrupted/wrong. - */ - if (params->size > 63) - return -EINVAL; - - params->size = 1ULL << params->size; - } else { - params->size++; - } - params->size >>= 3; /* Convert to bytes. */ - - /* Fast Read settings. */ - for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { - const struct sfdp_bfpt_read *rd = &sfdp_bfpt_reads[i]; - struct spi_nor_read_command *read; - - if (!(bfpt.dwords[rd->supported_dword] & rd->supported_bit)) { - params->hwcaps.mask &= ~rd->hwcaps; - continue; - } - - params->hwcaps.mask |= rd->hwcaps; - cmd = spi_nor_hwcaps_read2cmd(rd->hwcaps); - read = ¶ms->reads[cmd]; - half = bfpt.dwords[rd->settings_dword] >> rd->settings_shift; - spi_nor_set_read_settings_from_bfpt(read, half, rd->proto); - } - - /* Sector Erase settings. */ - for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) { - const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i]; - u32 erasesize; - u8 opcode; - - half = bfpt.dwords[er->dword] >> er->shift; - erasesize = half & 0xff; - - /* erasesize == 0 means this Erase Type is not supported. */ - if (!erasesize) - continue; - - erasesize = 1U << erasesize; - opcode = (half >> 8) & 0xff; -#ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS - if (erasesize == SZ_4K) { - nor->erase_opcode = opcode; - mtd->erasesize = erasesize; - break; - } -#endif - if (!mtd->erasesize || mtd->erasesize < erasesize) { - nor->erase_opcode = opcode; - mtd->erasesize = erasesize; - } - } - - /* Stop here if not JESD216 rev A or later. */ - if (bfpt_header->length == BFPT_DWORD_MAX_JESD216) - return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, - params); - - /* Page size: this field specifies 'N' so the page size = 2^N bytes. */ - params->page_size = bfpt.dwords[BFPT_DWORD(11)]; - params->page_size &= BFPT_DWORD11_PAGE_SIZE_MASK; - params->page_size >>= BFPT_DWORD11_PAGE_SIZE_SHIFT; - params->page_size = 1U << params->page_size; - - /* Quad Enable Requirements. */ - switch (bfpt.dwords[BFPT_DWORD(15)] & BFPT_DWORD15_QER_MASK) { - case BFPT_DWORD15_QER_NONE: - params->quad_enable = NULL; - break; -#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) - case BFPT_DWORD15_QER_SR2_BIT1_BUGGY: - case BFPT_DWORD15_QER_SR2_BIT1_NO_RD: - params->quad_enable = spansion_no_read_cr_quad_enable; - break; -#endif -#if defined(CONFIG_SPI_FLASH_MACRONIX) || defined(CONFIG_SPI_FLASH_ISSI) - case BFPT_DWORD15_QER_SR1_BIT6: - params->quad_enable = macronix_quad_enable; - break; -#endif -#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) - case BFPT_DWORD15_QER_SR2_BIT1: - params->quad_enable = spansion_read_cr_quad_enable; - break; -#endif - default: - dev_dbg(nor->dev, "BFPT QER reserved value used\n"); - break; - } - - /* Soft Reset support. */ - if (bfpt.dwords[BFPT_DWORD(16)] & BFPT_DWORD16_SOFT_RST) - nor->flags |= SNOR_F_SOFT_RESET; - - /* Stop here if JESD216 rev B. */ - if (bfpt_header->length == BFPT_DWORD_MAX_JESD216B) - return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, - params); - - /* 8D-8D-8D command extension. */ - switch (bfpt.dwords[BFPT_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) { - case BFPT_DWORD18_CMD_EXT_REP: - nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; - break; - - case BFPT_DWORD18_CMD_EXT_INV: - nor->cmd_ext_type = SPI_NOR_EXT_INVERT; - break; - - case BFPT_DWORD18_CMD_EXT_RES: - return -EINVAL; - - case BFPT_DWORD18_CMD_EXT_16B: - dev_err(nor->dev, "16-bit opcodes not supported\n"); - return -ENOTSUPP; - } - - return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params); -} - -/** - * spi_nor_parse_microchip_sfdp() - parse the Microchip manufacturer specific - * SFDP table. - * @nor: pointer to a 'struct spi_nor'. - * @param_header: pointer to the SFDP parameter header. - * - * Return: 0 on success, -errno otherwise. - */ -static int -spi_nor_parse_microchip_sfdp(struct spi_nor *nor, - const struct sfdp_parameter_header *param_header) -{ - size_t size; - u32 addr; - int ret; - - size = param_header->length * sizeof(u32); - addr = SFDP_PARAM_HEADER_PTP(param_header); - - nor->manufacturer_sfdp = devm_kmalloc(nor->dev, size, GFP_KERNEL); - if (!nor->manufacturer_sfdp) - return -ENOMEM; - - ret = spi_nor_read_sfdp(nor, addr, size, nor->manufacturer_sfdp); - - return ret; -} - -/** - * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table - * @nor: pointer to a 'struct spi_nor' - * @profile1_header: pointer to the 'struct sfdp_parameter_header' describing - * the 4-Byte Address Instruction Table length and version. - * @params: pointer to the 'struct spi_nor_flash_parameter' to be. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_parse_profile1(struct spi_nor *nor, - const struct sfdp_parameter_header *profile1_header, - struct spi_nor_flash_parameter *params) -{ - u32 *table, opcode, addr; - size_t len; - int ret, i; - u8 dummy; - - len = profile1_header->length * sizeof(*table); - table = kmalloc(len, GFP_KERNEL); - if (!table) - return -ENOMEM; - - addr = SFDP_PARAM_HEADER_PTP(profile1_header); - ret = spi_nor_read_sfdp(nor, addr, len, table); - if (ret) - goto out; - - /* Fix endianness of the table DWORDs. */ - for (i = 0; i < profile1_header->length; i++) - table[i] = le32_to_cpu(table[i]); - - /* Get 8D-8D-8D fast read opcode and dummy cycles. */ - opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, table[0]); - - /* - * We don't know what speed the controller is running at. Find the - * dummy cycles for the fastest frequency the flash can run at to be - * sure we are never short of dummy cycles. A value of 0 means the - * frequency is not supported. - * - * Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let - * flashes set the correct value if needed in their fixup hooks. - */ - dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, table[3]); - if (!dummy) - dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ, table[4]); - if (!dummy) - dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ, table[4]); - if (!dummy) - dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ, table[4]); - if (!dummy) - dummy = PROFILE1_DUMMY_DEFAULT; - - /* Round up to an even value to avoid tripping controllers up. */ - dummy = ROUND_UP_TO(dummy, 2); - - /* Update the fast read settings. */ - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], - 0, dummy, opcode, - SNOR_PROTO_8_8_8_DTR); - - /* - * Set the Read Status Register dummy cycles and dummy address bytes. - */ - if (table[0] & PROFILE1_DWORD1_RDSR_DUMMY) - params->rdsr_dummy = 8; - else - params->rdsr_dummy = 4; - - if (table[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES) - params->rdsr_addr_nbytes = 4; - else - params->rdsr_addr_nbytes = 0; - -out: - kfree(table); - return ret; -} - -/** - * spi_nor_parse_sccr() - Parse the Status, Control and Configuration Register - * Map. - * @nor: pointer to a 'struct spi_nor' - * @sccr_header: pointer to the 'struct sfdp_parameter_header' describing - * the SCCR Map table length and version. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_parse_sccr(struct spi_nor *nor, - const struct sfdp_parameter_header *sccr_header) -{ - u32 *table, addr; - size_t len; - int ret, i; - - len = sccr_header->length * sizeof(*table); - table = kmalloc(len, GFP_KERNEL); - if (!table) - return -ENOMEM; - - addr = SFDP_PARAM_HEADER_PTP(sccr_header); - ret = spi_nor_read_sfdp(nor, addr, len, table); - if (ret) - goto out; - - /* Fix endianness of the table DWORDs. */ - for (i = 0; i < sccr_header->length; i++) - table[i] = le32_to_cpu(table[i]); - - if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[21])) - nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; - -out: - kfree(table); - return ret; -} - -/** - * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. - * @nor: pointer to a 'struct spi_nor' - * @params: pointer to the 'struct spi_nor_flash_parameter' to be - * filled - * - * The Serial Flash Discoverable Parameters are described by the JEDEC JESD216 - * specification. This is a standard which tends to supported by almost all - * (Q)SPI memory manufacturers. Those hard-coded tables allow us to learn at - * runtime the main parameters needed to perform basic SPI flash operations such - * as Fast Read, Page Program or Sector Erase commands. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_parse_sfdp(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - const struct sfdp_parameter_header *param_header, *bfpt_header; - struct sfdp_parameter_header *param_headers = NULL; - struct sfdp_header header; - size_t psize; - int i, err; - - /* Get the SFDP header. */ - err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(header), &header); - if (err < 0) - return err; - - /* Check the SFDP header version. */ - if (le32_to_cpu(header.signature) != SFDP_SIGNATURE || - header.major != SFDP_JESD216_MAJOR) - return -EINVAL; - - /* - * Verify that the first and only mandatory parameter header is a - * Basic Flash Parameter Table header as specified in JESD216. - */ - bfpt_header = &header.bfpt_header; - if (SFDP_PARAM_HEADER_ID(bfpt_header) != SFDP_BFPT_ID || - bfpt_header->major != SFDP_JESD216_MAJOR) - return -EINVAL; - - /* - * Allocate memory then read all parameter headers with a single - * Read SFDP command. These parameter headers will actually be parsed - * twice: a first time to get the latest revision of the basic flash - * parameter table, then a second time to handle the supported optional - * tables. - * Hence we read the parameter headers once for all to reduce the - * processing time. Also we use kmalloc() instead of devm_kmalloc() - * because we don't need to keep these parameter headers: the allocated - * memory is always released with kfree() before exiting this function. - */ - if (header.nph) { - psize = header.nph * sizeof(*param_headers); - - param_headers = kmalloc(psize, GFP_KERNEL); - if (!param_headers) - return -ENOMEM; - - err = spi_nor_read_sfdp(nor, sizeof(header), - psize, param_headers); - if (err < 0) { - dev_err(nor->dev, - "failed to read SFDP parameter headers\n"); - goto exit; - } - } - - /* - * Check other parameter headers to get the latest revision of - * the basic flash parameter table. - */ - for (i = 0; i < header.nph; i++) { - param_header = ¶m_headers[i]; - - if (SFDP_PARAM_HEADER_ID(param_header) == SFDP_BFPT_ID && - param_header->major == SFDP_JESD216_MAJOR && - (param_header->minor > bfpt_header->minor || - (param_header->minor == bfpt_header->minor && - param_header->length > bfpt_header->length))) - bfpt_header = param_header; - } - - err = spi_nor_parse_bfpt(nor, bfpt_header, params); - if (err) - goto exit; - - /* Parse other parameter headers. */ - for (i = 0; i < header.nph; i++) { - param_header = ¶m_headers[i]; - - switch (SFDP_PARAM_HEADER_ID(param_header)) { - case SFDP_SECTOR_MAP_ID: - dev_info(nor->dev, - "non-uniform erase sector maps are not supported yet.\n"); - break; - - case SFDP_SST_ID: - err = spi_nor_parse_microchip_sfdp(nor, param_header); - break; - - case SFDP_PROFILE1_ID: - err = spi_nor_parse_profile1(nor, param_header, params); - break; - - case SFDP_SCCR_MAP_ID: - err = spi_nor_parse_sccr(nor, param_header); - break; - - default: - break; - } - - if (err) { - dev_warn(nor->dev, - "Failed to parse optional parameter table: %04x\n", - SFDP_PARAM_HEADER_ID(param_header)); - /* - * Let's not drop all information we extracted so far - * if optional table parsers fail. In case of failing, - * each optional parser is responsible to roll back to - * the previously known spi_nor data. - */ - err = 0; - } - } - -exit: - kfree(param_headers); - return err; -} -#else -static int spi_nor_parse_sfdp(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - return -EINVAL; -} -#endif /* SPI_FLASH_SFDP_SUPPORT */ - /** * spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings * after SFDP has been parsed. @@ -3273,7 +2404,7 @@ static int spi_nor_hwcaps2cmd(u32 hwcaps, const int table[][2], size_t size) return -EINVAL; } -static int spi_nor_hwcaps_read2cmd(u32 hwcaps) +int spi_nor_hwcaps_read2cmd(u32 hwcaps) { static const int hwcaps_read2cmd[][2] = { { SNOR_HWCAPS_READ, SNOR_CMD_READ }, -- 2.53.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 1/4] mtd: spi-nor: move SFDP logic out of the core @ 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay 0 siblings, 0 replies; 15+ messages in thread From: Takahiro Kuwano via B4 Relay @ 2026-10-16 1:43 UTC (permalink / raw) To: u-boot Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev, Takahiro Kuwano From: Takahiro Kuwano <takahiro.kuwano@infineon.com> Move SFDP parsing functions and definitions to newly introduced sfdp.c/sfdp.h. The new module (sfdp.c) is compiled along with spi-nor-core depending on SPI_FLASH_SFDP_SUPPORT configuration option. The quad_enable hooks and some helper functions are exposed from core and some need to be guarded by CONFIG_SPI_FLASH_TINY to avoid name conflict with local functions in tiny. Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com> --- drivers/mtd/spi/Makefile | 1 + drivers/mtd/spi/sf_internal.h | 50 +++ drivers/mtd/spi/sfdp.c | 711 +++++++++++++++++++++++++++++++++ drivers/mtd/spi/sfdp.h | 152 +++++++ drivers/mtd/spi/spi-nor-core.c | 879 +---------------------------------------- 5 files changed, 919 insertions(+), 874 deletions(-) diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 9a96be11e6d..1828e5fadfe 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -14,6 +14,7 @@ ifeq ($(CONFIG_$(PHASE_)SPI_FLASH_TINY),y) spi-nor-y += spi-nor-tiny.o else spi-nor-y += spi-nor-core.o +spi-nor-$(CONFIG_SPI_FLASH_SFDP_SUPPORT) += sfdp.o endif obj-$(CONFIG_SPI_FLASH) += spi-nor.o diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 8d2249ce354..576617beb70 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -13,9 +13,35 @@ #include <linux/types.h> #include <linux/compiler.h> +#include "sfdp.h" + #define SPI_NOR_MAX_ID_LEN 6 #define SPI_NOR_MAX_ADDR_WIDTH 4 +/** + * struct spi_nor_fixups - SPI NOR fixup hooks + * @post_bfpt: called after the BFPT table has been parsed + * @post_sfdp: called after SFDP has been parsed. Typically used to tweak + * various parameters that could not be extracted by other means + * (i.e. when information provided by the SFDP tables are incomplete + * or wrong). + * @late_init: used to initialize flash parameters that are not declared in the + * JESD216 SFDP standard, or where SFDP tables not defined at all. + * + * Those hooks can be used to tweak the SPI NOR configuration when the SFDP + * table is broken or not available. + */ +struct spi_nor_fixups { + int (*post_bfpt)(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params); + void (*post_sfdp)(struct spi_nor *nor, + struct spi_nor_flash_parameter *params); + void (*late_init)(struct spi_nor *nor, + struct spi_nor_flash_parameter *params); +}; + struct flash_info { #if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) char *name; @@ -93,4 +119,28 @@ static inline void spi_flash_mtd_unregister(struct spi_flash *flash) } #endif +#if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT) +int spi_nor_parse_sfdp(struct spi_nor *nor, + struct spi_nor_flash_parameter *params); +#else +static inline int spi_nor_parse_sfdp(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + return -EINVAL; +} +#endif + +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) +void spi_nor_set_read_settings(struct spi_nor_read_command *read, + u8 num_mode_clocks, + u8 num_wait_states, + u8 opcode, + enum spi_nor_protocol proto); +int spansion_read_cr_quad_enable(struct spi_nor *nor); +int macronix_quad_enable(struct spi_nor *nor); +#endif + +int spi_nor_hwcaps_read2cmd(u32 hwcaps); +int spansion_no_read_cr_quad_enable(struct spi_nor *nor); + #endif /* _SF_INTERNAL_H_ */ diff --git a/drivers/mtd/spi/sfdp.c b/drivers/mtd/spi/sfdp.c new file mode 100644 index 00000000000..fd545796d50 --- /dev/null +++ b/drivers/mtd/spi/sfdp.c @@ -0,0 +1,711 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005, Intec Automation Inc. + * Copyright (C) 2014, Freescale Semiconductor, Inc. + */ + +#include <stddef.h> +#include <string.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <linux/errno.h> +#include <linux/sizes.h> +#include <linux/bitfield.h> +#include <linux/mtd/spi-nor.h> +#include <spi.h> + +#include "sf_internal.h" + +/* + * Serial Flash Discoverable Parameters (SFDP) parsing. + */ + +/** + * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters. + * @nor: pointer to a 'struct spi_nor' + * @addr: offset in the SFDP area to start reading data from + * @len: number of bytes to read + * @buf: buffer where the SFDP data are copied into (dma-safe memory) + * + * Whatever the actual numbers of bytes for address and dummy cycles are + * for (Fast) Read commands, the Read SFDP (5Ah) instruction is always + * followed by a 3-byte address and 8 dummy clock cycles. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, + size_t len, void *buf) +{ + u8 addr_width, read_opcode, read_dummy; + int ret; + + read_opcode = nor->read_opcode; + addr_width = nor->addr_width; + read_dummy = nor->read_dummy; + + nor->read_opcode = SPINOR_OP_RDSFDP; + nor->addr_width = 3; + nor->read_dummy = 8; + + while (len) { + /* Both chips are identical, so should be the SFDP data */ + if (nor->flags & SNOR_F_HAS_PARALLEL) + nor->spi->flags |= SPI_XFER_LOWER; + + ret = nor->read(nor, addr, len, (u8 *)buf); + if (!ret || ret > len) { + ret = -EIO; + goto read_err; + } + if (ret < 0) + goto read_err; + + buf += ret; + addr += ret; + len -= ret; + } + ret = 0; + +read_err: + nor->read_opcode = read_opcode; + nor->addr_width = addr_width; + nor->read_dummy = read_dummy; + + return ret; +} + +/** + * spi_nor_read_sfdp_dma_unsafe() - read Serial Flash Discoverable Parameters. + * @nor: pointer to a 'struct spi_nor' + * @addr: offset in the SFDP area to start reading data from + * @len: number of bytes to read + * @buf: buffer where the SFDP data are copied into + * + * Wrap spi_nor_read_sfdp() using a kmalloc'ed bounce buffer as @buf is now not + * guaranteed to be dma-safe. + * + * Return: -ENOMEM if kmalloc() fails, the return code of spi_nor_read_sfdp() + * otherwise. + */ +static int spi_nor_read_sfdp_dma_unsafe(struct spi_nor *nor, u32 addr, + size_t len, void *buf) +{ + void *dma_safe_buf; + int ret; + + dma_safe_buf = kmalloc(len, GFP_KERNEL); + if (!dma_safe_buf) + return -ENOMEM; + + ret = spi_nor_read_sfdp(nor, addr, len, dma_safe_buf); + memcpy(buf, dma_safe_buf, len); + kfree(dma_safe_buf); + + return ret; +} + +/* Fast Read settings. */ + +static void +spi_nor_set_read_settings_from_bfpt(struct spi_nor_read_command *read, + u16 half, + enum spi_nor_protocol proto) +{ + read->num_mode_clocks = (half >> 5) & 0x07; + read->num_wait_states = (half >> 0) & 0x1f; + read->opcode = (half >> 8) & 0xff; + read->proto = proto; +} + +struct sfdp_bfpt_read { + /* The Fast Read x-y-z hardware capability in params->hwcaps.mask. */ + u32 hwcaps; + + /* + * The <supported_bit> bit in <supported_dword> BFPT DWORD tells us + * whether the Fast Read x-y-z command is supported. + */ + u32 supported_dword; + u32 supported_bit; + + /* + * The half-word at offset <setting_shift> in <setting_dword> BFPT DWORD + * encodes the op code, the number of mode clocks and the number of wait + * states to be used by Fast Read x-y-z command. + */ + u32 settings_dword; + u32 settings_shift; + + /* The SPI protocol for this Fast Read x-y-z command. */ + enum spi_nor_protocol proto; +}; + +static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = { + /* Fast Read 1-1-2 */ + { + SNOR_HWCAPS_READ_1_1_2, + BFPT_DWORD(1), BIT(16), /* Supported bit */ + BFPT_DWORD(4), 0, /* Settings */ + SNOR_PROTO_1_1_2, + }, + + /* Fast Read 1-2-2 */ + { + SNOR_HWCAPS_READ_1_2_2, + BFPT_DWORD(1), BIT(20), /* Supported bit */ + BFPT_DWORD(4), 16, /* Settings */ + SNOR_PROTO_1_2_2, + }, + + /* Fast Read 2-2-2 */ + { + SNOR_HWCAPS_READ_2_2_2, + BFPT_DWORD(5), BIT(0), /* Supported bit */ + BFPT_DWORD(6), 16, /* Settings */ + SNOR_PROTO_2_2_2, + }, + + /* Fast Read 1-1-4 */ + { + SNOR_HWCAPS_READ_1_1_4, + BFPT_DWORD(1), BIT(22), /* Supported bit */ + BFPT_DWORD(3), 16, /* Settings */ + SNOR_PROTO_1_1_4, + }, + + /* Fast Read 1-4-4 */ + { + SNOR_HWCAPS_READ_1_4_4, + BFPT_DWORD(1), BIT(21), /* Supported bit */ + BFPT_DWORD(3), 0, /* Settings */ + SNOR_PROTO_1_4_4, + }, + + /* Fast Read 4-4-4 */ + { + SNOR_HWCAPS_READ_4_4_4, + BFPT_DWORD(5), BIT(4), /* Supported bit */ + BFPT_DWORD(7), 16, /* Settings */ + SNOR_PROTO_4_4_4, + }, +}; + +struct sfdp_bfpt_erase { + /* + * The half-word at offset <shift> in DWORD <dwoard> encodes the + * op code and erase sector size to be used by Sector Erase commands. + */ + u32 dword; + u32 shift; +}; + +static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = { + /* Erase Type 1 in DWORD8 bits[15:0] */ + {BFPT_DWORD(8), 0}, + + /* Erase Type 2 in DWORD8 bits[31:16] */ + {BFPT_DWORD(8), 16}, + + /* Erase Type 3 in DWORD9 bits[15:0] */ + {BFPT_DWORD(9), 0}, + + /* Erase Type 4 in DWORD9 bits[31:16] */ + {BFPT_DWORD(9), 16}, +}; + +static int +spi_nor_post_bfpt_fixups(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + if (nor->fixups && nor->fixups->post_bfpt) + return nor->fixups->post_bfpt(nor, bfpt_header, bfpt, params); + + return 0; +} + +/** + * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table. + * @nor: pointer to a 'struct spi_nor' + * @bfpt_header: pointer to the 'struct sfdp_parameter_header' describing + * the Basic Flash Parameter Table length and version + * @params: pointer to the 'struct spi_nor_flash_parameter' to be + * filled + * + * The Basic Flash Parameter Table is the main and only mandatory table as + * defined by the SFDP (JESD216) specification. + * It provides us with the total size (memory density) of the data array and + * the number of address bytes for Fast Read, Page Program and Sector Erase + * commands. + * For Fast READ commands, it also gives the number of mode clock cycles and + * wait states (regrouped in the number of dummy clock cycles) for each + * supported instruction op code. + * For Page Program, the page size is now available since JESD216 rev A, however + * the supported instruction op codes are still not provided. + * For Sector Erase commands, this table stores the supported instruction op + * codes and the associated sector sizes. + * Finally, the Quad Enable Requirements (QER) are also available since JESD216 + * rev A. The QER bits encode the manufacturer dependent procedure to be + * executed to set the Quad Enable (QE) bit in some internal register of the + * Quad SPI memory. Indeed the QE bit, when it exists, must be set before + * sending any Quad SPI command to the memory. Actually, setting the QE bit + * tells the memory to reassign its WP# and HOLD#/RESET# pins to functions IO2 + * and IO3 hence enabling 4 (Quad) I/O lines. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_bfpt(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + struct spi_nor_flash_parameter *params) +{ + struct mtd_info *mtd = &nor->mtd; + struct sfdp_bfpt bfpt; + size_t len; + int i, cmd, err; + u32 addr; + u16 half; + + /* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */ + if (bfpt_header->length < BFPT_DWORD_MAX_JESD216) + return -EINVAL; + + /* Read the Basic Flash Parameter Table. */ + len = min_t(size_t, sizeof(bfpt), + bfpt_header->length * sizeof(u32)); + addr = SFDP_PARAM_HEADER_PTP(bfpt_header); + memset(&bfpt, 0, sizeof(bfpt)); + err = spi_nor_read_sfdp_dma_unsafe(nor, addr, len, &bfpt); + if (err < 0) + return err; + + /* Fix endianness of the BFPT DWORDs. */ + for (i = 0; i < BFPT_DWORD_MAX; i++) + bfpt.dwords[i] = le32_to_cpu(bfpt.dwords[i]); + + /* Number of address bytes. */ + switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) { + case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY: + case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4: + nor->addr_width = 3; + nor->addr_mode_nbytes = 3; + break; + + case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY: + nor->addr_width = 4; + nor->addr_mode_nbytes = 4; + break; + + default: + break; + } + + /* Flash Memory Density (in bits). */ + params->size = bfpt.dwords[BFPT_DWORD(2)]; + if (params->size & BIT(31)) { + params->size &= ~BIT(31); + + /* + * Prevent overflows on params->size. Anyway, a NOR of 2^64 + * bits is unlikely to exist so this error probably means + * the BFPT we are reading is corrupted/wrong. + */ + if (params->size > 63) + return -EINVAL; + + params->size = 1ULL << params->size; + } else { + params->size++; + } + params->size >>= 3; /* Convert to bytes. */ + + /* Fast Read settings. */ + for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { + const struct sfdp_bfpt_read *rd = &sfdp_bfpt_reads[i]; + struct spi_nor_read_command *read; + + if (!(bfpt.dwords[rd->supported_dword] & rd->supported_bit)) { + params->hwcaps.mask &= ~rd->hwcaps; + continue; + } + + params->hwcaps.mask |= rd->hwcaps; + cmd = spi_nor_hwcaps_read2cmd(rd->hwcaps); + read = ¶ms->reads[cmd]; + half = bfpt.dwords[rd->settings_dword] >> rd->settings_shift; + spi_nor_set_read_settings_from_bfpt(read, half, rd->proto); + } + + /* Sector Erase settings. */ + for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) { + const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i]; + u32 erasesize; + u8 opcode; + + half = bfpt.dwords[er->dword] >> er->shift; + erasesize = half & 0xff; + + /* erasesize == 0 means this Erase Type is not supported. */ + if (!erasesize) + continue; + + erasesize = 1U << erasesize; + opcode = (half >> 8) & 0xff; +#ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS + if (erasesize == SZ_4K) { + nor->erase_opcode = opcode; + mtd->erasesize = erasesize; + break; + } +#endif + if (!mtd->erasesize || mtd->erasesize < erasesize) { + nor->erase_opcode = opcode; + mtd->erasesize = erasesize; + } + } + + /* Stop here if not JESD216 rev A or later. */ + if (bfpt_header->length == BFPT_DWORD_MAX_JESD216) + return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, + params); + + /* Page size: this field specifies 'N' so the page size = 2^N bytes. */ + params->page_size = bfpt.dwords[BFPT_DWORD(11)]; + params->page_size &= BFPT_DWORD11_PAGE_SIZE_MASK; + params->page_size >>= BFPT_DWORD11_PAGE_SIZE_SHIFT; + params->page_size = 1U << params->page_size; + + /* Quad Enable Requirements. */ + switch (bfpt.dwords[BFPT_DWORD(15)] & BFPT_DWORD15_QER_MASK) { + case BFPT_DWORD15_QER_NONE: + params->quad_enable = NULL; + break; +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) + case BFPT_DWORD15_QER_SR2_BIT1_BUGGY: + case BFPT_DWORD15_QER_SR2_BIT1_NO_RD: + params->quad_enable = spansion_no_read_cr_quad_enable; + break; +#endif +#if defined(CONFIG_SPI_FLASH_MACRONIX) || defined(CONFIG_SPI_FLASH_ISSI) + case BFPT_DWORD15_QER_SR1_BIT6: + params->quad_enable = macronix_quad_enable; + break; +#endif +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) + case BFPT_DWORD15_QER_SR2_BIT1: + params->quad_enable = spansion_read_cr_quad_enable; + break; +#endif + default: + dev_dbg(nor->dev, "BFPT QER reserved value used\n"); + break; + } + + /* Soft Reset support. */ + if (bfpt.dwords[BFPT_DWORD(16)] & BFPT_DWORD16_SOFT_RST) + nor->flags |= SNOR_F_SOFT_RESET; + + /* Stop here if JESD216 rev B. */ + if (bfpt_header->length == BFPT_DWORD_MAX_JESD216B) + return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, + params); + + /* 8D-8D-8D command extension. */ + switch (bfpt.dwords[BFPT_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) { + case BFPT_DWORD18_CMD_EXT_REP: + nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; + break; + + case BFPT_DWORD18_CMD_EXT_INV: + nor->cmd_ext_type = SPI_NOR_EXT_INVERT; + break; + + case BFPT_DWORD18_CMD_EXT_RES: + return -EINVAL; + + case BFPT_DWORD18_CMD_EXT_16B: + dev_err(nor->dev, "16-bit opcodes not supported\n"); + return -ENOTSUPP; + } + + return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params); +} + +/** + * spi_nor_parse_microchip_sfdp() - parse the Microchip manufacturer specific + * SFDP table. + * @nor: pointer to a 'struct spi_nor'. + * @param_header: pointer to the SFDP parameter header. + * + * Return: 0 on success, -errno otherwise. + */ +static int +spi_nor_parse_microchip_sfdp(struct spi_nor *nor, + const struct sfdp_parameter_header *param_header) +{ + size_t size; + u32 addr; + int ret; + + size = param_header->length * sizeof(u32); + addr = SFDP_PARAM_HEADER_PTP(param_header); + + nor->manufacturer_sfdp = devm_kmalloc(nor->dev, size, GFP_KERNEL); + if (!nor->manufacturer_sfdp) + return -ENOMEM; + + ret = spi_nor_read_sfdp(nor, addr, size, nor->manufacturer_sfdp); + + return ret; +} + +/** + * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table + * @nor: pointer to a 'struct spi_nor' + * @profile1_header: pointer to the 'struct sfdp_parameter_header' describing + * the 4-Byte Address Instruction Table length and version. + * @params: pointer to the 'struct spi_nor_flash_parameter' to be. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_profile1(struct spi_nor *nor, + const struct sfdp_parameter_header *profile1_header, + struct spi_nor_flash_parameter *params) +{ + u32 *table, opcode, addr; + size_t len; + int ret, i; + u8 dummy; + + len = profile1_header->length * sizeof(*table); + table = kmalloc(len, GFP_KERNEL); + if (!table) + return -ENOMEM; + + addr = SFDP_PARAM_HEADER_PTP(profile1_header); + ret = spi_nor_read_sfdp(nor, addr, len, table); + if (ret) + goto out; + + /* Fix endianness of the table DWORDs. */ + for (i = 0; i < profile1_header->length; i++) + table[i] = le32_to_cpu(table[i]); + + /* Get 8D-8D-8D fast read opcode and dummy cycles. */ + opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, table[0]); + + /* + * We don't know what speed the controller is running at. Find the + * dummy cycles for the fastest frequency the flash can run at to be + * sure we are never short of dummy cycles. A value of 0 means the + * frequency is not supported. + * + * Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let + * flashes set the correct value if needed in their fixup hooks. + */ + dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, table[3]); + if (!dummy) + dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ, table[4]); + if (!dummy) + dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ, table[4]); + if (!dummy) + dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ, table[4]); + if (!dummy) + dummy = PROFILE1_DUMMY_DEFAULT; + + /* Round up to an even value to avoid tripping controllers up. */ + dummy = ROUND_UP_TO(dummy, 2); + + /* Update the fast read settings. */ + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], + 0, dummy, opcode, + SNOR_PROTO_8_8_8_DTR); + + /* + * Set the Read Status Register dummy cycles and dummy address bytes. + */ + if (table[0] & PROFILE1_DWORD1_RDSR_DUMMY) + params->rdsr_dummy = 8; + else + params->rdsr_dummy = 4; + + if (table[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES) + params->rdsr_addr_nbytes = 4; + else + params->rdsr_addr_nbytes = 0; + +out: + kfree(table); + return ret; +} + +/** + * spi_nor_parse_sccr() - Parse the Status, Control and Configuration Register + * Map. + * @nor: pointer to a 'struct spi_nor' + * @sccr_header: pointer to the 'struct sfdp_parameter_header' describing + * the SCCR Map table length and version. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_sccr(struct spi_nor *nor, + const struct sfdp_parameter_header *sccr_header) +{ + u32 *table, addr; + size_t len; + int ret, i; + + len = sccr_header->length * sizeof(*table); + table = kmalloc(len, GFP_KERNEL); + if (!table) + return -ENOMEM; + + addr = SFDP_PARAM_HEADER_PTP(sccr_header); + ret = spi_nor_read_sfdp(nor, addr, len, table); + if (ret) + goto out; + + /* Fix endianness of the table DWORDs. */ + for (i = 0; i < sccr_header->length; i++) + table[i] = le32_to_cpu(table[i]); + + if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[21])) + nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; + +out: + kfree(table); + return ret; +} + +/** + * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. + * @nor: pointer to a 'struct spi_nor' + * @params: pointer to the 'struct spi_nor_flash_parameter' to be + * filled + * + * The Serial Flash Discoverable Parameters are described by the JEDEC JESD216 + * specification. This is a standard which tends to supported by almost all + * (Q)SPI memory manufacturers. Those hard-coded tables allow us to learn at + * runtime the main parameters needed to perform basic SPI flash operations such + * as Fast Read, Page Program or Sector Erase commands. + * + * Return: 0 on success, -errno otherwise. + */ +int spi_nor_parse_sfdp(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + const struct sfdp_parameter_header *param_header, *bfpt_header; + struct sfdp_parameter_header *param_headers = NULL; + struct sfdp_header header; + size_t psize; + int i, err; + + /* Get the SFDP header. */ + err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(header), &header); + if (err < 0) + return err; + + /* Check the SFDP header version. */ + if (le32_to_cpu(header.signature) != SFDP_SIGNATURE || + header.major != SFDP_JESD216_MAJOR) + return -EINVAL; + + /* + * Verify that the first and only mandatory parameter header is a + * Basic Flash Parameter Table header as specified in JESD216. + */ + bfpt_header = &header.bfpt_header; + if (SFDP_PARAM_HEADER_ID(bfpt_header) != SFDP_BFPT_ID || + bfpt_header->major != SFDP_JESD216_MAJOR) + return -EINVAL; + + /* + * Allocate memory then read all parameter headers with a single + * Read SFDP command. These parameter headers will actually be parsed + * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supported optional + * tables. + * Hence we read the parameter headers once for all to reduce the + * processing time. Also we use kmalloc() instead of devm_kmalloc() + * because we don't need to keep these parameter headers: the allocated + * memory is always released with kfree() before exiting this function. + */ + if (header.nph) { + psize = header.nph * sizeof(*param_headers); + + param_headers = kmalloc(psize, GFP_KERNEL); + if (!param_headers) + return -ENOMEM; + + err = spi_nor_read_sfdp(nor, sizeof(header), + psize, param_headers); + if (err < 0) { + dev_err(nor->dev, + "failed to read SFDP parameter headers\n"); + goto exit; + } + } + + /* + * Check other parameter headers to get the latest revision of + * the basic flash parameter table. + */ + for (i = 0; i < header.nph; i++) { + param_header = ¶m_headers[i]; + + if (SFDP_PARAM_HEADER_ID(param_header) == SFDP_BFPT_ID && + param_header->major == SFDP_JESD216_MAJOR && + (param_header->minor > bfpt_header->minor || + (param_header->minor == bfpt_header->minor && + param_header->length > bfpt_header->length))) + bfpt_header = param_header; + } + + err = spi_nor_parse_bfpt(nor, bfpt_header, params); + if (err) + goto exit; + + /* Parse other parameter headers. */ + for (i = 0; i < header.nph; i++) { + param_header = ¶m_headers[i]; + + switch (SFDP_PARAM_HEADER_ID(param_header)) { + case SFDP_SECTOR_MAP_ID: + dev_info(nor->dev, + "non-uniform erase sector maps are not supported yet.\n"); + break; + + case SFDP_SST_ID: + err = spi_nor_parse_microchip_sfdp(nor, param_header); + break; + + case SFDP_PROFILE1_ID: + err = spi_nor_parse_profile1(nor, param_header, params); + break; + + case SFDP_SCCR_MAP_ID: + err = spi_nor_parse_sccr(nor, param_header); + break; + + default: + break; + } + + if (err) { + dev_warn(nor->dev, + "Failed to parse optional parameter table: %04x\n", + SFDP_PARAM_HEADER_ID(param_header)); + /* + * Let's not drop all information we extracted so far + * if optional table parsers fail. In case of failing, + * each optional parser is responsible to roll back to + * the previously known spi_nor data. + */ + err = 0; + } + } + +exit: + kfree(param_headers); + return err; +} diff --git a/drivers/mtd/spi/sfdp.h b/drivers/mtd/spi/sfdp.h new file mode 100644 index 00000000000..f85ac71490b --- /dev/null +++ b/drivers/mtd/spi/sfdp.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005, Intec Automation Inc. + * Copyright (C) 2014, Freescale Semiconductor, Inc. + */ + +#ifndef _SPI_NOR_SFDP_H_ +#define _SPI_NOR_SFDP_H_ + +#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) + +struct sfdp_parameter_header { + u8 id_lsb; + u8 minor; + u8 major; + u8 length; /* in double words */ + u8 parameter_table_pointer[3]; /* byte address */ + u8 id_msb; +}; + +#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb) +#define SFDP_PARAM_HEADER_PTP(p) \ + (((p)->parameter_table_pointer[2] << 16) | \ + ((p)->parameter_table_pointer[1] << 8) | \ + ((p)->parameter_table_pointer[0] << 0)) + +#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ +#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ +#define SFDP_SST_ID 0x01bf /* Manufacturer specific Table */ +#define SFDP_PROFILE1_ID 0xff05 /* xSPI Profile 1.0 Table */ +#define SFDP_SCCR_MAP_ID 0xff87 /* + * Status, Control and Configuration + * Register Map. + */ + +#define SFDP_SIGNATURE 0x50444653U +#define SFDP_JESD216_MAJOR 1 +#define SFDP_JESD216_MINOR 0 +#define SFDP_JESD216A_MINOR 5 +#define SFDP_JESD216B_MINOR 6 + +struct sfdp_header { + u32 signature; /* Ox50444653U <=> "SFDP" */ + u8 minor; + u8 major; + u8 nph; /* 0-base number of parameter headers */ + u8 unused; + + /* Basic Flash Parameter Table. */ + struct sfdp_parameter_header bfpt_header; +}; + +/* Basic Flash Parameter Table */ + +/* + * JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs. + * They are indexed from 1 but C arrays are indexed from 0. + */ +#define BFPT_DWORD(i) ((i) - 1) +#define BFPT_DWORD_MAX 20 + +/* The first version of JESB216 defined only 9 DWORDs. */ +#define BFPT_DWORD_MAX_JESD216 9 +#define BFPT_DWORD_MAX_JESD216B 16 + +/* 1st DWORD. */ +#define BFPT_DWORD1_FAST_READ_1_1_2 BIT(16) +#define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17) +#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY (0x0UL << 17) +#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (0x1UL << 17) +#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY (0x2UL << 17) +#define BFPT_DWORD1_DTR BIT(19) +#define BFPT_DWORD1_FAST_READ_1_2_2 BIT(20) +#define BFPT_DWORD1_FAST_READ_1_4_4 BIT(21) +#define BFPT_DWORD1_FAST_READ_1_1_4 BIT(22) + +/* 5th DWORD. */ +#define BFPT_DWORD5_FAST_READ_2_2_2 BIT(0) +#define BFPT_DWORD5_FAST_READ_4_4_4 BIT(4) + +/* 11th DWORD. */ +#define BFPT_DWORD11_PAGE_SIZE_SHIFT 4 +#define BFPT_DWORD11_PAGE_SIZE_MASK GENMASK(7, 4) + +/* 15th DWORD. */ + +/* + * (from JESD216 rev B) + * Quad Enable Requirements (QER): + * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4 + * reads based on instruction. DQ3/HOLD# functions are hold during + * instruction phase. + * - 001b: QE is bit 1 of status register 2. It is set via Write Status with + * two data bytes where bit 1 of the second byte is one. + * [...] + * Writing only one byte to the status register has the side-effect of + * clearing status register 2, including the QE bit. The 100b code is + * used if writing one byte to the status register does not modify + * status register 2. + * - 010b: QE is bit 6 of status register 1. It is set via Write Status with + * one data byte where bit 6 is one. + * [...] + * - 011b: QE is bit 7 of status register 2. It is set via Write status + * register 2 instruction 3Eh with one data byte where bit 7 is one. + * [...] + * The status register 2 is read using instruction 3Fh. + * - 100b: QE is bit 1 of status register 2. It is set via Write Status with + * two data bytes where bit 1 of the second byte is one. + * [...] + * In contrast to the 001b code, writing one byte to the status + * register does not modify status register 2. + * - 101b: QE is bit 1 of status register 2. Status register 1 is read using + * Read Status instruction 05h. Status register2 is read using + * instruction 35h. QE is set via Writ Status instruction 01h with + * two data bytes where bit 1 of the second byte is one. + * [...] + */ +#define BFPT_DWORD15_QER_MASK GENMASK(22, 20) +#define BFPT_DWORD15_QER_NONE (0x0UL << 20) /* Micron */ +#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) +#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20) /* Macronix */ +#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20) +#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20) +#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */ + +#define BFPT_DWORD16_SOFT_RST BIT(12) +#define BFPT_DWORD16_EX4B_PWRCYC BIT(21) + +#define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29) +#define BFPT_DWORD18_CMD_EXT_REP (0x0UL << 29) /* Repeat */ +#define BFPT_DWORD18_CMD_EXT_INV (0x1UL << 29) /* Invert */ +#define BFPT_DWORD18_CMD_EXT_RES (0x2UL << 29) /* Reserved */ +#define BFPT_DWORD18_CMD_EXT_16B (0x3UL << 29) /* 16-bit opcode */ + +/* xSPI Profile 1.0 table (from JESD216D.01). */ +#define PROFILE1_DWORD1_RD_FAST_CMD GENMASK(15, 8) +#define PROFILE1_DWORD1_RDSR_DUMMY BIT(28) +#define PROFILE1_DWORD1_RDSR_ADDR_BYTES BIT(29) +#define PROFILE1_DWORD4_DUMMY_200MHZ GENMASK(11, 7) +#define PROFILE1_DWORD5_DUMMY_166MHZ GENMASK(31, 27) +#define PROFILE1_DWORD5_DUMMY_133MHZ GENMASK(21, 17) +#define PROFILE1_DWORD5_DUMMY_100MHZ GENMASK(11, 7) +#define PROFILE1_DUMMY_DEFAULT 20 + +/* Status, Control and Configuration Register Map(SCCR) */ +#define SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE BIT(31) + +struct sfdp_bfpt { + u32 dwords[BFPT_DWORD_MAX]; +}; + +#endif /* _SPI_NOR_SFDP_H_ */ diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 937d79af64e..b99a1a45d8f 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -50,171 +50,6 @@ */ #define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ) -#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) - -struct sfdp_parameter_header { - u8 id_lsb; - u8 minor; - u8 major; - u8 length; /* in double words */ - u8 parameter_table_pointer[3]; /* byte address */ - u8 id_msb; -}; - -#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb) -#define SFDP_PARAM_HEADER_PTP(p) \ - (((p)->parameter_table_pointer[2] << 16) | \ - ((p)->parameter_table_pointer[1] << 8) | \ - ((p)->parameter_table_pointer[0] << 0)) - -#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ -#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ -#define SFDP_SST_ID 0x01bf /* Manufacturer specific Table */ -#define SFDP_PROFILE1_ID 0xff05 /* xSPI Profile 1.0 Table */ -#define SFDP_SCCR_MAP_ID 0xff87 /* - * Status, Control and Configuration - * Register Map. - */ - -#define SFDP_SIGNATURE 0x50444653U -#define SFDP_JESD216_MAJOR 1 -#define SFDP_JESD216_MINOR 0 -#define SFDP_JESD216A_MINOR 5 -#define SFDP_JESD216B_MINOR 6 - -struct sfdp_header { - u32 signature; /* Ox50444653U <=> "SFDP" */ - u8 minor; - u8 major; - u8 nph; /* 0-base number of parameter headers */ - u8 unused; - - /* Basic Flash Parameter Table. */ - struct sfdp_parameter_header bfpt_header; -}; - -/* Basic Flash Parameter Table */ - -/* - * JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs. - * They are indexed from 1 but C arrays are indexed from 0. - */ -#define BFPT_DWORD(i) ((i) - 1) -#define BFPT_DWORD_MAX 20 - -/* The first version of JESB216 defined only 9 DWORDs. */ -#define BFPT_DWORD_MAX_JESD216 9 -#define BFPT_DWORD_MAX_JESD216B 16 - -/* 1st DWORD. */ -#define BFPT_DWORD1_FAST_READ_1_1_2 BIT(16) -#define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17) -#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY (0x0UL << 17) -#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (0x1UL << 17) -#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY (0x2UL << 17) -#define BFPT_DWORD1_DTR BIT(19) -#define BFPT_DWORD1_FAST_READ_1_2_2 BIT(20) -#define BFPT_DWORD1_FAST_READ_1_4_4 BIT(21) -#define BFPT_DWORD1_FAST_READ_1_1_4 BIT(22) - -/* 5th DWORD. */ -#define BFPT_DWORD5_FAST_READ_2_2_2 BIT(0) -#define BFPT_DWORD5_FAST_READ_4_4_4 BIT(4) - -/* 11th DWORD. */ -#define BFPT_DWORD11_PAGE_SIZE_SHIFT 4 -#define BFPT_DWORD11_PAGE_SIZE_MASK GENMASK(7, 4) - -/* 15th DWORD. */ - -/* - * (from JESD216 rev B) - * Quad Enable Requirements (QER): - * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4 - * reads based on instruction. DQ3/HOLD# functions are hold during - * instruction phase. - * - 001b: QE is bit 1 of status register 2. It is set via Write Status with - * two data bytes where bit 1 of the second byte is one. - * [...] - * Writing only one byte to the status register has the side-effect of - * clearing status register 2, including the QE bit. The 100b code is - * used if writing one byte to the status register does not modify - * status register 2. - * - 010b: QE is bit 6 of status register 1. It is set via Write Status with - * one data byte where bit 6 is one. - * [...] - * - 011b: QE is bit 7 of status register 2. It is set via Write status - * register 2 instruction 3Eh with one data byte where bit 7 is one. - * [...] - * The status register 2 is read using instruction 3Fh. - * - 100b: QE is bit 1 of status register 2. It is set via Write Status with - * two data bytes where bit 1 of the second byte is one. - * [...] - * In contrast to the 001b code, writing one byte to the status - * register does not modify status register 2. - * - 101b: QE is bit 1 of status register 2. Status register 1 is read using - * Read Status instruction 05h. Status register2 is read using - * instruction 35h. QE is set via Writ Status instruction 01h with - * two data bytes where bit 1 of the second byte is one. - * [...] - */ -#define BFPT_DWORD15_QER_MASK GENMASK(22, 20) -#define BFPT_DWORD15_QER_NONE (0x0UL << 20) /* Micron */ -#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) -#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20) /* Macronix */ -#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20) -#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20) -#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */ - -#define BFPT_DWORD16_SOFT_RST BIT(12) -#define BFPT_DWORD16_EX4B_PWRCYC BIT(21) - -#define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29) -#define BFPT_DWORD18_CMD_EXT_REP (0x0UL << 29) /* Repeat */ -#define BFPT_DWORD18_CMD_EXT_INV (0x1UL << 29) /* Invert */ -#define BFPT_DWORD18_CMD_EXT_RES (0x2UL << 29) /* Reserved */ -#define BFPT_DWORD18_CMD_EXT_16B (0x3UL << 29) /* 16-bit opcode */ - -/* xSPI Profile 1.0 table (from JESD216D.01). */ -#define PROFILE1_DWORD1_RD_FAST_CMD GENMASK(15, 8) -#define PROFILE1_DWORD1_RDSR_DUMMY BIT(28) -#define PROFILE1_DWORD1_RDSR_ADDR_BYTES BIT(29) -#define PROFILE1_DWORD4_DUMMY_200MHZ GENMASK(11, 7) -#define PROFILE1_DWORD5_DUMMY_166MHZ GENMASK(31, 27) -#define PROFILE1_DWORD5_DUMMY_133MHZ GENMASK(21, 17) -#define PROFILE1_DWORD5_DUMMY_100MHZ GENMASK(11, 7) -#define PROFILE1_DUMMY_DEFAULT 20 - -/* Status, Control and Configuration Register Map(SCCR) */ -#define SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE BIT(31) - -struct sfdp_bfpt { - u32 dwords[BFPT_DWORD_MAX]; -}; - -/** - * struct spi_nor_fixups - SPI NOR fixup hooks - * @post_bfpt: called after the BFPT table has been parsed - * @post_sfdp: called after SFDP has been parsed. Typically used to tweak - * various parameters that could not be extracted by other means - * (i.e. when information provided by the SFDP tables are incomplete - * or wrong). - * @late_init: used to initialize flash parameters that are not declared in the - * JESD216 SFDP standard, or where SFDP tables not defined at all. - * - * Those hooks can be used to tweak the SPI NOR configuration when the SFDP - * table is broken or not available. - */ -struct spi_nor_fixups { - int (*post_bfpt)(struct spi_nor *nor, - const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params); - void (*post_sfdp)(struct spi_nor *nor, - struct spi_nor_flash_parameter *params); - void (*late_init)(struct spi_nor *nor, - struct spi_nor_flash_parameter *params); -}; #define SPI_NOR_SRST_SLEEP_LEN 200 @@ -2121,7 +1956,7 @@ write_err: * * Return: 0 on success, -errno otherwise. */ -static int macronix_quad_enable(struct spi_nor *nor) +int macronix_quad_enable(struct spi_nor *nor) { int ret, val; @@ -2247,7 +2082,7 @@ static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr) * * Return: 0 on success, -errno otherwise. */ -static int spansion_read_cr_quad_enable(struct spi_nor *nor) +int spansion_read_cr_quad_enable(struct spi_nor *nor) { u8 sr_cr[2]; int ret; @@ -2301,7 +2136,7 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor) * * Return: 0 on success, -errno otherwise. */ -static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) +int spansion_no_read_cr_quad_enable(struct spi_nor *nor) { u8 sr_cr[2]; int ret; @@ -2321,7 +2156,7 @@ static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) #endif /* CONFIG_SPI_FLASH_SFDP_SUPPORT */ #endif /* CONFIG_SPI_FLASH_SPANSION */ -static void +void spi_nor_set_read_settings(struct spi_nor_read_command *read, u8 num_mode_clocks, u8 num_wait_states, @@ -2343,710 +2178,6 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, pp->proto = proto; } -#if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT) -/* - * Serial Flash Discoverable Parameters (SFDP) parsing. - */ - -/** - * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters. - * @nor: pointer to a 'struct spi_nor' - * @addr: offset in the SFDP area to start reading data from - * @len: number of bytes to read - * @buf: buffer where the SFDP data are copied into (dma-safe memory) - * - * Whatever the actual numbers of bytes for address and dummy cycles are - * for (Fast) Read commands, the Read SFDP (5Ah) instruction is always - * followed by a 3-byte address and 8 dummy clock cycles. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, - size_t len, void *buf) -{ - u8 addr_width, read_opcode, read_dummy; - int ret; - - read_opcode = nor->read_opcode; - addr_width = nor->addr_width; - read_dummy = nor->read_dummy; - - nor->read_opcode = SPINOR_OP_RDSFDP; - nor->addr_width = 3; - nor->read_dummy = 8; - - while (len) { - /* Both chips are identical, so should be the SFDP data */ - if (nor->flags & SNOR_F_HAS_PARALLEL) - nor->spi->flags |= SPI_XFER_LOWER; - - ret = nor->read(nor, addr, len, (u8 *)buf); - if (!ret || ret > len) { - ret = -EIO; - goto read_err; - } - if (ret < 0) - goto read_err; - - buf += ret; - addr += ret; - len -= ret; - } - ret = 0; - -read_err: - nor->read_opcode = read_opcode; - nor->addr_width = addr_width; - nor->read_dummy = read_dummy; - - return ret; -} - -/** - * spi_nor_read_sfdp_dma_unsafe() - read Serial Flash Discoverable Parameters. - * @nor: pointer to a 'struct spi_nor' - * @addr: offset in the SFDP area to start reading data from - * @len: number of bytes to read - * @buf: buffer where the SFDP data are copied into - * - * Wrap spi_nor_read_sfdp() using a kmalloc'ed bounce buffer as @buf is now not - * guaranteed to be dma-safe. - * - * Return: -ENOMEM if kmalloc() fails, the return code of spi_nor_read_sfdp() - * otherwise. - */ -static int spi_nor_read_sfdp_dma_unsafe(struct spi_nor *nor, u32 addr, - size_t len, void *buf) -{ - void *dma_safe_buf; - int ret; - - dma_safe_buf = kmalloc(len, GFP_KERNEL); - if (!dma_safe_buf) - return -ENOMEM; - - ret = spi_nor_read_sfdp(nor, addr, len, dma_safe_buf); - memcpy(buf, dma_safe_buf, len); - kfree(dma_safe_buf); - - return ret; -} - -/* Fast Read settings. */ - -static void -spi_nor_set_read_settings_from_bfpt(struct spi_nor_read_command *read, - u16 half, - enum spi_nor_protocol proto) -{ - read->num_mode_clocks = (half >> 5) & 0x07; - read->num_wait_states = (half >> 0) & 0x1f; - read->opcode = (half >> 8) & 0xff; - read->proto = proto; -} - -struct sfdp_bfpt_read { - /* The Fast Read x-y-z hardware capability in params->hwcaps.mask. */ - u32 hwcaps; - - /* - * The <supported_bit> bit in <supported_dword> BFPT DWORD tells us - * whether the Fast Read x-y-z command is supported. - */ - u32 supported_dword; - u32 supported_bit; - - /* - * The half-word at offset <setting_shift> in <setting_dword> BFPT DWORD - * encodes the op code, the number of mode clocks and the number of wait - * states to be used by Fast Read x-y-z command. - */ - u32 settings_dword; - u32 settings_shift; - - /* The SPI protocol for this Fast Read x-y-z command. */ - enum spi_nor_protocol proto; -}; - -static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = { - /* Fast Read 1-1-2 */ - { - SNOR_HWCAPS_READ_1_1_2, - BFPT_DWORD(1), BIT(16), /* Supported bit */ - BFPT_DWORD(4), 0, /* Settings */ - SNOR_PROTO_1_1_2, - }, - - /* Fast Read 1-2-2 */ - { - SNOR_HWCAPS_READ_1_2_2, - BFPT_DWORD(1), BIT(20), /* Supported bit */ - BFPT_DWORD(4), 16, /* Settings */ - SNOR_PROTO_1_2_2, - }, - - /* Fast Read 2-2-2 */ - { - SNOR_HWCAPS_READ_2_2_2, - BFPT_DWORD(5), BIT(0), /* Supported bit */ - BFPT_DWORD(6), 16, /* Settings */ - SNOR_PROTO_2_2_2, - }, - - /* Fast Read 1-1-4 */ - { - SNOR_HWCAPS_READ_1_1_4, - BFPT_DWORD(1), BIT(22), /* Supported bit */ - BFPT_DWORD(3), 16, /* Settings */ - SNOR_PROTO_1_1_4, - }, - - /* Fast Read 1-4-4 */ - { - SNOR_HWCAPS_READ_1_4_4, - BFPT_DWORD(1), BIT(21), /* Supported bit */ - BFPT_DWORD(3), 0, /* Settings */ - SNOR_PROTO_1_4_4, - }, - - /* Fast Read 4-4-4 */ - { - SNOR_HWCAPS_READ_4_4_4, - BFPT_DWORD(5), BIT(4), /* Supported bit */ - BFPT_DWORD(7), 16, /* Settings */ - SNOR_PROTO_4_4_4, - }, -}; - -struct sfdp_bfpt_erase { - /* - * The half-word at offset <shift> in DWORD <dwoard> encodes the - * op code and erase sector size to be used by Sector Erase commands. - */ - u32 dword; - u32 shift; -}; - -static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = { - /* Erase Type 1 in DWORD8 bits[15:0] */ - {BFPT_DWORD(8), 0}, - - /* Erase Type 2 in DWORD8 bits[31:16] */ - {BFPT_DWORD(8), 16}, - - /* Erase Type 3 in DWORD9 bits[15:0] */ - {BFPT_DWORD(9), 0}, - - /* Erase Type 4 in DWORD9 bits[31:16] */ - {BFPT_DWORD(9), 16}, -}; - -static int spi_nor_hwcaps_read2cmd(u32 hwcaps); - -static int -spi_nor_post_bfpt_fixups(struct spi_nor *nor, - const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) -{ - if (nor->fixups && nor->fixups->post_bfpt) - return nor->fixups->post_bfpt(nor, bfpt_header, bfpt, params); - - return 0; -} - -/** - * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table. - * @nor: pointer to a 'struct spi_nor' - * @bfpt_header: pointer to the 'struct sfdp_parameter_header' describing - * the Basic Flash Parameter Table length and version - * @params: pointer to the 'struct spi_nor_flash_parameter' to be - * filled - * - * The Basic Flash Parameter Table is the main and only mandatory table as - * defined by the SFDP (JESD216) specification. - * It provides us with the total size (memory density) of the data array and - * the number of address bytes for Fast Read, Page Program and Sector Erase - * commands. - * For Fast READ commands, it also gives the number of mode clock cycles and - * wait states (regrouped in the number of dummy clock cycles) for each - * supported instruction op code. - * For Page Program, the page size is now available since JESD216 rev A, however - * the supported instruction op codes are still not provided. - * For Sector Erase commands, this table stores the supported instruction op - * codes and the associated sector sizes. - * Finally, the Quad Enable Requirements (QER) are also available since JESD216 - * rev A. The QER bits encode the manufacturer dependent procedure to be - * executed to set the Quad Enable (QE) bit in some internal register of the - * Quad SPI memory. Indeed the QE bit, when it exists, must be set before - * sending any Quad SPI command to the memory. Actually, setting the QE bit - * tells the memory to reassign its WP# and HOLD#/RESET# pins to functions IO2 - * and IO3 hence enabling 4 (Quad) I/O lines. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_parse_bfpt(struct spi_nor *nor, - const struct sfdp_parameter_header *bfpt_header, - struct spi_nor_flash_parameter *params) -{ - struct mtd_info *mtd = &nor->mtd; - struct sfdp_bfpt bfpt; - size_t len; - int i, cmd, err; - u32 addr; - u16 half; - - /* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */ - if (bfpt_header->length < BFPT_DWORD_MAX_JESD216) - return -EINVAL; - - /* Read the Basic Flash Parameter Table. */ - len = min_t(size_t, sizeof(bfpt), - bfpt_header->length * sizeof(u32)); - addr = SFDP_PARAM_HEADER_PTP(bfpt_header); - memset(&bfpt, 0, sizeof(bfpt)); - err = spi_nor_read_sfdp_dma_unsafe(nor, addr, len, &bfpt); - if (err < 0) - return err; - - /* Fix endianness of the BFPT DWORDs. */ - for (i = 0; i < BFPT_DWORD_MAX; i++) - bfpt.dwords[i] = le32_to_cpu(bfpt.dwords[i]); - - /* Number of address bytes. */ - switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) { - case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY: - case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4: - nor->addr_width = 3; - nor->addr_mode_nbytes = 3; - break; - - case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY: - nor->addr_width = 4; - nor->addr_mode_nbytes = 4; - break; - - default: - break; - } - - /* Flash Memory Density (in bits). */ - params->size = bfpt.dwords[BFPT_DWORD(2)]; - if (params->size & BIT(31)) { - params->size &= ~BIT(31); - - /* - * Prevent overflows on params->size. Anyway, a NOR of 2^64 - * bits is unlikely to exist so this error probably means - * the BFPT we are reading is corrupted/wrong. - */ - if (params->size > 63) - return -EINVAL; - - params->size = 1ULL << params->size; - } else { - params->size++; - } - params->size >>= 3; /* Convert to bytes. */ - - /* Fast Read settings. */ - for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { - const struct sfdp_bfpt_read *rd = &sfdp_bfpt_reads[i]; - struct spi_nor_read_command *read; - - if (!(bfpt.dwords[rd->supported_dword] & rd->supported_bit)) { - params->hwcaps.mask &= ~rd->hwcaps; - continue; - } - - params->hwcaps.mask |= rd->hwcaps; - cmd = spi_nor_hwcaps_read2cmd(rd->hwcaps); - read = ¶ms->reads[cmd]; - half = bfpt.dwords[rd->settings_dword] >> rd->settings_shift; - spi_nor_set_read_settings_from_bfpt(read, half, rd->proto); - } - - /* Sector Erase settings. */ - for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) { - const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i]; - u32 erasesize; - u8 opcode; - - half = bfpt.dwords[er->dword] >> er->shift; - erasesize = half & 0xff; - - /* erasesize == 0 means this Erase Type is not supported. */ - if (!erasesize) - continue; - - erasesize = 1U << erasesize; - opcode = (half >> 8) & 0xff; -#ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS - if (erasesize == SZ_4K) { - nor->erase_opcode = opcode; - mtd->erasesize = erasesize; - break; - } -#endif - if (!mtd->erasesize || mtd->erasesize < erasesize) { - nor->erase_opcode = opcode; - mtd->erasesize = erasesize; - } - } - - /* Stop here if not JESD216 rev A or later. */ - if (bfpt_header->length == BFPT_DWORD_MAX_JESD216) - return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, - params); - - /* Page size: this field specifies 'N' so the page size = 2^N bytes. */ - params->page_size = bfpt.dwords[BFPT_DWORD(11)]; - params->page_size &= BFPT_DWORD11_PAGE_SIZE_MASK; - params->page_size >>= BFPT_DWORD11_PAGE_SIZE_SHIFT; - params->page_size = 1U << params->page_size; - - /* Quad Enable Requirements. */ - switch (bfpt.dwords[BFPT_DWORD(15)] & BFPT_DWORD15_QER_MASK) { - case BFPT_DWORD15_QER_NONE: - params->quad_enable = NULL; - break; -#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) - case BFPT_DWORD15_QER_SR2_BIT1_BUGGY: - case BFPT_DWORD15_QER_SR2_BIT1_NO_RD: - params->quad_enable = spansion_no_read_cr_quad_enable; - break; -#endif -#if defined(CONFIG_SPI_FLASH_MACRONIX) || defined(CONFIG_SPI_FLASH_ISSI) - case BFPT_DWORD15_QER_SR1_BIT6: - params->quad_enable = macronix_quad_enable; - break; -#endif -#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) - case BFPT_DWORD15_QER_SR2_BIT1: - params->quad_enable = spansion_read_cr_quad_enable; - break; -#endif - default: - dev_dbg(nor->dev, "BFPT QER reserved value used\n"); - break; - } - - /* Soft Reset support. */ - if (bfpt.dwords[BFPT_DWORD(16)] & BFPT_DWORD16_SOFT_RST) - nor->flags |= SNOR_F_SOFT_RESET; - - /* Stop here if JESD216 rev B. */ - if (bfpt_header->length == BFPT_DWORD_MAX_JESD216B) - return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, - params); - - /* 8D-8D-8D command extension. */ - switch (bfpt.dwords[BFPT_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) { - case BFPT_DWORD18_CMD_EXT_REP: - nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; - break; - - case BFPT_DWORD18_CMD_EXT_INV: - nor->cmd_ext_type = SPI_NOR_EXT_INVERT; - break; - - case BFPT_DWORD18_CMD_EXT_RES: - return -EINVAL; - - case BFPT_DWORD18_CMD_EXT_16B: - dev_err(nor->dev, "16-bit opcodes not supported\n"); - return -ENOTSUPP; - } - - return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params); -} - -/** - * spi_nor_parse_microchip_sfdp() - parse the Microchip manufacturer specific - * SFDP table. - * @nor: pointer to a 'struct spi_nor'. - * @param_header: pointer to the SFDP parameter header. - * - * Return: 0 on success, -errno otherwise. - */ -static int -spi_nor_parse_microchip_sfdp(struct spi_nor *nor, - const struct sfdp_parameter_header *param_header) -{ - size_t size; - u32 addr; - int ret; - - size = param_header->length * sizeof(u32); - addr = SFDP_PARAM_HEADER_PTP(param_header); - - nor->manufacturer_sfdp = devm_kmalloc(nor->dev, size, GFP_KERNEL); - if (!nor->manufacturer_sfdp) - return -ENOMEM; - - ret = spi_nor_read_sfdp(nor, addr, size, nor->manufacturer_sfdp); - - return ret; -} - -/** - * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table - * @nor: pointer to a 'struct spi_nor' - * @profile1_header: pointer to the 'struct sfdp_parameter_header' describing - * the 4-Byte Address Instruction Table length and version. - * @params: pointer to the 'struct spi_nor_flash_parameter' to be. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_parse_profile1(struct spi_nor *nor, - const struct sfdp_parameter_header *profile1_header, - struct spi_nor_flash_parameter *params) -{ - u32 *table, opcode, addr; - size_t len; - int ret, i; - u8 dummy; - - len = profile1_header->length * sizeof(*table); - table = kmalloc(len, GFP_KERNEL); - if (!table) - return -ENOMEM; - - addr = SFDP_PARAM_HEADER_PTP(profile1_header); - ret = spi_nor_read_sfdp(nor, addr, len, table); - if (ret) - goto out; - - /* Fix endianness of the table DWORDs. */ - for (i = 0; i < profile1_header->length; i++) - table[i] = le32_to_cpu(table[i]); - - /* Get 8D-8D-8D fast read opcode and dummy cycles. */ - opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, table[0]); - - /* - * We don't know what speed the controller is running at. Find the - * dummy cycles for the fastest frequency the flash can run at to be - * sure we are never short of dummy cycles. A value of 0 means the - * frequency is not supported. - * - * Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let - * flashes set the correct value if needed in their fixup hooks. - */ - dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, table[3]); - if (!dummy) - dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ, table[4]); - if (!dummy) - dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ, table[4]); - if (!dummy) - dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ, table[4]); - if (!dummy) - dummy = PROFILE1_DUMMY_DEFAULT; - - /* Round up to an even value to avoid tripping controllers up. */ - dummy = ROUND_UP_TO(dummy, 2); - - /* Update the fast read settings. */ - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], - 0, dummy, opcode, - SNOR_PROTO_8_8_8_DTR); - - /* - * Set the Read Status Register dummy cycles and dummy address bytes. - */ - if (table[0] & PROFILE1_DWORD1_RDSR_DUMMY) - params->rdsr_dummy = 8; - else - params->rdsr_dummy = 4; - - if (table[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES) - params->rdsr_addr_nbytes = 4; - else - params->rdsr_addr_nbytes = 0; - -out: - kfree(table); - return ret; -} - -/** - * spi_nor_parse_sccr() - Parse the Status, Control and Configuration Register - * Map. - * @nor: pointer to a 'struct spi_nor' - * @sccr_header: pointer to the 'struct sfdp_parameter_header' describing - * the SCCR Map table length and version. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_parse_sccr(struct spi_nor *nor, - const struct sfdp_parameter_header *sccr_header) -{ - u32 *table, addr; - size_t len; - int ret, i; - - len = sccr_header->length * sizeof(*table); - table = kmalloc(len, GFP_KERNEL); - if (!table) - return -ENOMEM; - - addr = SFDP_PARAM_HEADER_PTP(sccr_header); - ret = spi_nor_read_sfdp(nor, addr, len, table); - if (ret) - goto out; - - /* Fix endianness of the table DWORDs. */ - for (i = 0; i < sccr_header->length; i++) - table[i] = le32_to_cpu(table[i]); - - if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[21])) - nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; - -out: - kfree(table); - return ret; -} - -/** - * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. - * @nor: pointer to a 'struct spi_nor' - * @params: pointer to the 'struct spi_nor_flash_parameter' to be - * filled - * - * The Serial Flash Discoverable Parameters are described by the JEDEC JESD216 - * specification. This is a standard which tends to supported by almost all - * (Q)SPI memory manufacturers. Those hard-coded tables allow us to learn at - * runtime the main parameters needed to perform basic SPI flash operations such - * as Fast Read, Page Program or Sector Erase commands. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_parse_sfdp(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - const struct sfdp_parameter_header *param_header, *bfpt_header; - struct sfdp_parameter_header *param_headers = NULL; - struct sfdp_header header; - size_t psize; - int i, err; - - /* Get the SFDP header. */ - err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(header), &header); - if (err < 0) - return err; - - /* Check the SFDP header version. */ - if (le32_to_cpu(header.signature) != SFDP_SIGNATURE || - header.major != SFDP_JESD216_MAJOR) - return -EINVAL; - - /* - * Verify that the first and only mandatory parameter header is a - * Basic Flash Parameter Table header as specified in JESD216. - */ - bfpt_header = &header.bfpt_header; - if (SFDP_PARAM_HEADER_ID(bfpt_header) != SFDP_BFPT_ID || - bfpt_header->major != SFDP_JESD216_MAJOR) - return -EINVAL; - - /* - * Allocate memory then read all parameter headers with a single - * Read SFDP command. These parameter headers will actually be parsed - * twice: a first time to get the latest revision of the basic flash - * parameter table, then a second time to handle the supported optional - * tables. - * Hence we read the parameter headers once for all to reduce the - * processing time. Also we use kmalloc() instead of devm_kmalloc() - * because we don't need to keep these parameter headers: the allocated - * memory is always released with kfree() before exiting this function. - */ - if (header.nph) { - psize = header.nph * sizeof(*param_headers); - - param_headers = kmalloc(psize, GFP_KERNEL); - if (!param_headers) - return -ENOMEM; - - err = spi_nor_read_sfdp(nor, sizeof(header), - psize, param_headers); - if (err < 0) { - dev_err(nor->dev, - "failed to read SFDP parameter headers\n"); - goto exit; - } - } - - /* - * Check other parameter headers to get the latest revision of - * the basic flash parameter table. - */ - for (i = 0; i < header.nph; i++) { - param_header = ¶m_headers[i]; - - if (SFDP_PARAM_HEADER_ID(param_header) == SFDP_BFPT_ID && - param_header->major == SFDP_JESD216_MAJOR && - (param_header->minor > bfpt_header->minor || - (param_header->minor == bfpt_header->minor && - param_header->length > bfpt_header->length))) - bfpt_header = param_header; - } - - err = spi_nor_parse_bfpt(nor, bfpt_header, params); - if (err) - goto exit; - - /* Parse other parameter headers. */ - for (i = 0; i < header.nph; i++) { - param_header = ¶m_headers[i]; - - switch (SFDP_PARAM_HEADER_ID(param_header)) { - case SFDP_SECTOR_MAP_ID: - dev_info(nor->dev, - "non-uniform erase sector maps are not supported yet.\n"); - break; - - case SFDP_SST_ID: - err = spi_nor_parse_microchip_sfdp(nor, param_header); - break; - - case SFDP_PROFILE1_ID: - err = spi_nor_parse_profile1(nor, param_header, params); - break; - - case SFDP_SCCR_MAP_ID: - err = spi_nor_parse_sccr(nor, param_header); - break; - - default: - break; - } - - if (err) { - dev_warn(nor->dev, - "Failed to parse optional parameter table: %04x\n", - SFDP_PARAM_HEADER_ID(param_header)); - /* - * Let's not drop all information we extracted so far - * if optional table parsers fail. In case of failing, - * each optional parser is responsible to roll back to - * the previously known spi_nor data. - */ - err = 0; - } - } - -exit: - kfree(param_headers); - return err; -} -#else -static int spi_nor_parse_sfdp(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - return -EINVAL; -} -#endif /* SPI_FLASH_SFDP_SUPPORT */ - /** * spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings * after SFDP has been parsed. @@ -3273,7 +2404,7 @@ static int spi_nor_hwcaps2cmd(u32 hwcaps, const int table[][2], size_t size) return -EINVAL; } -static int spi_nor_hwcaps_read2cmd(u32 hwcaps) +int spi_nor_hwcaps_read2cmd(u32 hwcaps) { static const int hwcaps_read2cmd[][2] = { { SNOR_HWCAPS_READ, SNOR_CMD_READ }, -- 2.53.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 2/4] mtd: spi-nor: import manufacturer driver concept from Linux 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay @ 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay -1 siblings, 0 replies; 15+ messages in thread From: Takahiro Kuwano @ 2026-10-16 1:43 UTC (permalink / raw) To: u-boot Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev, Takahiro Kuwano Port spi_nor_manufacturer struct from Linux but ommit 'name' as we don't print manufacturer name in u-boot, and add 'set_fixups' function pointer to assign chip specific fixups in manufacturer drivers.Since the u-boot has size constraint, we should keep having chip-specific fixups in struct spi_nor instead of flash_info. The 'fixups' and 'set_fixups' are excluded for tiny. The manufacturers array and match_id helper are placed in spi-nor-ids.c as those need to be referred from both core and tiny. Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com> --- drivers/mtd/spi/sf_internal.h | 19 +++++++++++++++++++ drivers/mtd/spi/sfdp.c | 9 +++++++++ drivers/mtd/spi/spi-nor-core.c | 9 +++++++++ drivers/mtd/spi/spi-nor-ids.c | 22 ++++++++++++++++++++++ include/linux/mtd/spi-nor.h | 2 ++ 5 files changed, 61 insertions(+) diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 576617beb70..bc69af94aca 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -97,6 +97,23 @@ struct flash_info { #define SPI_NOR_OCTAL_DTR_READ BIT(17) /* Flash supports Octal DTR Read */ }; +/** + * struct spi_nor_manufacturer - SPI NOR manufacturer object + * @parts: array of parts supported by this manufacturer + * @nparts: number of entries in the parts array + * @fixups: hooks called at various points in time during spi_nor_scan() + * @set_fixups: called to assign chip-specific fixups + */ +struct spi_nor_manufacturer { + const struct flash_info *parts; + unsigned int nparts; +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + const struct spi_nor_fixups *fixups; + void (*set_fixups)(struct spi_nor *nor); +#endif +}; + +extern const struct spi_nor_manufacturer *manufacturers[]; extern const struct flash_info spi_nor_ids[]; #define JEDEC_MFR(info) ((info)->id[0]) @@ -143,4 +160,6 @@ int macronix_quad_enable(struct spi_nor *nor); int spi_nor_hwcaps_read2cmd(u32 hwcaps); int spansion_no_read_cr_quad_enable(struct spi_nor *nor); +const struct flash_info *spi_nor_match_id(struct spi_nor *nor, const u8 *id); + #endif /* _SF_INTERNAL_H_ */ diff --git a/drivers/mtd/spi/sfdp.c b/drivers/mtd/spi/sfdp.c index fd545796d50..db9dda12e27 100644 --- a/drivers/mtd/spi/sfdp.c +++ b/drivers/mtd/spi/sfdp.c @@ -219,6 +219,15 @@ spi_nor_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_bfpt *bfpt, struct spi_nor_flash_parameter *params) { + int ret; + + if (nor->manufacturer->fixups && nor->manufacturer->fixups->post_bfpt) { + ret = nor->manufacturer->fixups->post_bfpt(nor, bfpt_header, + bfpt, params); + if (ret) + return ret; + } + if (nor->fixups && nor->fixups->post_bfpt) return nor->fixups->post_bfpt(nor, bfpt_header, bfpt, params); diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index b99a1a45d8f..205986a4464 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -2190,6 +2190,9 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, static void spi_nor_post_sfdp_fixups(struct spi_nor *nor, struct spi_nor_flash_parameter *params) { + if (nor->manufacturer->fixups && nor->manufacturer->fixups->post_sfdp) + nor->manufacturer->fixups->post_sfdp(nor, params); + if (nor->fixups && nor->fixups->post_sfdp) nor->fixups->post_sfdp(nor, params); } @@ -2197,6 +2200,9 @@ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor, static void spi_nor_late_init_fixups(struct spi_nor *nor, struct spi_nor_flash_parameter *params) { + if (nor->manufacturer->fixups && nor->manufacturer->fixups->late_init) + nor->manufacturer->fixups->late_init(nor, params); + if (nor->fixups && nor->fixups->late_init) nor->fixups->late_init(nor, params); } @@ -3640,6 +3646,9 @@ int spi_nor_remove(struct spi_nor *nor) void spi_nor_set_fixups(struct spi_nor *nor) { + if (nor->manufacturer->set_fixups) + nor->manufacturer->set_fixups(nor); + #ifdef CONFIG_SPI_FLASH_SPANSION if (JEDEC_MFR(nor->info) == SNOR_MFR_CYPRESS) { switch (nor->info->id[1]) { diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 90aa1025176..e56efd3915e 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -728,3 +728,25 @@ const struct flash_info spi_nor_ids[] = { #endif { }, }; + +const struct spi_nor_manufacturer *manufacturers[] = { + NULL /* sentinel */ +}; + +const struct flash_info *spi_nor_match_id(struct spi_nor *nor, const u8 *id) +{ + const struct flash_info *part; + unsigned int i, j; + + for (i = 0; manufacturers[i]; i++) { + for (j = 0; j < manufacturers[i]->nparts; j++) { + part = &manufacturers[i]->parts[j]; + if (!memcmp(part->id, id, part->id_len)) { + nor->manufacturer = manufacturers[i]; + return part; + } + } + } + + return NULL; +} diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 4eef4ab0488..08567a80472 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -508,6 +508,7 @@ struct spi_flash { * @lock: the lock for the read/write/erase/lock/unlock operations * @dev: point to a spi device, or a spi nor controller device. * @info: spi-nor part JDEC MFR id and other info + * @manufacturer: SPI NOR manufacturer * @manufacturer_sfdp: manufacturer specific SFDP table * @page_size: the page size of the SPI NOR * @addr_width: number of address bytes @@ -559,6 +560,7 @@ struct spi_nor { struct udevice *dev; struct spi_slave *spi; const struct flash_info *info; + const struct spi_nor_manufacturer *manufacturer; u8 *manufacturer_sfdp; u32 page_size; u8 addr_width; -- 2.53.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 2/4] mtd: spi-nor: import manufacturer driver concept from Linux @ 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay 0 siblings, 0 replies; 15+ messages in thread From: Takahiro Kuwano via B4 Relay @ 2026-10-16 1:43 UTC (permalink / raw) To: u-boot Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev, Takahiro Kuwano From: Takahiro Kuwano <takahiro.kuwano@infineon.com> Port spi_nor_manufacturer struct from Linux but ommit 'name' as we don't print manufacturer name in u-boot, and add 'set_fixups' function pointer to assign chip specific fixups in manufacturer drivers.Since the u-boot has size constraint, we should keep having chip-specific fixups in struct spi_nor instead of flash_info. The 'fixups' and 'set_fixups' are excluded for tiny. The manufacturers array and match_id helper are placed in spi-nor-ids.c as those need to be referred from both core and tiny. Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com> --- drivers/mtd/spi/sf_internal.h | 19 +++++++++++++++++++ drivers/mtd/spi/sfdp.c | 9 +++++++++ drivers/mtd/spi/spi-nor-core.c | 9 +++++++++ drivers/mtd/spi/spi-nor-ids.c | 22 ++++++++++++++++++++++ include/linux/mtd/spi-nor.h | 2 ++ 5 files changed, 61 insertions(+) diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 576617beb70..bc69af94aca 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -97,6 +97,23 @@ struct flash_info { #define SPI_NOR_OCTAL_DTR_READ BIT(17) /* Flash supports Octal DTR Read */ }; +/** + * struct spi_nor_manufacturer - SPI NOR manufacturer object + * @parts: array of parts supported by this manufacturer + * @nparts: number of entries in the parts array + * @fixups: hooks called at various points in time during spi_nor_scan() + * @set_fixups: called to assign chip-specific fixups + */ +struct spi_nor_manufacturer { + const struct flash_info *parts; + unsigned int nparts; +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + const struct spi_nor_fixups *fixups; + void (*set_fixups)(struct spi_nor *nor); +#endif +}; + +extern const struct spi_nor_manufacturer *manufacturers[]; extern const struct flash_info spi_nor_ids[]; #define JEDEC_MFR(info) ((info)->id[0]) @@ -143,4 +160,6 @@ int macronix_quad_enable(struct spi_nor *nor); int spi_nor_hwcaps_read2cmd(u32 hwcaps); int spansion_no_read_cr_quad_enable(struct spi_nor *nor); +const struct flash_info *spi_nor_match_id(struct spi_nor *nor, const u8 *id); + #endif /* _SF_INTERNAL_H_ */ diff --git a/drivers/mtd/spi/sfdp.c b/drivers/mtd/spi/sfdp.c index fd545796d50..db9dda12e27 100644 --- a/drivers/mtd/spi/sfdp.c +++ b/drivers/mtd/spi/sfdp.c @@ -219,6 +219,15 @@ spi_nor_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_bfpt *bfpt, struct spi_nor_flash_parameter *params) { + int ret; + + if (nor->manufacturer->fixups && nor->manufacturer->fixups->post_bfpt) { + ret = nor->manufacturer->fixups->post_bfpt(nor, bfpt_header, + bfpt, params); + if (ret) + return ret; + } + if (nor->fixups && nor->fixups->post_bfpt) return nor->fixups->post_bfpt(nor, bfpt_header, bfpt, params); diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index b99a1a45d8f..205986a4464 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -2190,6 +2190,9 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, static void spi_nor_post_sfdp_fixups(struct spi_nor *nor, struct spi_nor_flash_parameter *params) { + if (nor->manufacturer->fixups && nor->manufacturer->fixups->post_sfdp) + nor->manufacturer->fixups->post_sfdp(nor, params); + if (nor->fixups && nor->fixups->post_sfdp) nor->fixups->post_sfdp(nor, params); } @@ -2197,6 +2200,9 @@ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor, static void spi_nor_late_init_fixups(struct spi_nor *nor, struct spi_nor_flash_parameter *params) { + if (nor->manufacturer->fixups && nor->manufacturer->fixups->late_init) + nor->manufacturer->fixups->late_init(nor, params); + if (nor->fixups && nor->fixups->late_init) nor->fixups->late_init(nor, params); } @@ -3640,6 +3646,9 @@ int spi_nor_remove(struct spi_nor *nor) void spi_nor_set_fixups(struct spi_nor *nor) { + if (nor->manufacturer->set_fixups) + nor->manufacturer->set_fixups(nor); + #ifdef CONFIG_SPI_FLASH_SPANSION if (JEDEC_MFR(nor->info) == SNOR_MFR_CYPRESS) { switch (nor->info->id[1]) { diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 90aa1025176..e56efd3915e 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -728,3 +728,25 @@ const struct flash_info spi_nor_ids[] = { #endif { }, }; + +const struct spi_nor_manufacturer *manufacturers[] = { + NULL /* sentinel */ +}; + +const struct flash_info *spi_nor_match_id(struct spi_nor *nor, const u8 *id) +{ + const struct flash_info *part; + unsigned int i, j; + + for (i = 0; manufacturers[i]; i++) { + for (j = 0; j < manufacturers[i]->nparts; j++) { + part = &manufacturers[i]->parts[j]; + if (!memcmp(part->id, id, part->id_len)) { + nor->manufacturer = manufacturers[i]; + return part; + } + } + } + + return NULL; +} diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 4eef4ab0488..08567a80472 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -508,6 +508,7 @@ struct spi_flash { * @lock: the lock for the read/write/erase/lock/unlock operations * @dev: point to a spi device, or a spi nor controller device. * @info: spi-nor part JDEC MFR id and other info + * @manufacturer: SPI NOR manufacturer * @manufacturer_sfdp: manufacturer specific SFDP table * @page_size: the page size of the SPI NOR * @addr_width: number of address bytes @@ -559,6 +560,7 @@ struct spi_nor { struct udevice *dev; struct spi_slave *spi; const struct flash_info *info; + const struct spi_nor_manufacturer *manufacturer; u8 *manufacturer_sfdp; u32 page_size; u8 addr_width; -- 2.53.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 3/4] mtd: spi-nor: move flash info entries to manufacturer drivers 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay @ 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay -1 siblings, 0 replies; 15+ messages in thread From: Takahiro Kuwano @ 2026-10-16 1:43 UTC (permalink / raw) To: u-boot Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev, Takahiro Kuwano Create manufacturer driver files and move flash info entries into them. Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com> --- drivers/mtd/spi/Makefile | 17 + drivers/mtd/spi/atmel.c | 28 ++ drivers/mtd/spi/dosilicon.c | 25 ++ drivers/mtd/spi/eon.c | 23 ++ drivers/mtd/spi/fujitsu.c | 27 ++ drivers/mtd/spi/gigadevice.c | 140 ++++++++ drivers/mtd/spi/issi.c | 84 +++++ drivers/mtd/spi/macronix.c | 65 ++++ drivers/mtd/spi/micron-st.c | 70 ++++ drivers/mtd/spi/puya.c | 56 +++ drivers/mtd/spi/sandbox.c | 33 +- drivers/mtd/spi/sf_internal.h | 57 +++- drivers/mtd/spi/siliconkaiser.c | 18 + drivers/mtd/spi/spansion.c | 73 ++++ drivers/mtd/spi/spi-nor-core.c | 10 +- drivers/mtd/spi/spi-nor-ids.c | 737 ++-------------------------------------- drivers/mtd/spi/spi-nor-tiny.c | 11 +- drivers/mtd/spi/sst.c | 34 ++ drivers/mtd/spi/winbond.c | 146 ++++++++ drivers/mtd/spi/xmc.c | 27 ++ drivers/mtd/spi/xtx.c | 54 +++ drivers/mtd/spi/zbit.c | 19 ++ 22 files changed, 1027 insertions(+), 727 deletions(-) diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 1828e5fadfe..74fe9b49a69 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -17,6 +17,23 @@ spi-nor-y += spi-nor-core.o spi-nor-$(CONFIG_SPI_FLASH_SFDP_SUPPORT) += sfdp.o endif +spi-nor-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o +spi-nor-$(CONFIG_SPI_FLASH_DOSILICON) += dosilicon.o +spi-nor-$(CONFIG_SPI_FLASH_EON) += eon.o +spi-nor-$(CONFIG_SPI_FRAM_FUJITSU) += fujitsu.o +spi-nor-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.o +spi-nor-$(CONFIG_SPI_FLASH_ISSI) += issi.o +spi-nor-$(CONFIG_SPI_FLASH_MACRONIX) += macronix.o +spi-nor-$(CONFIG_SPI_FLASH_PUYA) += puya.o +spi-nor-$(CONFIG_SPI_FLASH_SILICONKAISER) += siliconkaiser.o +spi-nor-$(CONFIG_SPI_FLASH_STMICRO) += micron-st.o +spi-nor-$(CONFIG_SPI_FLASH_SPANSION) += spansion.o +spi-nor-$(CONFIG_SPI_FLASH_SST) += sst.o +spi-nor-$(CONFIG_SPI_FLASH_WINBOND) += winbond.o +spi-nor-$(CONFIG_SPI_FLASH_XMC) += xmc.o +spi-nor-$(CONFIG_SPI_FLASH_XTX) += xtx.o +spi-nor-$(CONFIG_SPI_FLASH_ZBIT) += zbit.o + obj-$(CONFIG_SPI_FLASH) += spi-nor.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o obj-$(CONFIG_$(PHASE_)SPI_FLASH_MTD) += sf_mtd.o diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c new file mode 100644 index 00000000000..53c7afff323 --- /dev/null +++ b/drivers/mtd/spi/atmel.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info atmel_nor_parts[] = { + { INFO("at26df321", 0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("at25df321a", 0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("at45db011d", 0x1f2200, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("at45db021d", 0x1f2300, 0, 64 * 1024, 8, SECT_4K) }, + { INFO("at45db041d", 0x1f2400, 0, 64 * 1024, 8, SECT_4K) }, + { INFO("at45db081d", 0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, + { INFO("at45db161d", 0x1f2600, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("at45db321d", 0x1f2700, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("at45db641d", 0x1f2800, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("at25sl321", 0x1f4216, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, +}; + +const struct spi_nor_manufacturer spi_nor_atmel = { + .parts = atmel_nor_parts, + .nparts = ARRAY_SIZE(atmel_nor_parts), +}; diff --git a/drivers/mtd/spi/dosilicon.c b/drivers/mtd/spi/dosilicon.c new file mode 100644 index 00000000000..1c889960656 --- /dev/null +++ b/drivers/mtd/spi/dosilicon.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info dosilicon_nor_parts[] = { + { INFO("ds25m4cb", 0xe5401a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("ds25m4dn", 0xe5401b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("ds25q4cb", 0xe5301a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("ds25q4dn", 0xe5301b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_dosilicon = { + .parts = dosilicon_nor_parts, + .nparts = ARRAY_SIZE(dosilicon_nor_parts), +}; diff --git a/drivers/mtd/spi/eon.c b/drivers/mtd/spi/eon.c new file mode 100644 index 00000000000..6690ba2a1da --- /dev/null +++ b/drivers/mtd/spi/eon.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info eon_nor_parts[] = { + { INFO("en25q80b", 0x1c3014, 0, 64 * 1024, 16, SECT_4K) }, + { INFO("en25q32b", 0x1c3016, 0, 64 * 1024, 64, 0) }, + { INFO("en25q64", 0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("en25q128b", 0x1c3018, 0, 64 * 1024, 256, 0) }, + { INFO("en25qh128", 0x1c7018, 0, 64 * 1024, 256, 0) }, + { INFO("en25s64", 0x1c3817, 0, 64 * 1024, 128, SECT_4K) }, +}; + +const struct spi_nor_manufacturer spi_nor_eon = { + .parts = eon_nor_parts, + .nparts = ARRAY_SIZE(eon_nor_parts), +}; diff --git a/drivers/mtd/spi/fujitsu.c b/drivers/mtd/spi/fujitsu.c new file mode 100644 index 00000000000..3d5328b1815 --- /dev/null +++ b/drivers/mtd/spi/fujitsu.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info fujitsu_nor_parts[] = { + { + INFO_NAME("mb85rs256ty") + .id = {0x04, 0x7f, 0x25, 0x00, 0x00}, + .id_len = 3, + .sector_size = 32 * 1024, + .n_sectors = 1, + .page_size = 32 * 1024, /* Whole chip can be written at once */ + .flags = SPI_NOR_NO_ERASE, + .addr_width = 2, + }, +}; + +const struct spi_nor_manufacturer spi_nor_fujitsu = { + .parts = fujitsu_nor_parts, + .nparts = ARRAY_SIZE(fujitsu_nor_parts), +}; diff --git a/drivers/mtd/spi/gigadevice.c b/drivers/mtd/spi/gigadevice.c new file mode 100644 index 00000000000..895d97f5f9b --- /dev/null +++ b/drivers/mtd/spi/gigadevice.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info gigadevice_nor_parts[] = { + { + INFO("gd25q16", 0xc84015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25q32", 0xc84016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25lq32", 0xc86016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25q64", 0xc84017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25lq64c", 0xc86017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25q128", 0xc84018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + /* adding these 3V QSPI flash parts */ + {INFO("gd25b256", 0xc84019, 0, 64 * 1024, 512, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES) }, + {INFO("gd25b512", 0xc8471A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55b01g", 0xc8471B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55b02g", 0xc8471C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25f64", 0xc84317, 0, 64 * 1024, 128, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, + {INFO("gd25f128", 0xc84318, 0, 64 * 1024, 256, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, + {INFO("gd25f256", 0xc84319, 0, 64 * 1024, 512, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55f512", 0xc8431A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25t512", 0xc8461A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55t01g", 0xc8461B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55t02g", 0xc8461C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + /* adding these 3V OSPI flash parts */ + {INFO("gd25x512", 0xc8481A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + {INFO("gd55x01g", 0xc8481B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + {INFO("gd55x02g", 0xc8481C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + { + INFO("gd25lq128", 0xc86018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25lq256d", 0xc86019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + /* adding these 1.8V QSPI flash parts */ + {INFO("gd25lb256", 0xc86719, 0, 64 * 1024, 512, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lb512", 0xc8671A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lb01g", 0xc8671B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lb02g", 0xc8671C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lf80", 0xc86314, 0, 64 * 1024, 16, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, + {INFO("gd25lf16", 0xc86315, 0, 64 * 1024, 32, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, + {INFO("gd25lf32", 0xc86316, 0, 64 * 1024, 64, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, + {INFO("gd25lf64", 0xc86317, 0, 64 * 1024, 128, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, + {INFO("gd25lf128", 0xc86318, 0, 64 * 1024, 256, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, + {INFO("gd25lf255", 0xc86319, 0, 64 * 1024, 512, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lf511", 0xc8631A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lt256", 0xc86619, 0, 64 * 1024, 512, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lt512", 0xc8661A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lt01g", 0xc8661B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lt02g", 0xc8661C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lx128j", 0xc86818, 0, 64 * 1024, 256, SECT_4K | + SPI_NOR_OCTAL_READ)}, + { + INFO("gd25lx256e", 0xc86819, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) + }, + /* adding these 1.8V OSPI flash parts */ + {INFO("gd25lx512", 0xc8681A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lx01g", 0xc8681B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lx02g", 0xc8681C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + { + INFO("gd55lb02ge", 0xc8671c, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd55lb02gf", 0xc8601c, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) + }, +}; + +const struct spi_nor_manufacturer spi_nor_gigadevice = { + .parts = gigadevice_nor_parts, + .nparts = ARRAY_SIZE(gigadevice_nor_parts), +}; diff --git a/drivers/mtd/spi/issi.c b/drivers/mtd/spi/issi.c new file mode 100644 index 00000000000..2537ca811f8 --- /dev/null +++ b/drivers/mtd/spi/issi.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info issi_nor_parts[] = { + { INFO("is25lq040b", 0x9d4013, 0, 64 * 1024, 8, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp008", 0x9d6014, 0, 64 * 1024, 16, SPI_NOR_QUAD_READ) }, + { INFO("is25lp016", 0x9d6015, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ) }, + { INFO("is25lp032", 0x9d6016, 0, 64 * 1024, 64, 0) }, + { INFO("is25lp064", 0x9d6017, 0, 64 * 1024, 128, 0) }, + { INFO("is25lp128", 0x9d6018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ) }, + { INFO("is25lp256", 0x9d6019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ) }, + { INFO("is25lp512", 0x9d601a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp512mj", 0x9d6020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp01g", 0x9d601b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp008", 0x9d7014, 0, 64 * 1024, 16, SPI_NOR_QUAD_READ) }, + { INFO("is25wp016", 0x9d7015, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ) }, + { INFO("is25wp032", 0x9d7016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp064", 0x9d7017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp128", 0x9d7018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp256", 0x9d7019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_4B_OPCODES) }, + { INFO("is25wp512", 0x9d701a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp512mj", 0x9d7020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp01g", 0x9d701b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp01gg", 0x9d7021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wx128", 0x9d5b18, 0, 64 * 1024, 256, + SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ) }, + { INFO("is25wx256", 0x9d5b19, 0, 128 * 1024, 256, + SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, + { INFO("is25lx128", 0x9d5a18, 0, 64 * 1024, 256, + SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ) }, + { INFO("is25lx512", 0x9d5a1a, 0, 64 * 1024, 1024, + SECT_4K | USE_FSR | SPI_NOR_4B_OPCODES | SPI_NOR_HAS_TB) }, + { INFO("is25lp01gg", 0x9d6021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25lp010e", 0x9d4011, 0, 64 * 1024, 2, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp020e", 0x9d4012, 0, 64 * 1024, 4, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp040e", 0x9d4013, 0, 64 * 1024, 8, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp01gj", 0x9d6021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25lp02gg", 0x9d6022, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25lp02gj", 0x9d6022, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25wp01gg", 0x9d7021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25wp01gj", 0x9d7021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25wj128f", 0x9d7118, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25wp02gg", 0x9d7022, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25wp02gj", 0x9d7022, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, +}; + +const struct spi_nor_manufacturer spi_nor_issi = { + .parts = issi_nor_parts, + .nparts = ARRAY_SIZE(issi_nor_parts), +}; diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c new file mode 100644 index 00000000000..87843978cad --- /dev/null +++ b/drivers/mtd/spi/macronix.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info macronix_nor_parts[] = { + { INFO("mx25l2005a", 0xc22012, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("mx25l4005a", 0xc22013, 0, 64 * 1024, 8, SECT_4K) }, + { INFO("mx25l8005", 0xc22014, 0, 64 * 1024, 16, 0) }, + { INFO("mx25l1606e", 0xc22015, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("mx25l3205d", 0xc22016, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("mx25l6405d", 0xc22017, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("mx25u2033e", 0xc22532, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("mx25u1635e", 0xc22535, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("mx25u3235f", 0xc22536, 0, 4 * 1024, 1024, SECT_4K) }, + { INFO("mx25u6435f", 0xc22537, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, SECT_4K) }, + { INFO("mx25u12835f", 0xc22538, 0, 64 * 1024, 256, SECT_4K | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("mx25u51245g", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0) }, + { INFO("mx25l25635e", 0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("mx25u25635f", 0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, + { INFO("mx25v8035f", 0xc22314, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("mx25r1635f", 0xc22815, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0) }, + { INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66u51235f", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25u51245f", 0xc2953a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66u1g45g", 0xc2253b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66u2g45g", 0xc2253c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66l1g45g", 0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("mx66l2g45g", 0xc2201c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25l1633e", 0xc22415, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SECT_4K) }, + { INFO("mx25r6435f", 0xc22817, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("mx66uw2g345gx0", 0xc2943c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_READ) }, + { INFO("mx66lm1g45g", 0xc2853b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25lm51245g", 0xc2853a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25lw51245g", 0xc2863a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25lm25645g", 0xc28539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66uw2g345g", 0xc2843c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66um1g45g", 0xc2803b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66uw1g45g", 0xc2813b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw51245g", 0xc2813a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw51345g", 0xc2843a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25um25645g", 0xc28039, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw25645g", 0xc28139, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25um25345g", 0xc28339, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw25345g", 0xc28439, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw12845g", 0xc28138, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw12345g", 0xc28438, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw6445g", 0xc28137, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw6345g", 0xc28437, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_macronix = { + .parts = macronix_nor_parts, + .nparts = ARRAY_SIZE(macronix_nor_parts), +}; diff --git a/drivers/mtd/spi/micron-st.c b/drivers/mtd/spi/micron-st.c new file mode 100644 index 00000000000..2d47f1c60c0 --- /dev/null +++ b/drivers/mtd/spi/micron-st.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info micron_nor_parts[] = { + { INFO("n25q016a", 0x20bb15, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_QUAD_READ) }, + { INFO("n25q032", 0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, + { INFO("n25q032a", 0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, + { INFO("n25q064", 0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, + { INFO("n25q064a", 0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, + { INFO("n25q128a11", 0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, + { INFO("n25q128a13", 0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, + { INFO6("mt25ql256a", 0x20ba19, 0x104400, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) }, + { INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_FSR) }, + { INFO6("mt25qu256a", 0x20bb19, 0x104400, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) }, + { INFO("n25q256ax1", 0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | USE_FSR) }, + { INFO("mt25qu128ab", 0x20bb18, 0, 64 * 1024, 256, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { INFO6("mt25qu512a", 0x20bb20, 0x104400, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_FSR) }, + { INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { INFO6("mt25ql512a", 0x20ba20, 0x104400, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { INFO("n25q00a", 0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { INFO("mt25ql01g", 0x21ba20, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { INFO6("mt25qu01g", 0x20bb21, 0x104400, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE | SPI_NOR_4B_OPCODES) }, + { INFO("mt25qu02g", 0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { INFO("mt25ql02g", 0x20ba22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE | SPI_NOR_4B_OPCODES) }, +#ifdef CONFIG_SPI_FLASH_MT35XU + { INFO("mt35xl512aba", 0x2c5a1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ) }, + { INFO("mt35xu512aba", 0x2c5b1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ) }, + { INFO("mt35xu01gaba", 0x2c5b1b, 0, 128 * 1024, 1024, + USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, +#endif /* CONFIG_SPI_FLASH_MT35XU */ + { INFO6("mt35xu01g", 0x2c5b1b, 0x104100, 128 * 1024, 1024, + USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, + { INFO("mt35xu02g", 0x2c5b1c, 0, 128 * 1024, 2048, + USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, +}; + +static const struct flash_info st_nor_parts[] = { + { INFO("m25p10", 0x202011, 0, 32 * 1024, 4, 0) }, + { INFO("m25p20", 0x202012, 0, 64 * 1024, 4, 0) }, + { INFO("m25p40", 0x202013, 0, 64 * 1024, 8, 0) }, + { INFO("m25p80", 0x202014, 0, 64 * 1024, 16, 0) }, + { INFO("m25p16", 0x202015, 0, 64 * 1024, 32, 0) }, + { INFO("m25p32", 0x202016, 0, 64 * 1024, 64, 0) }, + { INFO("m25p64", 0x202017, 0, 64 * 1024, 128, 0) }, + { INFO("m25p128", 0x202018, 0, 256 * 1024, 64, 0) }, + { INFO("m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("m25px16", 0x207115, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0) }, +}; + +const struct spi_nor_manufacturer spi_nor_micron = { + .parts = micron_nor_parts, + .nparts = ARRAY_SIZE(micron_nor_parts), +}; + +const struct spi_nor_manufacturer spi_nor_st = { + .parts = st_nor_parts, + .nparts = ARRAY_SIZE(st_nor_parts), +}; diff --git a/drivers/mtd/spi/puya.c b/drivers/mtd/spi/puya.c new file mode 100644 index 00000000000..37092945dfc --- /dev/null +++ b/drivers/mtd/spi/puya.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info puya_nor_parts[] = { + { INFO + ("p25q05h", 0x856010, 0, 64 * 1024, 1, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q10h", 0x856011, 0, 64 * 1024, 2, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q20h", 0x856012, 0, 64 * 1024, 4, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q40h", 0x856013, 0, 64 * 1024, 8, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q80h", 0x856014, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q16h", 0x856015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q32h", 0x856016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q64h", 0x856017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q128h", 0x856018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("py25f512hb", 0x85231a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO + ("py25f01ghb", 0x85231b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO + ("py25f512lc", 0x85631a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO + ("py25f01glc", 0x85631b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_puya = { + .parts = puya_nor_parts, + .nparts = ARRAY_SIZE(puya_nor_parts), +}; diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index e5ebc3479fb..44d8509cd64 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -110,6 +110,27 @@ void sandbox_sf_set_block_protect(struct udevice *dev, int bp_mask) sbsf->status |= bp_mask << STAT_BP_SHIFT; } +static const struct flash_info *spi_nor_match_name(const char *name, + size_t name_len) +{ + const struct flash_info *part; + unsigned int i, j; + size_t len; + + for (i = 0; manufacturers[i]; i++) { + for (j = 0; j < manufacturers[i]->nparts; j++) { + part = &manufacturers[i]->parts[j]; + len = strlen(part->name); + if (name_len != len) + continue; + if (!strncasecmp(name, part->name, len)) + return part; + } + } + + return NULL; +} + /** * 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 @@ -119,7 +140,7 @@ static int sandbox_sf_probe(struct udevice *dev) { /* spec = idcode:file */ struct sandbox_spi_flash *sbsf = dev_get_priv(dev); - size_t len, idname_len; + size_t idname_len; const struct flash_info *data; struct sandbox_spi_flash_plat_data *pdata = dev_get_plat(dev); struct sandbox_state *state = state_get_current(); @@ -153,14 +174,8 @@ static int sandbox_sf_probe(struct udevice *dev) idname_len = strlen(spec); debug("%s: device='%s'\n", __func__, spec); - for (data = spi_nor_ids; data->name; data++) { - len = strlen(data->name); - if (idname_len != len) - continue; - if (!strncasecmp(spec, data->name, len)) - break; - } - if (!data->name) { + data = spi_nor_match_name(spec, idname_len); + if (!data) { printf("%s: unknown flash '%*s'\n", __func__, (int)idname_len, spec); ret = -EINVAL; diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index bc69af94aca..f96895c7439 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -97,6 +97,45 @@ struct flash_info { #define SPI_NOR_OCTAL_DTR_READ BIT(17) /* Flash supports Octal DTR Read */ }; +/* Exclude chip names for SPL to save space */ +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) +#define INFO_NAME(_name) .name = _name, +#else +#define INFO_NAME(_name) +#endif + +/* Used when the "_ext_id" is two bytes at most */ +#define INFO(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ + INFO_NAME(_name) \ + .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(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ + INFO_NAME(_name) \ + .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), + /** * struct spi_nor_manufacturer - SPI NOR manufacturer object * @parts: array of parts supported by this manufacturer @@ -114,7 +153,23 @@ struct spi_nor_manufacturer { }; extern const struct spi_nor_manufacturer *manufacturers[]; -extern const struct flash_info spi_nor_ids[]; +extern const struct spi_nor_manufacturer spi_nor_atmel; +extern const struct spi_nor_manufacturer spi_nor_dosilicon; +extern const struct spi_nor_manufacturer spi_nor_eon; +extern const struct spi_nor_manufacturer spi_nor_fujitsu; +extern const struct spi_nor_manufacturer spi_nor_gigadevice; +extern const struct spi_nor_manufacturer spi_nor_issi; +extern const struct spi_nor_manufacturer spi_nor_macronix; +extern const struct spi_nor_manufacturer spi_nor_puya; +extern const struct spi_nor_manufacturer spi_nor_siliconkaiser; +extern const struct spi_nor_manufacturer spi_nor_micron; +extern const struct spi_nor_manufacturer spi_nor_st; +extern const struct spi_nor_manufacturer spi_nor_spansion; +extern const struct spi_nor_manufacturer spi_nor_sst; +extern const struct spi_nor_manufacturer spi_nor_winbond; +extern const struct spi_nor_manufacturer spi_nor_xmc; +extern const struct spi_nor_manufacturer spi_nor_xtx; +extern const struct spi_nor_manufacturer spi_nor_zbit; #define JEDEC_MFR(info) ((info)->id[0]) #define JEDEC_ID(info) (((info)->id[1]) << 8 | ((info)->id[2])) diff --git a/drivers/mtd/spi/siliconkaiser.c b/drivers/mtd/spi/siliconkaiser.c new file mode 100644 index 00000000000..23e03ff8088 --- /dev/null +++ b/drivers/mtd/spi/siliconkaiser.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info siliconkaiser_nor_parts[] = { + { INFO("sk25lp128", 0x257018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +}; + +const struct spi_nor_manufacturer spi_nor_siliconkaiser = { + .parts = siliconkaiser_nor_parts, + .nparts = ARRAY_SIZE(siliconkaiser_nor_parts), +}; diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c new file mode 100644 index 00000000000..405f5bf5e79 --- /dev/null +++ b/drivers/mtd/spi/spansion.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info spansion_nor_parts[] = { + { INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO6("s25fl256s0", 0x010219, 0x4d0080, 256 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fl256s1", 0x010219, 0x4d0180, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fl512s", 0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs064s", 0x010217, 0x4d0181, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs128s", 0x012018, 0x4d0181, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs256s", 0x010219, 0x4d0181, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs512s", 0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25fl512s_256k", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25fl512s_64k", 0x010220, 0x4d01, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25fl512s_512k", 0x010220, 0x4f00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s70fs01gs_256k", 0x010221, 0x4d00, 256 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, 0) }, + { INFO("s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, 0) }, + { INFO6("s25fl128s", 0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25sl008a", 0x010213, 0, 64 * 1024, 16, 0) }, + { INFO("s25sl016a", 0x010214, 0, 64 * 1024, 32, 0) }, + { INFO("s25sl032a", 0x010215, 0, 64 * 1024, 64, 0) }, + { INFO("s25sl064a", 0x010216, 0, 64 * 1024, 128, 0) }, + { INFO("s25fl116k", 0x014015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("s25fl164k", 0x014017, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("s25fl208k", 0x014014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) }, + { INFO("s25fl064l", 0x016017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("s25fl128l", 0x016018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("s25fl256l", 0x016019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO6("s25hl512t", 0x342a1a, 0x0f0390, 256 * 1024, 256, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hl01gt", 0x342a1b, 0x0f0390, 256 * 1024, 512, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hl02gt", 0x342a1c, 0x0f0090, 256 * 1024, 1024, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, + { INFO6("s25hs512t", 0x342b1a, 0x0f0390, 256 * 1024, 256, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hs01gt", 0x342b1b, 0x0f0390, 256 * 1024, 512, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hs02gt", 0x342b1c, 0x0f0090, 256 * 1024, 1024, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, + { INFO6("s25fs256t", 0x342b19, 0x0f0890, 128 * 1024, 256, + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +#ifdef CONFIG_SPI_FLASH_S28HX_T + { INFO("s28hl256t", 0x345a19, 0, 256 * 1024, 128, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hl512t", 0x345a1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hl01gt", 0x345a1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hl02gt", 0x345a1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ | NO_CHIP_ERASE) }, + { INFO("s28hs256t", 0x345b19, 0, 256 * 1024, 128, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hs512t", 0x345b1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hs01gt", 0x345b1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hs02gt", 0x345b1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ | NO_CHIP_ERASE) }, +#endif +}; + +const struct spi_nor_manufacturer spi_nor_spansion = { + .parts = spansion_nor_parts, + .nparts = ARRAY_SIZE(spansion_nor_parts), +}; diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 205986a4464..d107828092c 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -1405,13 +1405,9 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) return ERR_PTR(tmp); } - info = spi_nor_ids; - for (; info->name; info++) { - if (info->id_len) { - if (!memcmp(info->id, id, info->id_len)) - return info; - } - } + info = spi_nor_match_id(nor, id); + if (info) + return info; dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n", id[0], id[1], id[2]); diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index e56efd3915e..d1b22f0e5da 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -11,725 +11,56 @@ #include "sf_internal.h" -/* Exclude chip names for SPL to save space */ -#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) -#define INFO_NAME(_name) .name = _name, -#else -#define INFO_NAME(_name) -#endif - -/* Used when the "_ext_id" is two bytes at most */ -#define INFO(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - INFO_NAME(_name) \ - .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(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - INFO_NAME(_name) \ - .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), - -/* NOTE: double check command sets and memory organization when you add - * more nor chips. This current list focusses on newer chips, which - * have been converging on command sets which including JEDEC ID. - * - * All newly added entries should describe *hardware* and should use SECT_4K - * (or SECT_4K_PMC) if hardware supports erasing 4 KiB sectors. For usage - * scenarios excluding small sectors there is config option that can be - * disabled: CONFIG_SPI_FLASH_USE_4K_SECTORS. - * For historical (and compatibility) reasons (before we got above config) some - * old entries may be missing 4K flag. - */ -const struct flash_info spi_nor_ids[] = { -#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ - /* Atmel -- some are (confusingly) marketed as "DataFlash" */ - { INFO("at26df321", 0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("at25df321a", 0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, - - { INFO("at45db011d", 0x1f2200, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("at45db021d", 0x1f2300, 0, 64 * 1024, 8, SECT_4K) }, - { INFO("at45db041d", 0x1f2400, 0, 64 * 1024, 8, SECT_4K) }, - { INFO("at45db081d", 0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, - { INFO("at45db161d", 0x1f2600, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("at45db321d", 0x1f2700, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("at45db641d", 0x1f2800, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("at25sl321", 0x1f4216, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, -#endif -#ifdef CONFIG_SPI_FLASH_DOSILICON - /* Dosilicon Co., Ltd */ - { INFO("ds25m4cb", 0xe5401a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("ds25m4dn", 0xe5401b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("ds25q4cb", 0xe5301a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("ds25q4dn", 0xe5301b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, -#endif -#ifdef CONFIG_SPI_FLASH_EON /* EON */ - /* EON -- en25xxx */ - { INFO("en25q80b", 0x1c3014, 0, 64 * 1024, 16, SECT_4K) }, - { INFO("en25q32b", 0x1c3016, 0, 64 * 1024, 64, 0) }, - { INFO("en25q64", 0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("en25q128b", 0x1c3018, 0, 64 * 1024, 256, 0) }, - { INFO("en25qh128", 0x1c7018, 0, 64 * 1024, 256, 0) }, - { INFO("en25s64", 0x1c3817, 0, 64 * 1024, 128, SECT_4K) }, +const struct spi_nor_manufacturer *manufacturers[] = { +#if (IS_ENABLED(CONFIG_SPI_FLASH_ATMEL)) + &spi_nor_atmel, #endif -#ifdef CONFIG_SPI_FRAM_FUJITSU - /* Fujitsu MB85RS256TY */ - { - INFO_NAME("mb85rs256ty") - .id = {0x04, 0x7f, 0x25, 0x00, 0x00}, - .id_len = 3, - .sector_size = 32 * 1024, - .n_sectors = 1, - .page_size = 32 * 1024, /* Whole chip can be written at once */ - .flags = SPI_NOR_NO_ERASE, - .addr_width = 2, - }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_DOSILICON)) + &spi_nor_dosilicon, #endif -#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ - /* GigaDevice */ - { - INFO("gd25q16", 0xc84015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25q32", 0xc84016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25lq32", 0xc86016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25q64", 0xc84017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25lq64c", 0xc86017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25q128", 0xc84018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - /* adding these 3V QSPI flash parts */ - {INFO("gd25b256", 0xc84019, 0, 64 * 1024, 512, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES) }, - {INFO("gd25b512", 0xc8471A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55b01g", 0xc8471B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55b02g", 0xc8471C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25f64", 0xc84317, 0, 64 * 1024, 128, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, - {INFO("gd25f128", 0xc84318, 0, 64 * 1024, 256, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, - {INFO("gd25f256", 0xc84319, 0, 64 * 1024, 512, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55f512", 0xc8431A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25t512", 0xc8461A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55t01g", 0xc8461B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55t02g", 0xc8461C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - /* adding these 3V OSPI flash parts */ - {INFO("gd25x512", 0xc8481A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - {INFO("gd55x01g", 0xc8481B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - {INFO("gd55x02g", 0xc8481C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - { - INFO("gd25lq128", 0xc86018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25lq256d", 0xc86019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - /* adding these 1.8V QSPI flash parts */ - {INFO("gd25lb256", 0xc86719, 0, 64 * 1024, 512, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lb512", 0xc8671A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lb01g", 0xc8671B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lb02g", 0xc8671C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lf80", 0xc86314, 0, 64 * 1024, 16, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, - {INFO("gd25lf16", 0xc86315, 0, 64 * 1024, 32, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, - {INFO("gd25lf32", 0xc86316, 0, 64 * 1024, 64, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, - {INFO("gd25lf64", 0xc86317, 0, 64 * 1024, 128, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, - {INFO("gd25lf128", 0xc86318, 0, 64 * 1024, 256, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, - {INFO("gd25lf255", 0xc86319, 0, 64 * 1024, 512, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lf511", 0xc8631A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lt256", 0xc86619, 0, 64 * 1024, 512, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lt512", 0xc8661A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lt01g", 0xc8661B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lt02g", 0xc8661C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lx128j", 0xc86818, 0, 64 * 1024, 256, SECT_4K | - SPI_NOR_OCTAL_READ)}, - { - INFO("gd25lx256e", 0xc86819, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) - }, - /* adding these 1.8V OSPI flash parts */ - {INFO("gd25lx512", 0xc8681A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lx01g", 0xc8681B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lx02g", 0xc8681C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - { - INFO("gd55lb02ge", 0xc8671c, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd55lb02gf", 0xc8601c, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) - }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_EON)) + &spi_nor_eon, #endif -#ifdef CONFIG_SPI_FLASH_ISSI /* ISSI */ - /* ISSI */ - { INFO("is25lq040b", 0x9d4013, 0, 64 * 1024, 8, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp008", 0x9d6014, 0, 64 * 1024, 16, SPI_NOR_QUAD_READ) }, - { INFO("is25lp016", 0x9d6015, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ) }, - { INFO("is25lp032", 0x9d6016, 0, 64 * 1024, 64, 0) }, - { INFO("is25lp064", 0x9d6017, 0, 64 * 1024, 128, 0) }, - { INFO("is25lp128", 0x9d6018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ) }, - { INFO("is25lp256", 0x9d6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ) }, - { INFO("is25lp512", 0x9d601a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp512mj", 0x9d6020, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp01g", 0x9d601b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp008", 0x9d7014, 0, 64 * 1024, 16, SPI_NOR_QUAD_READ) }, - { INFO("is25wp016", 0x9d7015, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ) }, - { INFO("is25wp032", 0x9d7016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp064", 0x9d7017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp128", 0x9d7018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp256", 0x9d7019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_4B_OPCODES) }, - { INFO("is25wp512", 0x9d701a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp512mj", 0x9d7020, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp01g", 0x9d701b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp01gg", 0x9d7021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wx128", 0x9d5b18, 0, 64 * 1024, 256, - SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ) }, - { INFO("is25wx256", 0x9d5b19, 0, 128 * 1024, 256, - SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, - { INFO("is25lx128", 0x9d5a18, 0, 64 * 1024, 256, - SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ) }, - { INFO("is25lx512", 0x9d5a1a, 0, 64 * 1024, 1024, - SECT_4K | USE_FSR | SPI_NOR_4B_OPCODES | SPI_NOR_HAS_TB) }, - { INFO("is25lp01gg", 0x9d6021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25lp010e", 0x9d4011, 0, 64 * 1024, 2, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp020e", 0x9d4012, 0, 64 * 1024, 4, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp040e", 0x9d4013, 0, 64 * 1024, 8, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp01gj", 0x9d6021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25lp02gg", 0x9d6022, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25lp02gj", 0x9d6022, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25wp01gg", 0x9d7021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25wp01gj", 0x9d7021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25wj128f", 0x9d7118, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25wp02gg", 0x9d7022, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25wp02gj", 0x9d7022, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, +#if (IS_ENABLED(CONFIG_SPI_FRAM_FUJITSU)) + &spi_nor_fujitsu, #endif -#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ - /* Macronix */ - { INFO("mx25l2005a", 0xc22012, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("mx25l4005a", 0xc22013, 0, 64 * 1024, 8, SECT_4K) }, - { INFO("mx25l8005", 0xc22014, 0, 64 * 1024, 16, 0) }, - { INFO("mx25l1606e", 0xc22015, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("mx25l3205d", 0xc22016, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("mx25l6405d", 0xc22017, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("mx25u2033e", 0xc22532, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("mx25u1635e", 0xc22535, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("mx25u3235f", 0xc22536, 0, 4 * 1024, 1024, SECT_4K) }, - { INFO("mx25u6435f", 0xc22537, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, SECT_4K) }, - { INFO("mx25u12835f", 0xc22538, 0, 64 * 1024, 256, SECT_4K | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("mx25u51245g", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0) }, - { INFO("mx25l25635e", 0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("mx25u25635f", 0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, - { INFO("mx25v8035f", 0xc22314, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("mx25r1635f", 0xc22815, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0) }, - { INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66u51235f", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25u51245f", 0xc2953a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66u1g45g", 0xc2253b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66u2g45g", 0xc2253c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66l1g45g", 0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("mx66l2g45g", 0xc2201c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25l1633e", 0xc22415, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SECT_4K) }, - { INFO("mx25r6435f", 0xc22817, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("mx66uw2g345gx0", 0xc2943c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_READ) }, - { INFO("mx66lm1g45g", 0xc2853b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25lm51245g", 0xc2853a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25lw51245g", 0xc2863a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25lm25645g", 0xc28539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66uw2g345g", 0xc2843c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66um1g45g", 0xc2803b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66uw1g45g", 0xc2813b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw51245g", 0xc2813a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw51345g", 0xc2843a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25um25645g", 0xc28039, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw25645g", 0xc28139, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25um25345g", 0xc28339, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw25345g", 0xc28439, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw12845g", 0xc28138, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw12345g", 0xc28438, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw6445g", 0xc28137, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw6345g", 0xc28437, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_GIGADEVICE)) + &spi_nor_gigadevice, #endif -#ifdef CONFIG_SPI_FLASH_PUYA - /* Puya Semiconductor (Shanghai) Co., Ltd */ - { INFO - ("p25q05h", 0x856010, 0, 64 * 1024, 1, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q10h", 0x856011, 0, 64 * 1024, 2, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q20h", 0x856012, 0, 64 * 1024, 4, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q40h", 0x856013, 0, 64 * 1024, 8, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q80h", 0x856014, 0, 64 * 1024, 16, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q16h", 0x856015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q32h", 0x856016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q64h", 0x856017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q128h", 0x856018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("py25f512hb", 0x85231a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO - ("py25f01ghb", 0x85231b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO - ("py25f512lc", 0x85631a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO - ("py25f01glc", 0x85631b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_ISSI)) + &spi_nor_issi, #endif - -#ifdef CONFIG_SPI_FLASH_SILICONKAISER - { INFO("sk25lp128", 0x257018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_MACRONIX)) + &spi_nor_macronix, #endif - -#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - /* Micron */ - { INFO("n25q016a", 0x20bb15, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_QUAD_READ) }, - { INFO("n25q032", 0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, - { INFO("n25q032a", 0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, - { INFO("n25q064", 0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, - { INFO("n25q064a", 0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, - { INFO("n25q128a11", 0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, - { INFO("n25q128a13", 0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, - { INFO6("mt25ql256a", 0x20ba19, 0x104400, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) }, - { INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_FSR) }, - { INFO6("mt25qu256a", 0x20bb19, 0x104400, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) }, - { INFO("n25q256ax1", 0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | USE_FSR) }, - { INFO("mt25qu128ab", 0x20bb18, 0, 64 * 1024, 256, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, - { INFO6("mt25qu512a", 0x20bb20, 0x104400, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | - USE_FSR) }, - { INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, - { INFO6("mt25ql512a", 0x20ba20, 0x104400, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, - { INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, - { INFO("n25q00a", 0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, - { INFO("mt25ql01g", 0x21ba20, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, - { INFO6("mt25qu01g", 0x20bb21, 0x104400, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE | SPI_NOR_4B_OPCODES) }, - { INFO("mt25qu02g", 0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, - { INFO("mt25ql02g", 0x20ba22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE | SPI_NOR_4B_OPCODES) }, -#ifdef CONFIG_SPI_FLASH_MT35XU - { INFO("mt35xl512aba", 0x2c5a1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ) }, - { INFO("mt35xu512aba", 0x2c5b1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ) }, - { INFO("mt35xu01gaba", 0x2c5b1b, 0, 128 * 1024, 1024, - USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, -#endif /* CONFIG_SPI_FLASH_MT35XU */ - { INFO6("mt35xu01g", 0x2c5b1b, 0x104100, 128 * 1024, 1024, - USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, - { INFO("mt35xu02g", 0x2c5b1c, 0, 128 * 1024, 2048, - USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_PUYA)) + &spi_nor_puya, #endif -#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ - /* Spansion/Cypress -- single (large) sector size only, at least - * for the chips listed here (without boot sectors). - */ - { INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO6("s25fl256s0", 0x010219, 0x4d0080, 256 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fl256s1", 0x010219, 0x4d0180, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fl512s", 0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fs064s", 0x010217, 0x4d0181, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fs128s", 0x012018, 0x4d0181, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fs256s", 0x010219, 0x4d0181, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fs512s", 0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl512s_256k", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl512s_64k", 0x010220, 0x4d01, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl512s_512k", 0x010220, 0x4f00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s70fs01gs_256k", 0x010221, 0x4d00, 256 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, 0) }, - { INFO("s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, 0) }, - { INFO6("s25fl128s", 0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25sl008a", 0x010213, 0, 64 * 1024, 16, 0) }, - { INFO("s25sl016a", 0x010214, 0, 64 * 1024, 32, 0) }, - { INFO("s25sl032a", 0x010215, 0, 64 * 1024, 64, 0) }, - { INFO("s25sl064a", 0x010216, 0, 64 * 1024, 128, 0) }, - { INFO("s25fl116k", 0x014015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("s25fl164k", 0x014017, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("s25fl208k", 0x014014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) }, - { INFO("s25fl064l", 0x016017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("s25fl128l", 0x016018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("s25fl256l", 0x016019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO6("s25hl512t", 0x342a1a, 0x0f0390, 256 * 1024, 256, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | - USE_CLSR) }, - { INFO6("s25hl01gt", 0x342a1b, 0x0f0390, 256 * 1024, 512, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | - USE_CLSR) }, - { INFO6("s25hl02gt", 0x342a1c, 0x0f0090, 256 * 1024, 1024, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, - { INFO6("s25hs512t", 0x342b1a, 0x0f0390, 256 * 1024, 256, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | - USE_CLSR) }, - { INFO6("s25hs01gt", 0x342b1b, 0x0f0390, 256 * 1024, 512, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | - USE_CLSR) }, - { INFO6("s25hs02gt", 0x342b1c, 0x0f0090, 256 * 1024, 1024, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, - { INFO6("s25fs256t", 0x342b19, 0x0f0890, 128 * 1024, 256, - SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, -#ifdef CONFIG_SPI_FLASH_S28HX_T - { INFO("s28hl256t", 0x345a19, 0, 256 * 1024, 128, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hl512t", 0x345a1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hl01gt", 0x345a1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hl02gt", 0x345a1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ | NO_CHIP_ERASE) }, - { INFO("s28hs256t", 0x345b19, 0, 256 * 1024, 128, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hs512t", 0x345b1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hs01gt", 0x345b1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hs02gt", 0x345b1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ | NO_CHIP_ERASE) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_SILICONKAISER)) + &spi_nor_siliconkaiser, #endif +#if (IS_ENABLED(CONFIG_SPI_FLASH_STMICRO)) + &spi_nor_micron, + &spi_nor_st, #endif -#ifdef CONFIG_SPI_FLASH_SST /* SST */ - /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - { INFO("sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, - { INFO("sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, - { INFO("sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) }, - { INFO("sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) }, - { INFO("sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, - { INFO("sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, - { INFO("sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, - { INFO("sst25wf020a", 0x621612, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("sst25wf040b", 0x621613, 0, 64 * 1024, 8, SECT_4K) }, - { INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, - { INFO("sst25wf080", 0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, - { INFO("sst26vf064b", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("sst26wf016b", 0xbf2641, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("sst26wf016", 0xbf2651, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, - { INFO("sst26wf032", 0xbf2622, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, - { INFO("sst26wf064", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_SPANSION)) + &spi_nor_spansion, #endif -#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - /* STMicroelectronics -- newer production may have feature updates */ - { INFO("m25p10", 0x202011, 0, 32 * 1024, 4, 0) }, - { INFO("m25p20", 0x202012, 0, 64 * 1024, 4, 0) }, - { INFO("m25p40", 0x202013, 0, 64 * 1024, 8, 0) }, - { INFO("m25p80", 0x202014, 0, 64 * 1024, 16, 0) }, - { INFO("m25p16", 0x202015, 0, 64 * 1024, 32, 0) }, - { INFO("m25p32", 0x202016, 0, 64 * 1024, 64, 0) }, - { INFO("m25p64", 0x202017, 0, 64 * 1024, 128, 0) }, - { INFO("m25p128", 0x202018, 0, 256 * 1024, 64, 0) }, - { INFO("m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("m25px16", 0x207115, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_SST)) + &spi_nor_sst, #endif -#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ - /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ - { INFO("w25p80", 0xef2014, 0x0, 64 * 1024, 16, 0) }, - { INFO("w25p16", 0xef2015, 0x0, 64 * 1024, 32, 0) }, - { INFO("w25p32", 0xef2016, 0x0, 64 * 1024, 64, 0) }, - { INFO("w25x05", 0xef3010, 0, 64 * 1024, 1, SECT_4K) }, - { INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K) }, - { INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("w25q20cl", 0xef4012, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("w25q20bw", 0xef5012, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("w25q20ew", 0xef6012, 0, 64 * 1024, 4, SECT_4K) }, - { - INFO("w25q16dw", 0xef6015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q16jv", 0xef7015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) - }, - { - INFO("w25q32jv", 0xef7016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q32jwm", 0xef8016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q256jwm", 0xef8019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K) }, - { - INFO("w25q64dw", 0xef6017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q64jv", 0xef7017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q128fw", 0xef6018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q128jv", 0xef7018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q128jw", 0xef8018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q256fw", 0xef6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q256jw", 0xef7019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q512nwq", 0xef6020, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q512nwm", 0xef8020, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q512jvq", 0xef4020, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q01jv", 0xef4021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q01jvfim", 0xef7021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q02jv", 0xef7022, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K) }, - { INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { - INFO("w25q16cl", 0xef4015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q64cv", 0xef4017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25m512jw", 0xef6119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25m512jv", 0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25h02jv", 0xef9022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25h512nw-am", 0xefa020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25h01nw-am", 0xefa021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25h02nw-am", 0xefa022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q01nw-iq", 0xef6021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q01nw-im", 0xef8021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q02nw-im", 0xef8022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w77q51nw", 0xef8a1a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_WINBOND)) + &spi_nor_winbond, #endif -#ifdef CONFIG_SPI_FLASH_XMC - /* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */ - { INFO("XM25QH64A", 0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("XM25QH64C", 0x204017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("XM25QH128A", 0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("XM25QH128C", 0x204018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("XM25QU128C", 0x204118, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("XM25QH256C", 0x204019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("XM25QU256C", 0x204119, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("XM25QH512C", 0x204020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("XM25QU512C", 0x204120, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("XM25QH01D", 0x204021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_XMC)) + &spi_nor_xmc, #endif -#ifdef CONFIG_SPI_FLASH_XTX - /* XTX Technology Limited */ - /* adding these 3V QSPI flash parts */ - { INFO("xt25f08", 0x0b4014, 0, 64 * 1024, 16, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25f16", 0x0b4015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25f32", 0x0b4016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25f64", 0x0b4017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25f128", 0x0b4018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25f256", 0x0b4019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - /* adding these 1.8V QSPI flash parts */ - { INFO("xt25q08", 0x0b6014, 0, 64 * 1024, 16, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25q16", 0x0b6015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25q32", 0x0b6016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25q64", 0x0b6017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25q128", 0x0b6018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25q256", 0x0b6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("xt25q512", 0x0b601A, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("xt25q01g", 0x0b601B, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("xt55q02g", 0x0b601C, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - /* adding these wide voltage QSPI flash parts */ - { INFO("xt25w512", 0x0b651A, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("xt25w01g", 0x0b651B, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_XTX)) + &spi_nor_xtx, #endif -#ifdef CONFIG_SPI_FLASH_ZBIT - /* Zbit Semiconductor Inc. */ - { INFO("zb25vq128", 0x5e4018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_ZBIT)) + &spi_nor_zbit, #endif - { }, -}; - -const struct spi_nor_manufacturer *manufacturers[] = { NULL /* sentinel */ }; diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index cf00473ee83..0df78483ccb 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -383,13 +383,10 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) return ERR_PTR(tmp); } - info = spi_nor_ids; - for (; info->sector_size != 0; info++) { - if (info->id_len) { - if (!memcmp(info->id, id, info->id_len)) - return info; - } - } + info = spi_nor_match_id(nor, id); + if (info) + return info; + dev_dbg(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n", id[0], id[1], id[2]); return ERR_PTR(-EMEDIUMTYPE); diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c new file mode 100644 index 00000000000..e169dba663a --- /dev/null +++ b/drivers/mtd/spi/sst.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info sst_nor_parts[] = { + { INFO("sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + { INFO("sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, + { INFO("sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) }, + { INFO("sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) }, + { INFO("sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, + { INFO("sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, + { INFO("sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, + { INFO("sst25wf020a", 0x621612, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("sst25wf040b", 0x621613, 0, 64 * 1024, 8, SECT_4K) }, + { INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + { INFO("sst25wf080", 0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, + { INFO("sst26vf064b", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("sst26wf016b", 0xbf2641, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("sst26wf016", 0xbf2651, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, + { INFO("sst26wf032", 0xbf2622, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, + { INFO("sst26wf064", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, +}; + +const struct spi_nor_manufacturer spi_nor_sst = { + .parts = sst_nor_parts, + .nparts = ARRAY_SIZE(sst_nor_parts), +}; diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c new file mode 100644 index 00000000000..02c29ccf78c --- /dev/null +++ b/drivers/mtd/spi/winbond.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info winbond_nor_parts[] = { + { INFO("w25p80", 0xef2014, 0x0, 64 * 1024, 16, 0) }, + { INFO("w25p16", 0xef2015, 0x0, 64 * 1024, 32, 0) }, + { INFO("w25p32", 0xef2016, 0x0, 64 * 1024, 64, 0) }, + { INFO("w25x05", 0xef3010, 0, 64 * 1024, 1, SECT_4K) }, + { INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K) }, + { INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("w25q20cl", 0xef4012, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("w25q20bw", 0xef5012, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("w25q20ew", 0xef6012, 0, 64 * 1024, 4, SECT_4K) }, + { + INFO("w25q16dw", 0xef6015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q16jv", 0xef7015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) + }, + { + INFO("w25q32jv", 0xef7016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q32jwm", 0xef8016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q256jwm", 0xef8019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K) }, + { + INFO("w25q64dw", 0xef6017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q64jv", 0xef7017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q128fw", 0xef6018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q128jv", 0xef7018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q128jw", 0xef8018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q256fw", 0xef6019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q256jw", 0xef7019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q512nwq", 0xef6020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q512nwm", 0xef8020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q512jvq", 0xef4020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q01jv", 0xef4021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q01jvfim", 0xef7021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q02jv", 0xef7022, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K) }, + { INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { + INFO("w25q16cl", 0xef4015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q64cv", 0xef4017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25m512jw", 0xef6119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25m512jv", 0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h02jv", 0xef9022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h512nw-am", 0xefa020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h01nw-am", 0xefa021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h02nw-am", 0xefa022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q01nw-iq", 0xef6021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q01nw-im", 0xef8021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q02nw-im", 0xef8022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w77q51nw", 0xef8a1a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_winbond = { + .parts = winbond_nor_parts, + .nparts = ARRAY_SIZE(winbond_nor_parts), +}; diff --git a/drivers/mtd/spi/xmc.c b/drivers/mtd/spi/xmc.c new file mode 100644 index 00000000000..8356f3da2d2 --- /dev/null +++ b/drivers/mtd/spi/xmc.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info xmc_nor_parts[] = { + { INFO("XM25QH64A", 0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("XM25QH64C", 0x204017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("XM25QH128A", 0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("XM25QH128C", 0x204018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("XM25QU128C", 0x204118, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("XM25QH256C", 0x204019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("XM25QU256C", 0x204119, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("XM25QH512C", 0x204020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("XM25QU512C", 0x204120, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("XM25QH01D", 0x204021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_xmc = { + .parts = xmc_nor_parts, + .nparts = ARRAY_SIZE(xmc_nor_parts), +}; diff --git a/drivers/mtd/spi/xtx.c b/drivers/mtd/spi/xtx.c new file mode 100644 index 00000000000..e49b1ceb76d --- /dev/null +++ b/drivers/mtd/spi/xtx.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info xtx_nor_parts[] = { + /* adding these 3V QSPI flash parts */ + { INFO("xt25f08", 0x0b4014, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25f16", 0x0b4015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25f32", 0x0b4016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25f64", 0x0b4017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25f128", 0x0b4018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25f256", 0x0b4019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + /* adding these 1.8V QSPI flash parts */ + { INFO("xt25q08", 0x0b6014, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25q16", 0x0b6015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25q32", 0x0b6016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25q64", 0x0b6017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25q128", 0x0b6018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25q256", 0x0b6019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("xt25q512", 0x0b601A, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("xt25q01g", 0x0b601B, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("xt55q02g", 0x0b601C, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + /* adding these wide voltage QSPI flash parts */ + { INFO("xt25w512", 0x0b651A, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("xt25w01g", 0x0b651B, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_xtx = { + .parts = xtx_nor_parts, + .nparts = ARRAY_SIZE(xtx_nor_parts), +}; diff --git a/drivers/mtd/spi/zbit.c b/drivers/mtd/spi/zbit.c new file mode 100644 index 00000000000..ee709b2bef1 --- /dev/null +++ b/drivers/mtd/spi/zbit.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info zbit_nor_parts[] = { + { INFO("zb25vq128", 0x5e4018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +}; + +const struct spi_nor_manufacturer spi_nor_zbit = { + .parts = zbit_nor_parts, + .nparts = ARRAY_SIZE(zbit_nor_parts), +}; -- 2.53.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 3/4] mtd: spi-nor: move flash info entries to manufacturer drivers @ 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay 0 siblings, 0 replies; 15+ messages in thread From: Takahiro Kuwano via B4 Relay @ 2026-10-16 1:43 UTC (permalink / raw) To: u-boot Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev, Takahiro Kuwano From: Takahiro Kuwano <takahiro.kuwano@infineon.com> Create manufacturer driver files and move flash info entries into them. Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com> --- drivers/mtd/spi/Makefile | 17 + drivers/mtd/spi/atmel.c | 28 ++ drivers/mtd/spi/dosilicon.c | 25 ++ drivers/mtd/spi/eon.c | 23 ++ drivers/mtd/spi/fujitsu.c | 27 ++ drivers/mtd/spi/gigadevice.c | 140 ++++++++ drivers/mtd/spi/issi.c | 84 +++++ drivers/mtd/spi/macronix.c | 65 ++++ drivers/mtd/spi/micron-st.c | 70 ++++ drivers/mtd/spi/puya.c | 56 +++ drivers/mtd/spi/sandbox.c | 33 +- drivers/mtd/spi/sf_internal.h | 57 +++- drivers/mtd/spi/siliconkaiser.c | 18 + drivers/mtd/spi/spansion.c | 73 ++++ drivers/mtd/spi/spi-nor-core.c | 10 +- drivers/mtd/spi/spi-nor-ids.c | 737 ++-------------------------------------- drivers/mtd/spi/spi-nor-tiny.c | 11 +- drivers/mtd/spi/sst.c | 34 ++ drivers/mtd/spi/winbond.c | 146 ++++++++ drivers/mtd/spi/xmc.c | 27 ++ drivers/mtd/spi/xtx.c | 54 +++ drivers/mtd/spi/zbit.c | 19 ++ 22 files changed, 1027 insertions(+), 727 deletions(-) diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 1828e5fadfe..74fe9b49a69 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -17,6 +17,23 @@ spi-nor-y += spi-nor-core.o spi-nor-$(CONFIG_SPI_FLASH_SFDP_SUPPORT) += sfdp.o endif +spi-nor-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o +spi-nor-$(CONFIG_SPI_FLASH_DOSILICON) += dosilicon.o +spi-nor-$(CONFIG_SPI_FLASH_EON) += eon.o +spi-nor-$(CONFIG_SPI_FRAM_FUJITSU) += fujitsu.o +spi-nor-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.o +spi-nor-$(CONFIG_SPI_FLASH_ISSI) += issi.o +spi-nor-$(CONFIG_SPI_FLASH_MACRONIX) += macronix.o +spi-nor-$(CONFIG_SPI_FLASH_PUYA) += puya.o +spi-nor-$(CONFIG_SPI_FLASH_SILICONKAISER) += siliconkaiser.o +spi-nor-$(CONFIG_SPI_FLASH_STMICRO) += micron-st.o +spi-nor-$(CONFIG_SPI_FLASH_SPANSION) += spansion.o +spi-nor-$(CONFIG_SPI_FLASH_SST) += sst.o +spi-nor-$(CONFIG_SPI_FLASH_WINBOND) += winbond.o +spi-nor-$(CONFIG_SPI_FLASH_XMC) += xmc.o +spi-nor-$(CONFIG_SPI_FLASH_XTX) += xtx.o +spi-nor-$(CONFIG_SPI_FLASH_ZBIT) += zbit.o + obj-$(CONFIG_SPI_FLASH) += spi-nor.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o obj-$(CONFIG_$(PHASE_)SPI_FLASH_MTD) += sf_mtd.o diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c new file mode 100644 index 00000000000..53c7afff323 --- /dev/null +++ b/drivers/mtd/spi/atmel.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info atmel_nor_parts[] = { + { INFO("at26df321", 0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("at25df321a", 0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("at45db011d", 0x1f2200, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("at45db021d", 0x1f2300, 0, 64 * 1024, 8, SECT_4K) }, + { INFO("at45db041d", 0x1f2400, 0, 64 * 1024, 8, SECT_4K) }, + { INFO("at45db081d", 0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, + { INFO("at45db161d", 0x1f2600, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("at45db321d", 0x1f2700, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("at45db641d", 0x1f2800, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("at25sl321", 0x1f4216, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, +}; + +const struct spi_nor_manufacturer spi_nor_atmel = { + .parts = atmel_nor_parts, + .nparts = ARRAY_SIZE(atmel_nor_parts), +}; diff --git a/drivers/mtd/spi/dosilicon.c b/drivers/mtd/spi/dosilicon.c new file mode 100644 index 00000000000..1c889960656 --- /dev/null +++ b/drivers/mtd/spi/dosilicon.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info dosilicon_nor_parts[] = { + { INFO("ds25m4cb", 0xe5401a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("ds25m4dn", 0xe5401b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("ds25q4cb", 0xe5301a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("ds25q4dn", 0xe5301b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_dosilicon = { + .parts = dosilicon_nor_parts, + .nparts = ARRAY_SIZE(dosilicon_nor_parts), +}; diff --git a/drivers/mtd/spi/eon.c b/drivers/mtd/spi/eon.c new file mode 100644 index 00000000000..6690ba2a1da --- /dev/null +++ b/drivers/mtd/spi/eon.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info eon_nor_parts[] = { + { INFO("en25q80b", 0x1c3014, 0, 64 * 1024, 16, SECT_4K) }, + { INFO("en25q32b", 0x1c3016, 0, 64 * 1024, 64, 0) }, + { INFO("en25q64", 0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("en25q128b", 0x1c3018, 0, 64 * 1024, 256, 0) }, + { INFO("en25qh128", 0x1c7018, 0, 64 * 1024, 256, 0) }, + { INFO("en25s64", 0x1c3817, 0, 64 * 1024, 128, SECT_4K) }, +}; + +const struct spi_nor_manufacturer spi_nor_eon = { + .parts = eon_nor_parts, + .nparts = ARRAY_SIZE(eon_nor_parts), +}; diff --git a/drivers/mtd/spi/fujitsu.c b/drivers/mtd/spi/fujitsu.c new file mode 100644 index 00000000000..3d5328b1815 --- /dev/null +++ b/drivers/mtd/spi/fujitsu.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info fujitsu_nor_parts[] = { + { + INFO_NAME("mb85rs256ty") + .id = {0x04, 0x7f, 0x25, 0x00, 0x00}, + .id_len = 3, + .sector_size = 32 * 1024, + .n_sectors = 1, + .page_size = 32 * 1024, /* Whole chip can be written at once */ + .flags = SPI_NOR_NO_ERASE, + .addr_width = 2, + }, +}; + +const struct spi_nor_manufacturer spi_nor_fujitsu = { + .parts = fujitsu_nor_parts, + .nparts = ARRAY_SIZE(fujitsu_nor_parts), +}; diff --git a/drivers/mtd/spi/gigadevice.c b/drivers/mtd/spi/gigadevice.c new file mode 100644 index 00000000000..895d97f5f9b --- /dev/null +++ b/drivers/mtd/spi/gigadevice.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info gigadevice_nor_parts[] = { + { + INFO("gd25q16", 0xc84015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25q32", 0xc84016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25lq32", 0xc86016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25q64", 0xc84017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25lq64c", 0xc86017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25q128", 0xc84018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + /* adding these 3V QSPI flash parts */ + {INFO("gd25b256", 0xc84019, 0, 64 * 1024, 512, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES) }, + {INFO("gd25b512", 0xc8471A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55b01g", 0xc8471B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55b02g", 0xc8471C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25f64", 0xc84317, 0, 64 * 1024, 128, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, + {INFO("gd25f128", 0xc84318, 0, 64 * 1024, 256, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, + {INFO("gd25f256", 0xc84319, 0, 64 * 1024, 512, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55f512", 0xc8431A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25t512", 0xc8461A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55t01g", 0xc8461B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55t02g", 0xc8461C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + /* adding these 3V OSPI flash parts */ + {INFO("gd25x512", 0xc8481A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + {INFO("gd55x01g", 0xc8481B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + {INFO("gd55x02g", 0xc8481C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + { + INFO("gd25lq128", 0xc86018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd25lq256d", 0xc86019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + /* adding these 1.8V QSPI flash parts */ + {INFO("gd25lb256", 0xc86719, 0, 64 * 1024, 512, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lb512", 0xc8671A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lb01g", 0xc8671B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lb02g", 0xc8671C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lf80", 0xc86314, 0, 64 * 1024, 16, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, + {INFO("gd25lf16", 0xc86315, 0, 64 * 1024, 32, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, + {INFO("gd25lf32", 0xc86316, 0, 64 * 1024, 64, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, + {INFO("gd25lf64", 0xc86317, 0, 64 * 1024, 128, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, + {INFO("gd25lf128", 0xc86318, 0, 64 * 1024, 256, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, + {INFO("gd25lf255", 0xc86319, 0, 64 * 1024, 512, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lf511", 0xc8631A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lt256", 0xc86619, 0, 64 * 1024, 512, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lt512", 0xc8661A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lt01g", 0xc8661B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lt02g", 0xc8661C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, + {INFO("gd25lx128j", 0xc86818, 0, 64 * 1024, 256, SECT_4K | + SPI_NOR_OCTAL_READ)}, + { + INFO("gd25lx256e", 0xc86819, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) + }, + /* adding these 1.8V OSPI flash parts */ + {INFO("gd25lx512", 0xc8681A, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lx01g", 0xc8681B, 0, 64 * 1024, 2048, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + {INFO("gd55lx02g", 0xc8681C, 0, 64 * 1024, 4096, SECT_4K | + SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, + { + INFO("gd55lb02ge", 0xc8671c, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("gd55lb02gf", 0xc8601c, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) + }, +}; + +const struct spi_nor_manufacturer spi_nor_gigadevice = { + .parts = gigadevice_nor_parts, + .nparts = ARRAY_SIZE(gigadevice_nor_parts), +}; diff --git a/drivers/mtd/spi/issi.c b/drivers/mtd/spi/issi.c new file mode 100644 index 00000000000..2537ca811f8 --- /dev/null +++ b/drivers/mtd/spi/issi.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info issi_nor_parts[] = { + { INFO("is25lq040b", 0x9d4013, 0, 64 * 1024, 8, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp008", 0x9d6014, 0, 64 * 1024, 16, SPI_NOR_QUAD_READ) }, + { INFO("is25lp016", 0x9d6015, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ) }, + { INFO("is25lp032", 0x9d6016, 0, 64 * 1024, 64, 0) }, + { INFO("is25lp064", 0x9d6017, 0, 64 * 1024, 128, 0) }, + { INFO("is25lp128", 0x9d6018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ) }, + { INFO("is25lp256", 0x9d6019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ) }, + { INFO("is25lp512", 0x9d601a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp512mj", 0x9d6020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp01g", 0x9d601b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp008", 0x9d7014, 0, 64 * 1024, 16, SPI_NOR_QUAD_READ) }, + { INFO("is25wp016", 0x9d7015, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ) }, + { INFO("is25wp032", 0x9d7016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp064", 0x9d7017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp128", 0x9d7018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp256", 0x9d7019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_4B_OPCODES) }, + { INFO("is25wp512", 0x9d701a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp512mj", 0x9d7020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp01g", 0x9d701b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wp01gg", 0x9d7021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25wx128", 0x9d5b18, 0, 64 * 1024, 256, + SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ) }, + { INFO("is25wx256", 0x9d5b19, 0, 128 * 1024, 256, + SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, + { INFO("is25lx128", 0x9d5a18, 0, 64 * 1024, 256, + SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ) }, + { INFO("is25lx512", 0x9d5a1a, 0, 64 * 1024, 1024, + SECT_4K | USE_FSR | SPI_NOR_4B_OPCODES | SPI_NOR_HAS_TB) }, + { INFO("is25lp01gg", 0x9d6021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25lp010e", 0x9d4011, 0, 64 * 1024, 2, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp020e", 0x9d4012, 0, 64 * 1024, 4, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp040e", 0x9d4013, 0, 64 * 1024, 8, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lp01gj", 0x9d6021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25lp02gg", 0x9d6022, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25lp02gj", 0x9d6022, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25wp01gg", 0x9d7021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25wp01gj", 0x9d7021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25wj128f", 0x9d7118, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25wp02gg", 0x9d7022, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, + { INFO("is25wp02gj", 0x9d7022, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, +}; + +const struct spi_nor_manufacturer spi_nor_issi = { + .parts = issi_nor_parts, + .nparts = ARRAY_SIZE(issi_nor_parts), +}; diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c new file mode 100644 index 00000000000..87843978cad --- /dev/null +++ b/drivers/mtd/spi/macronix.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info macronix_nor_parts[] = { + { INFO("mx25l2005a", 0xc22012, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("mx25l4005a", 0xc22013, 0, 64 * 1024, 8, SECT_4K) }, + { INFO("mx25l8005", 0xc22014, 0, 64 * 1024, 16, 0) }, + { INFO("mx25l1606e", 0xc22015, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("mx25l3205d", 0xc22016, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("mx25l6405d", 0xc22017, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("mx25u2033e", 0xc22532, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("mx25u1635e", 0xc22535, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("mx25u3235f", 0xc22536, 0, 4 * 1024, 1024, SECT_4K) }, + { INFO("mx25u6435f", 0xc22537, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, SECT_4K) }, + { INFO("mx25u12835f", 0xc22538, 0, 64 * 1024, 256, SECT_4K | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("mx25u51245g", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0) }, + { INFO("mx25l25635e", 0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("mx25u25635f", 0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, + { INFO("mx25v8035f", 0xc22314, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("mx25r1635f", 0xc22815, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0) }, + { INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66u51235f", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25u51245f", 0xc2953a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66u1g45g", 0xc2253b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66u2g45g", 0xc2253c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66l1g45g", 0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("mx66l2g45g", 0xc2201c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25l1633e", 0xc22415, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SECT_4K) }, + { INFO("mx25r6435f", 0xc22817, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("mx66uw2g345gx0", 0xc2943c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_READ) }, + { INFO("mx66lm1g45g", 0xc2853b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25lm51245g", 0xc2853a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25lw51245g", 0xc2863a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25lm25645g", 0xc28539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66uw2g345g", 0xc2843c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66um1g45g", 0xc2803b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx66uw1g45g", 0xc2813b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw51245g", 0xc2813a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw51345g", 0xc2843a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25um25645g", 0xc28039, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw25645g", 0xc28139, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25um25345g", 0xc28339, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw25345g", 0xc28439, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw12845g", 0xc28138, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw12345g", 0xc28438, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw6445g", 0xc28137, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, + { INFO("mx25uw6345g", 0xc28437, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_macronix = { + .parts = macronix_nor_parts, + .nparts = ARRAY_SIZE(macronix_nor_parts), +}; diff --git a/drivers/mtd/spi/micron-st.c b/drivers/mtd/spi/micron-st.c new file mode 100644 index 00000000000..2d47f1c60c0 --- /dev/null +++ b/drivers/mtd/spi/micron-st.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info micron_nor_parts[] = { + { INFO("n25q016a", 0x20bb15, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_QUAD_READ) }, + { INFO("n25q032", 0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, + { INFO("n25q032a", 0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, + { INFO("n25q064", 0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, + { INFO("n25q064a", 0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, + { INFO("n25q128a11", 0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, + { INFO("n25q128a13", 0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, + { INFO6("mt25ql256a", 0x20ba19, 0x104400, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) }, + { INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_FSR) }, + { INFO6("mt25qu256a", 0x20bb19, 0x104400, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) }, + { INFO("n25q256ax1", 0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | USE_FSR) }, + { INFO("mt25qu128ab", 0x20bb18, 0, 64 * 1024, 256, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { INFO6("mt25qu512a", 0x20bb20, 0x104400, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_FSR) }, + { INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { INFO6("mt25ql512a", 0x20ba20, 0x104400, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { INFO("n25q00a", 0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { INFO("mt25ql01g", 0x21ba20, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { INFO6("mt25qu01g", 0x20bb21, 0x104400, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE | SPI_NOR_4B_OPCODES) }, + { INFO("mt25qu02g", 0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { INFO("mt25ql02g", 0x20ba22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE | SPI_NOR_4B_OPCODES) }, +#ifdef CONFIG_SPI_FLASH_MT35XU + { INFO("mt35xl512aba", 0x2c5a1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ) }, + { INFO("mt35xu512aba", 0x2c5b1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ) }, + { INFO("mt35xu01gaba", 0x2c5b1b, 0, 128 * 1024, 1024, + USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, +#endif /* CONFIG_SPI_FLASH_MT35XU */ + { INFO6("mt35xu01g", 0x2c5b1b, 0x104100, 128 * 1024, 1024, + USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, + { INFO("mt35xu02g", 0x2c5b1c, 0, 128 * 1024, 2048, + USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, +}; + +static const struct flash_info st_nor_parts[] = { + { INFO("m25p10", 0x202011, 0, 32 * 1024, 4, 0) }, + { INFO("m25p20", 0x202012, 0, 64 * 1024, 4, 0) }, + { INFO("m25p40", 0x202013, 0, 64 * 1024, 8, 0) }, + { INFO("m25p80", 0x202014, 0, 64 * 1024, 16, 0) }, + { INFO("m25p16", 0x202015, 0, 64 * 1024, 32, 0) }, + { INFO("m25p32", 0x202016, 0, 64 * 1024, 64, 0) }, + { INFO("m25p64", 0x202017, 0, 64 * 1024, 128, 0) }, + { INFO("m25p128", 0x202018, 0, 256 * 1024, 64, 0) }, + { INFO("m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("m25px16", 0x207115, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0) }, +}; + +const struct spi_nor_manufacturer spi_nor_micron = { + .parts = micron_nor_parts, + .nparts = ARRAY_SIZE(micron_nor_parts), +}; + +const struct spi_nor_manufacturer spi_nor_st = { + .parts = st_nor_parts, + .nparts = ARRAY_SIZE(st_nor_parts), +}; diff --git a/drivers/mtd/spi/puya.c b/drivers/mtd/spi/puya.c new file mode 100644 index 00000000000..37092945dfc --- /dev/null +++ b/drivers/mtd/spi/puya.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info puya_nor_parts[] = { + { INFO + ("p25q05h", 0x856010, 0, 64 * 1024, 1, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q10h", 0x856011, 0, 64 * 1024, 2, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q20h", 0x856012, 0, 64 * 1024, 4, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q40h", 0x856013, 0, 64 * 1024, 8, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q80h", 0x856014, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q16h", 0x856015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q32h", 0x856016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q64h", 0x856017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q128h", 0x856018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("py25f512hb", 0x85231a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO + ("py25f01ghb", 0x85231b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO + ("py25f512lc", 0x85631a, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO + ("py25f01glc", 0x85631b, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_puya = { + .parts = puya_nor_parts, + .nparts = ARRAY_SIZE(puya_nor_parts), +}; diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index e5ebc3479fb..44d8509cd64 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -110,6 +110,27 @@ void sandbox_sf_set_block_protect(struct udevice *dev, int bp_mask) sbsf->status |= bp_mask << STAT_BP_SHIFT; } +static const struct flash_info *spi_nor_match_name(const char *name, + size_t name_len) +{ + const struct flash_info *part; + unsigned int i, j; + size_t len; + + for (i = 0; manufacturers[i]; i++) { + for (j = 0; j < manufacturers[i]->nparts; j++) { + part = &manufacturers[i]->parts[j]; + len = strlen(part->name); + if (name_len != len) + continue; + if (!strncasecmp(name, part->name, len)) + return part; + } + } + + return NULL; +} + /** * 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 @@ -119,7 +140,7 @@ static int sandbox_sf_probe(struct udevice *dev) { /* spec = idcode:file */ struct sandbox_spi_flash *sbsf = dev_get_priv(dev); - size_t len, idname_len; + size_t idname_len; const struct flash_info *data; struct sandbox_spi_flash_plat_data *pdata = dev_get_plat(dev); struct sandbox_state *state = state_get_current(); @@ -153,14 +174,8 @@ static int sandbox_sf_probe(struct udevice *dev) idname_len = strlen(spec); debug("%s: device='%s'\n", __func__, spec); - for (data = spi_nor_ids; data->name; data++) { - len = strlen(data->name); - if (idname_len != len) - continue; - if (!strncasecmp(spec, data->name, len)) - break; - } - if (!data->name) { + data = spi_nor_match_name(spec, idname_len); + if (!data) { printf("%s: unknown flash '%*s'\n", __func__, (int)idname_len, spec); ret = -EINVAL; diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index bc69af94aca..f96895c7439 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -97,6 +97,45 @@ struct flash_info { #define SPI_NOR_OCTAL_DTR_READ BIT(17) /* Flash supports Octal DTR Read */ }; +/* Exclude chip names for SPL to save space */ +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) +#define INFO_NAME(_name) .name = _name, +#else +#define INFO_NAME(_name) +#endif + +/* Used when the "_ext_id" is two bytes at most */ +#define INFO(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ + INFO_NAME(_name) \ + .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(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ + INFO_NAME(_name) \ + .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), + /** * struct spi_nor_manufacturer - SPI NOR manufacturer object * @parts: array of parts supported by this manufacturer @@ -114,7 +153,23 @@ struct spi_nor_manufacturer { }; extern const struct spi_nor_manufacturer *manufacturers[]; -extern const struct flash_info spi_nor_ids[]; +extern const struct spi_nor_manufacturer spi_nor_atmel; +extern const struct spi_nor_manufacturer spi_nor_dosilicon; +extern const struct spi_nor_manufacturer spi_nor_eon; +extern const struct spi_nor_manufacturer spi_nor_fujitsu; +extern const struct spi_nor_manufacturer spi_nor_gigadevice; +extern const struct spi_nor_manufacturer spi_nor_issi; +extern const struct spi_nor_manufacturer spi_nor_macronix; +extern const struct spi_nor_manufacturer spi_nor_puya; +extern const struct spi_nor_manufacturer spi_nor_siliconkaiser; +extern const struct spi_nor_manufacturer spi_nor_micron; +extern const struct spi_nor_manufacturer spi_nor_st; +extern const struct spi_nor_manufacturer spi_nor_spansion; +extern const struct spi_nor_manufacturer spi_nor_sst; +extern const struct spi_nor_manufacturer spi_nor_winbond; +extern const struct spi_nor_manufacturer spi_nor_xmc; +extern const struct spi_nor_manufacturer spi_nor_xtx; +extern const struct spi_nor_manufacturer spi_nor_zbit; #define JEDEC_MFR(info) ((info)->id[0]) #define JEDEC_ID(info) (((info)->id[1]) << 8 | ((info)->id[2])) diff --git a/drivers/mtd/spi/siliconkaiser.c b/drivers/mtd/spi/siliconkaiser.c new file mode 100644 index 00000000000..23e03ff8088 --- /dev/null +++ b/drivers/mtd/spi/siliconkaiser.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info siliconkaiser_nor_parts[] = { + { INFO("sk25lp128", 0x257018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +}; + +const struct spi_nor_manufacturer spi_nor_siliconkaiser = { + .parts = siliconkaiser_nor_parts, + .nparts = ARRAY_SIZE(siliconkaiser_nor_parts), +}; diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c new file mode 100644 index 00000000000..405f5bf5e79 --- /dev/null +++ b/drivers/mtd/spi/spansion.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info spansion_nor_parts[] = { + { INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO6("s25fl256s0", 0x010219, 0x4d0080, 256 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fl256s1", 0x010219, 0x4d0180, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fl512s", 0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs064s", 0x010217, 0x4d0181, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs128s", 0x012018, 0x4d0181, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs256s", 0x010219, 0x4d0181, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs512s", 0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25fl512s_256k", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25fl512s_64k", 0x010220, 0x4d01, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25fl512s_512k", 0x010220, 0x4f00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s70fs01gs_256k", 0x010221, 0x4d00, 256 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, 0) }, + { INFO("s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, 0) }, + { INFO6("s25fl128s", 0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO("s25sl008a", 0x010213, 0, 64 * 1024, 16, 0) }, + { INFO("s25sl016a", 0x010214, 0, 64 * 1024, 32, 0) }, + { INFO("s25sl032a", 0x010215, 0, 64 * 1024, 64, 0) }, + { INFO("s25sl064a", 0x010216, 0, 64 * 1024, 128, 0) }, + { INFO("s25fl116k", 0x014015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("s25fl164k", 0x014017, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("s25fl208k", 0x014014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) }, + { INFO("s25fl064l", 0x016017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("s25fl128l", 0x016018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("s25fl256l", 0x016019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO6("s25hl512t", 0x342a1a, 0x0f0390, 256 * 1024, 256, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hl01gt", 0x342a1b, 0x0f0390, 256 * 1024, 512, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hl02gt", 0x342a1c, 0x0f0090, 256 * 1024, 1024, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, + { INFO6("s25hs512t", 0x342b1a, 0x0f0390, 256 * 1024, 256, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hs01gt", 0x342b1b, 0x0f0390, 256 * 1024, 512, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hs02gt", 0x342b1c, 0x0f0090, 256 * 1024, 1024, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, + { INFO6("s25fs256t", 0x342b19, 0x0f0890, 128 * 1024, 256, + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +#ifdef CONFIG_SPI_FLASH_S28HX_T + { INFO("s28hl256t", 0x345a19, 0, 256 * 1024, 128, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hl512t", 0x345a1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hl01gt", 0x345a1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hl02gt", 0x345a1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ | NO_CHIP_ERASE) }, + { INFO("s28hs256t", 0x345b19, 0, 256 * 1024, 128, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hs512t", 0x345b1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hs01gt", 0x345b1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hs02gt", 0x345b1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ | NO_CHIP_ERASE) }, +#endif +}; + +const struct spi_nor_manufacturer spi_nor_spansion = { + .parts = spansion_nor_parts, + .nparts = ARRAY_SIZE(spansion_nor_parts), +}; diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 205986a4464..d107828092c 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -1405,13 +1405,9 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) return ERR_PTR(tmp); } - info = spi_nor_ids; - for (; info->name; info++) { - if (info->id_len) { - if (!memcmp(info->id, id, info->id_len)) - return info; - } - } + info = spi_nor_match_id(nor, id); + if (info) + return info; dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n", id[0], id[1], id[2]); diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index e56efd3915e..d1b22f0e5da 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -11,725 +11,56 @@ #include "sf_internal.h" -/* Exclude chip names for SPL to save space */ -#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) -#define INFO_NAME(_name) .name = _name, -#else -#define INFO_NAME(_name) -#endif - -/* Used when the "_ext_id" is two bytes at most */ -#define INFO(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - INFO_NAME(_name) \ - .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(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - INFO_NAME(_name) \ - .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), - -/* NOTE: double check command sets and memory organization when you add - * more nor chips. This current list focusses on newer chips, which - * have been converging on command sets which including JEDEC ID. - * - * All newly added entries should describe *hardware* and should use SECT_4K - * (or SECT_4K_PMC) if hardware supports erasing 4 KiB sectors. For usage - * scenarios excluding small sectors there is config option that can be - * disabled: CONFIG_SPI_FLASH_USE_4K_SECTORS. - * For historical (and compatibility) reasons (before we got above config) some - * old entries may be missing 4K flag. - */ -const struct flash_info spi_nor_ids[] = { -#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ - /* Atmel -- some are (confusingly) marketed as "DataFlash" */ - { INFO("at26df321", 0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("at25df321a", 0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, - - { INFO("at45db011d", 0x1f2200, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("at45db021d", 0x1f2300, 0, 64 * 1024, 8, SECT_4K) }, - { INFO("at45db041d", 0x1f2400, 0, 64 * 1024, 8, SECT_4K) }, - { INFO("at45db081d", 0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, - { INFO("at45db161d", 0x1f2600, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("at45db321d", 0x1f2700, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("at45db641d", 0x1f2800, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("at25sl321", 0x1f4216, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, -#endif -#ifdef CONFIG_SPI_FLASH_DOSILICON - /* Dosilicon Co., Ltd */ - { INFO("ds25m4cb", 0xe5401a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("ds25m4dn", 0xe5401b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("ds25q4cb", 0xe5301a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("ds25q4dn", 0xe5301b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, -#endif -#ifdef CONFIG_SPI_FLASH_EON /* EON */ - /* EON -- en25xxx */ - { INFO("en25q80b", 0x1c3014, 0, 64 * 1024, 16, SECT_4K) }, - { INFO("en25q32b", 0x1c3016, 0, 64 * 1024, 64, 0) }, - { INFO("en25q64", 0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("en25q128b", 0x1c3018, 0, 64 * 1024, 256, 0) }, - { INFO("en25qh128", 0x1c7018, 0, 64 * 1024, 256, 0) }, - { INFO("en25s64", 0x1c3817, 0, 64 * 1024, 128, SECT_4K) }, +const struct spi_nor_manufacturer *manufacturers[] = { +#if (IS_ENABLED(CONFIG_SPI_FLASH_ATMEL)) + &spi_nor_atmel, #endif -#ifdef CONFIG_SPI_FRAM_FUJITSU - /* Fujitsu MB85RS256TY */ - { - INFO_NAME("mb85rs256ty") - .id = {0x04, 0x7f, 0x25, 0x00, 0x00}, - .id_len = 3, - .sector_size = 32 * 1024, - .n_sectors = 1, - .page_size = 32 * 1024, /* Whole chip can be written at once */ - .flags = SPI_NOR_NO_ERASE, - .addr_width = 2, - }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_DOSILICON)) + &spi_nor_dosilicon, #endif -#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ - /* GigaDevice */ - { - INFO("gd25q16", 0xc84015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25q32", 0xc84016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25lq32", 0xc86016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25q64", 0xc84017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25lq64c", 0xc86017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25q128", 0xc84018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - /* adding these 3V QSPI flash parts */ - {INFO("gd25b256", 0xc84019, 0, 64 * 1024, 512, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES) }, - {INFO("gd25b512", 0xc8471A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55b01g", 0xc8471B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55b02g", 0xc8471C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25f64", 0xc84317, 0, 64 * 1024, 128, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, - {INFO("gd25f128", 0xc84318, 0, 64 * 1024, 256, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, - {INFO("gd25f256", 0xc84319, 0, 64 * 1024, 512, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55f512", 0xc8431A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25t512", 0xc8461A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55t01g", 0xc8461B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55t02g", 0xc8461C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - /* adding these 3V OSPI flash parts */ - {INFO("gd25x512", 0xc8481A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - {INFO("gd55x01g", 0xc8481B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - {INFO("gd55x02g", 0xc8481C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - { - INFO("gd25lq128", 0xc86018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd25lq256d", 0xc86019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - /* adding these 1.8V QSPI flash parts */ - {INFO("gd25lb256", 0xc86719, 0, 64 * 1024, 512, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lb512", 0xc8671A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lb01g", 0xc8671B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lb02g", 0xc8671C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lf80", 0xc86314, 0, 64 * 1024, 16, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, - {INFO("gd25lf16", 0xc86315, 0, 64 * 1024, 32, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK)}, - {INFO("gd25lf32", 0xc86316, 0, 64 * 1024, 64, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, - {INFO("gd25lf64", 0xc86317, 0, 64 * 1024, 128, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, - {INFO("gd25lf128", 0xc86318, 0, 64 * 1024, 256, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, - {INFO("gd25lf255", 0xc86319, 0, 64 * 1024, 512, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lf511", 0xc8631A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lt256", 0xc86619, 0, 64 * 1024, 512, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lt512", 0xc8661A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lt01g", 0xc8661B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lt02g", 0xc8661C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_4B_OPCODES)}, - {INFO("gd25lx128j", 0xc86818, 0, 64 * 1024, 256, SECT_4K | - SPI_NOR_OCTAL_READ)}, - { - INFO("gd25lx256e", 0xc86819, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) - }, - /* adding these 1.8V OSPI flash parts */ - {INFO("gd25lx512", 0xc8681A, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lx01g", 0xc8681B, 0, 64 * 1024, 2048, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - {INFO("gd55lx02g", 0xc8681C, 0, 64 * 1024, 4096, SECT_4K | - SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)}, - { - INFO("gd55lb02ge", 0xc8671c, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("gd55lb02gf", 0xc8601c, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) - }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_EON)) + &spi_nor_eon, #endif -#ifdef CONFIG_SPI_FLASH_ISSI /* ISSI */ - /* ISSI */ - { INFO("is25lq040b", 0x9d4013, 0, 64 * 1024, 8, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp008", 0x9d6014, 0, 64 * 1024, 16, SPI_NOR_QUAD_READ) }, - { INFO("is25lp016", 0x9d6015, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ) }, - { INFO("is25lp032", 0x9d6016, 0, 64 * 1024, 64, 0) }, - { INFO("is25lp064", 0x9d6017, 0, 64 * 1024, 128, 0) }, - { INFO("is25lp128", 0x9d6018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ) }, - { INFO("is25lp256", 0x9d6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ) }, - { INFO("is25lp512", 0x9d601a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp512mj", 0x9d6020, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp01g", 0x9d601b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp008", 0x9d7014, 0, 64 * 1024, 16, SPI_NOR_QUAD_READ) }, - { INFO("is25wp016", 0x9d7015, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ) }, - { INFO("is25wp032", 0x9d7016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp064", 0x9d7017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp128", 0x9d7018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp256", 0x9d7019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_4B_OPCODES) }, - { INFO("is25wp512", 0x9d701a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp512mj", 0x9d7020, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp01g", 0x9d701b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wp01gg", 0x9d7021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25wx128", 0x9d5b18, 0, 64 * 1024, 256, - SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ) }, - { INFO("is25wx256", 0x9d5b19, 0, 128 * 1024, 256, - SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, - { INFO("is25lx128", 0x9d5a18, 0, 64 * 1024, 256, - SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ) }, - { INFO("is25lx512", 0x9d5a1a, 0, 64 * 1024, 1024, - SECT_4K | USE_FSR | SPI_NOR_4B_OPCODES | SPI_NOR_HAS_TB) }, - { INFO("is25lp01gg", 0x9d6021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25lp010e", 0x9d4011, 0, 64 * 1024, 2, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp020e", 0x9d4012, 0, 64 * 1024, 4, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp040e", 0x9d4013, 0, 64 * 1024, 8, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("is25lp01gj", 0x9d6021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25lp02gg", 0x9d6022, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25lp02gj", 0x9d6022, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25wp01gg", 0x9d7021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25wp01gj", 0x9d7021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25wj128f", 0x9d7118, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25wp02gg", 0x9d7022, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, - { INFO("is25wp02gj", 0x9d7022, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_TB) }, +#if (IS_ENABLED(CONFIG_SPI_FRAM_FUJITSU)) + &spi_nor_fujitsu, #endif -#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ - /* Macronix */ - { INFO("mx25l2005a", 0xc22012, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("mx25l4005a", 0xc22013, 0, 64 * 1024, 8, SECT_4K) }, - { INFO("mx25l8005", 0xc22014, 0, 64 * 1024, 16, 0) }, - { INFO("mx25l1606e", 0xc22015, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("mx25l3205d", 0xc22016, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("mx25l6405d", 0xc22017, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("mx25u2033e", 0xc22532, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("mx25u1635e", 0xc22535, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("mx25u3235f", 0xc22536, 0, 4 * 1024, 1024, SECT_4K) }, - { INFO("mx25u6435f", 0xc22537, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, SECT_4K) }, - { INFO("mx25u12835f", 0xc22538, 0, 64 * 1024, 256, SECT_4K | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("mx25u51245g", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0) }, - { INFO("mx25l25635e", 0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("mx25u25635f", 0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, - { INFO("mx25v8035f", 0xc22314, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("mx25r1635f", 0xc22815, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0) }, - { INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66u51235f", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25u51245f", 0xc2953a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66u1g45g", 0xc2253b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66u2g45g", 0xc2253c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66l1g45g", 0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("mx66l2g45g", 0xc2201c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25l1633e", 0xc22415, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SECT_4K) }, - { INFO("mx25r6435f", 0xc22817, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("mx66uw2g345gx0", 0xc2943c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_READ) }, - { INFO("mx66lm1g45g", 0xc2853b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25lm51245g", 0xc2853a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25lw51245g", 0xc2863a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25lm25645g", 0xc28539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66uw2g345g", 0xc2843c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66um1g45g", 0xc2803b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx66uw1g45g", 0xc2813b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw51245g", 0xc2813a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw51345g", 0xc2843a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25um25645g", 0xc28039, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw25645g", 0xc28139, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25um25345g", 0xc28339, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw25345g", 0xc28439, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw12845g", 0xc28138, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw12345g", 0xc28438, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw6445g", 0xc28137, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, - { INFO("mx25uw6345g", 0xc28437, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_GIGADEVICE)) + &spi_nor_gigadevice, #endif -#ifdef CONFIG_SPI_FLASH_PUYA - /* Puya Semiconductor (Shanghai) Co., Ltd */ - { INFO - ("p25q05h", 0x856010, 0, 64 * 1024, 1, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q10h", 0x856011, 0, 64 * 1024, 2, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q20h", 0x856012, 0, 64 * 1024, 4, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q40h", 0x856013, 0, 64 * 1024, 8, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q80h", 0x856014, 0, 64 * 1024, 16, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q16h", 0x856015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q32h", 0x856016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q64h", 0x856017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("p25q128h", 0x856018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO - ("py25f512hb", 0x85231a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO - ("py25f01ghb", 0x85231b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO - ("py25f512lc", 0x85631a, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO - ("py25f01glc", 0x85631b, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_ISSI)) + &spi_nor_issi, #endif - -#ifdef CONFIG_SPI_FLASH_SILICONKAISER - { INFO("sk25lp128", 0x257018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_MACRONIX)) + &spi_nor_macronix, #endif - -#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - /* Micron */ - { INFO("n25q016a", 0x20bb15, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_QUAD_READ) }, - { INFO("n25q032", 0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, - { INFO("n25q032a", 0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, - { INFO("n25q064", 0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, - { INFO("n25q064a", 0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, - { INFO("n25q128a11", 0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, - { INFO("n25q128a13", 0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, - { INFO6("mt25ql256a", 0x20ba19, 0x104400, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) }, - { INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_FSR) }, - { INFO6("mt25qu256a", 0x20bb19, 0x104400, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) }, - { INFO("n25q256ax1", 0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | USE_FSR) }, - { INFO("mt25qu128ab", 0x20bb18, 0, 64 * 1024, 256, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, - { INFO6("mt25qu512a", 0x20bb20, 0x104400, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | - USE_FSR) }, - { INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, - { INFO6("mt25ql512a", 0x20ba20, 0x104400, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, - { INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, - { INFO("n25q00a", 0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, - { INFO("mt25ql01g", 0x21ba20, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, - { INFO6("mt25qu01g", 0x20bb21, 0x104400, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE | SPI_NOR_4B_OPCODES) }, - { INFO("mt25qu02g", 0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, - { INFO("mt25ql02g", 0x20ba22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE | SPI_NOR_4B_OPCODES) }, -#ifdef CONFIG_SPI_FLASH_MT35XU - { INFO("mt35xl512aba", 0x2c5a1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ) }, - { INFO("mt35xu512aba", 0x2c5b1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ) }, - { INFO("mt35xu01gaba", 0x2c5b1b, 0, 128 * 1024, 1024, - USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, -#endif /* CONFIG_SPI_FLASH_MT35XU */ - { INFO6("mt35xu01g", 0x2c5b1b, 0x104100, 128 * 1024, 1024, - USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, - { INFO("mt35xu02g", 0x2c5b1c, 0, 128 * 1024, 2048, - USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_PUYA)) + &spi_nor_puya, #endif -#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ - /* Spansion/Cypress -- single (large) sector size only, at least - * for the chips listed here (without boot sectors). - */ - { INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO6("s25fl256s0", 0x010219, 0x4d0080, 256 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fl256s1", 0x010219, 0x4d0180, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fl512s", 0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fs064s", 0x010217, 0x4d0181, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fs128s", 0x012018, 0x4d0181, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fs256s", 0x010219, 0x4d0181, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO6("s25fs512s", 0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl512s_256k", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl512s_64k", 0x010220, 0x4d01, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl512s_512k", 0x010220, 0x4f00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s70fs01gs_256k", 0x010221, 0x4d00, 256 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, 0) }, - { INFO("s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, 0) }, - { INFO6("s25fl128s", 0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25sl008a", 0x010213, 0, 64 * 1024, 16, 0) }, - { INFO("s25sl016a", 0x010214, 0, 64 * 1024, 32, 0) }, - { INFO("s25sl032a", 0x010215, 0, 64 * 1024, 64, 0) }, - { INFO("s25sl064a", 0x010216, 0, 64 * 1024, 128, 0) }, - { INFO("s25fl116k", 0x014015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("s25fl164k", 0x014017, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("s25fl208k", 0x014014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) }, - { INFO("s25fl064l", 0x016017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("s25fl128l", 0x016018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("s25fl256l", 0x016019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO6("s25hl512t", 0x342a1a, 0x0f0390, 256 * 1024, 256, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | - USE_CLSR) }, - { INFO6("s25hl01gt", 0x342a1b, 0x0f0390, 256 * 1024, 512, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | - USE_CLSR) }, - { INFO6("s25hl02gt", 0x342a1c, 0x0f0090, 256 * 1024, 1024, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, - { INFO6("s25hs512t", 0x342b1a, 0x0f0390, 256 * 1024, 256, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | - USE_CLSR) }, - { INFO6("s25hs01gt", 0x342b1b, 0x0f0390, 256 * 1024, 512, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | - USE_CLSR) }, - { INFO6("s25hs02gt", 0x342b1c, 0x0f0090, 256 * 1024, 1024, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, - { INFO6("s25fs256t", 0x342b19, 0x0f0890, 128 * 1024, 256, - SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, -#ifdef CONFIG_SPI_FLASH_S28HX_T - { INFO("s28hl256t", 0x345a19, 0, 256 * 1024, 128, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hl512t", 0x345a1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hl01gt", 0x345a1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hl02gt", 0x345a1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ | NO_CHIP_ERASE) }, - { INFO("s28hs256t", 0x345b19, 0, 256 * 1024, 128, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hs512t", 0x345b1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hs01gt", 0x345b1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hs02gt", 0x345b1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ | NO_CHIP_ERASE) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_SILICONKAISER)) + &spi_nor_siliconkaiser, #endif +#if (IS_ENABLED(CONFIG_SPI_FLASH_STMICRO)) + &spi_nor_micron, + &spi_nor_st, #endif -#ifdef CONFIG_SPI_FLASH_SST /* SST */ - /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - { INFO("sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, - { INFO("sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, - { INFO("sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) }, - { INFO("sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) }, - { INFO("sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, SECT_4K) }, - { INFO("sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, - { INFO("sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, - { INFO("sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, - { INFO("sst25wf020a", 0x621612, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("sst25wf040b", 0x621613, 0, 64 * 1024, 8, SECT_4K) }, - { INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, - { INFO("sst25wf080", 0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, - { INFO("sst26vf064b", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("sst26wf016b", 0xbf2641, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("sst26wf016", 0xbf2651, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, - { INFO("sst26wf032", 0xbf2622, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, - { INFO("sst26wf064", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_SPANSION)) + &spi_nor_spansion, #endif -#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - /* STMicroelectronics -- newer production may have feature updates */ - { INFO("m25p10", 0x202011, 0, 32 * 1024, 4, 0) }, - { INFO("m25p20", 0x202012, 0, 64 * 1024, 4, 0) }, - { INFO("m25p40", 0x202013, 0, 64 * 1024, 8, 0) }, - { INFO("m25p80", 0x202014, 0, 64 * 1024, 16, 0) }, - { INFO("m25p16", 0x202015, 0, 64 * 1024, 32, 0) }, - { INFO("m25p32", 0x202016, 0, 64 * 1024, 64, 0) }, - { INFO("m25p64", 0x202017, 0, 64 * 1024, 128, 0) }, - { INFO("m25p128", 0x202018, 0, 256 * 1024, 64, 0) }, - { INFO("m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("m25px16", 0x207115, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_SST)) + &spi_nor_sst, #endif -#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ - /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ - { INFO("w25p80", 0xef2014, 0x0, 64 * 1024, 16, 0) }, - { INFO("w25p16", 0xef2015, 0x0, 64 * 1024, 32, 0) }, - { INFO("w25p32", 0xef2016, 0x0, 64 * 1024, 64, 0) }, - { INFO("w25x05", 0xef3010, 0, 64 * 1024, 1, SECT_4K) }, - { INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K) }, - { INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("w25q20cl", 0xef4012, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("w25q20bw", 0xef5012, 0, 64 * 1024, 4, SECT_4K) }, - { INFO("w25q20ew", 0xef6012, 0, 64 * 1024, 4, SECT_4K) }, - { - INFO("w25q16dw", 0xef6015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q16jv", 0xef7015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) - }, - { - INFO("w25q32jv", 0xef7016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q32jwm", 0xef8016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q256jwm", 0xef8019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K) }, - { - INFO("w25q64dw", 0xef6017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q64jv", 0xef7017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q128fw", 0xef6018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q128jv", 0xef7018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q128jw", 0xef8018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q256fw", 0xef6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q256jw", 0xef7019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q512nwq", 0xef6020, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q512nwm", 0xef8020, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q512jvq", 0xef4020, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q01jv", 0xef4021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q01jvfim", 0xef7021, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - INFO("w25q02jv", 0xef7022, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K) }, - { INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { - INFO("w25q16cl", 0xef4015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q64cv", 0xef4017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25m512jw", 0xef6119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25m512jv", 0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25h02jv", 0xef9022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25h512nw-am", 0xefa020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25h01nw-am", 0xefa021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25h02nw-am", 0xefa022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q01nw-iq", 0xef6021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q01nw-im", 0xef8021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q02nw-im", 0xef8022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w77q51nw", 0xef8a1a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_WINBOND)) + &spi_nor_winbond, #endif -#ifdef CONFIG_SPI_FLASH_XMC - /* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */ - { INFO("XM25QH64A", 0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("XM25QH64C", 0x204017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("XM25QH128A", 0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("XM25QH128C", 0x204018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("XM25QU128C", 0x204118, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("XM25QH256C", 0x204019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("XM25QU256C", 0x204119, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("XM25QH512C", 0x204020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("XM25QU512C", 0x204120, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("XM25QH01D", 0x204021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_XMC)) + &spi_nor_xmc, #endif -#ifdef CONFIG_SPI_FLASH_XTX - /* XTX Technology Limited */ - /* adding these 3V QSPI flash parts */ - { INFO("xt25f08", 0x0b4014, 0, 64 * 1024, 16, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25f16", 0x0b4015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25f32", 0x0b4016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25f64", 0x0b4017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25f128", 0x0b4018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25f256", 0x0b4019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - /* adding these 1.8V QSPI flash parts */ - { INFO("xt25q08", 0x0b6014, 0, 64 * 1024, 16, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25q16", 0x0b6015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25q32", 0x0b6016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25q64", 0x0b6017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25q128", 0x0b6018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("xt25q256", 0x0b6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("xt25q512", 0x0b601A, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("xt25q01g", 0x0b601B, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("xt55q02g", 0x0b601C, 0, 64 * 1024, 4096, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - /* adding these wide voltage QSPI flash parts */ - { INFO("xt25w512", 0x0b651A, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { INFO("xt25w01g", 0x0b651B, 0, 64 * 1024, 2048, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_XTX)) + &spi_nor_xtx, #endif -#ifdef CONFIG_SPI_FLASH_ZBIT - /* Zbit Semiconductor Inc. */ - { INFO("zb25vq128", 0x5e4018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +#if (IS_ENABLED(CONFIG_SPI_FLASH_ZBIT)) + &spi_nor_zbit, #endif - { }, -}; - -const struct spi_nor_manufacturer *manufacturers[] = { NULL /* sentinel */ }; diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index cf00473ee83..0df78483ccb 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -383,13 +383,10 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) return ERR_PTR(tmp); } - info = spi_nor_ids; - for (; info->sector_size != 0; info++) { - if (info->id_len) { - if (!memcmp(info->id, id, info->id_len)) - return info; - } - } + info = spi_nor_match_id(nor, id); + if (info) + return info; + dev_dbg(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n", id[0], id[1], id[2]); return ERR_PTR(-EMEDIUMTYPE); diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c new file mode 100644 index 00000000000..e169dba663a --- /dev/null +++ b/drivers/mtd/spi/sst.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info sst_nor_parts[] = { + { INFO("sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + { INFO("sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, + { INFO("sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) }, + { INFO("sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) }, + { INFO("sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, + { INFO("sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, + { INFO("sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, + { INFO("sst25wf020a", 0x621612, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("sst25wf040b", 0x621613, 0, 64 * 1024, 8, SECT_4K) }, + { INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + { INFO("sst25wf080", 0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, + { INFO("sst26vf064b", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("sst26wf016b", 0xbf2641, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("sst26wf016", 0xbf2651, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, + { INFO("sst26wf032", 0xbf2622, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, + { INFO("sst26wf064", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, +}; + +const struct spi_nor_manufacturer spi_nor_sst = { + .parts = sst_nor_parts, + .nparts = ARRAY_SIZE(sst_nor_parts), +}; diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c new file mode 100644 index 00000000000..02c29ccf78c --- /dev/null +++ b/drivers/mtd/spi/winbond.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info winbond_nor_parts[] = { + { INFO("w25p80", 0xef2014, 0x0, 64 * 1024, 16, 0) }, + { INFO("w25p16", 0xef2015, 0x0, 64 * 1024, 32, 0) }, + { INFO("w25p32", 0xef2016, 0x0, 64 * 1024, 64, 0) }, + { INFO("w25x05", 0xef3010, 0, 64 * 1024, 1, SECT_4K) }, + { INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K) }, + { INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K) }, + { INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K) }, + { INFO("w25q20cl", 0xef4012, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("w25q20bw", 0xef5012, 0, 64 * 1024, 4, SECT_4K) }, + { INFO("w25q20ew", 0xef6012, 0, 64 * 1024, 4, SECT_4K) }, + { + INFO("w25q16dw", 0xef6015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q16jv", 0xef7015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) + }, + { + INFO("w25q32jv", 0xef7016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q32jwm", 0xef8016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q256jwm", 0xef8019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K) }, + { + INFO("w25q64dw", 0xef6017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q64jv", 0xef7017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q128fw", 0xef6018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q128jv", 0xef7018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q128jw", 0xef8018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q256fw", 0xef6019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q256jw", 0xef7019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q512nwq", 0xef6020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q512nwm", 0xef8020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q512jvq", 0xef4020, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q01jv", 0xef4021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q01jvfim", 0xef7021, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { + INFO("w25q02jv", 0xef7022, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K) }, + { INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { + INFO("w25q16cl", 0xef4015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q64cv", 0xef4017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25m512jw", 0xef6119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25m512jv", 0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h02jv", 0xef9022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h512nw-am", 0xefa020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h01nw-am", 0xefa021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h02nw-am", 0xefa022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q01nw-iq", 0xef6021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q01nw-im", 0xef8021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q02nw-im", 0xef8022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w77q51nw", 0xef8a1a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_winbond = { + .parts = winbond_nor_parts, + .nparts = ARRAY_SIZE(winbond_nor_parts), +}; diff --git a/drivers/mtd/spi/xmc.c b/drivers/mtd/spi/xmc.c new file mode 100644 index 00000000000..8356f3da2d2 --- /dev/null +++ b/drivers/mtd/spi/xmc.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info xmc_nor_parts[] = { + { INFO("XM25QH64A", 0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("XM25QH64C", 0x204017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("XM25QH128A", 0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("XM25QH128C", 0x204018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("XM25QU128C", 0x204118, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("XM25QH256C", 0x204019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("XM25QU256C", 0x204119, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("XM25QH512C", 0x204020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("XM25QU512C", 0x204120, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("XM25QH01D", 0x204021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_xmc = { + .parts = xmc_nor_parts, + .nparts = ARRAY_SIZE(xmc_nor_parts), +}; diff --git a/drivers/mtd/spi/xtx.c b/drivers/mtd/spi/xtx.c new file mode 100644 index 00000000000..e49b1ceb76d --- /dev/null +++ b/drivers/mtd/spi/xtx.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info xtx_nor_parts[] = { + /* adding these 3V QSPI flash parts */ + { INFO("xt25f08", 0x0b4014, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25f16", 0x0b4015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25f32", 0x0b4016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25f64", 0x0b4017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25f128", 0x0b4018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25f256", 0x0b4019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + /* adding these 1.8V QSPI flash parts */ + { INFO("xt25q08", 0x0b6014, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25q16", 0x0b6015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25q32", 0x0b6016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25q64", 0x0b6017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25q128", 0x0b6018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("xt25q256", 0x0b6019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("xt25q512", 0x0b601A, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("xt25q01g", 0x0b601B, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("xt55q02g", 0x0b601C, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + /* adding these wide voltage QSPI flash parts */ + { INFO("xt25w512", 0x0b651A, 0, 64 * 1024, 1024, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("xt25w01g", 0x0b651B, 0, 64 * 1024, 2048, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +}; + +const struct spi_nor_manufacturer spi_nor_xtx = { + .parts = xtx_nor_parts, + .nparts = ARRAY_SIZE(xtx_nor_parts), +}; diff --git a/drivers/mtd/spi/zbit.c b/drivers/mtd/spi/zbit.c new file mode 100644 index 00000000000..ee709b2bef1 --- /dev/null +++ b/drivers/mtd/spi/zbit.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2016 Jagan Teki <jagan@openedev.com> + * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <linux/mtd/spi-nor.h> +#include "sf_internal.h" + +static const struct flash_info zbit_nor_parts[] = { + { INFO("zb25vq128", 0x5e4018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +}; + +const struct spi_nor_manufacturer spi_nor_zbit = { + .parts = zbit_nor_parts, + .nparts = ARRAY_SIZE(zbit_nor_parts), +}; -- 2.53.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 4/4] mtd: spi-nor: move fixups to manufacturer drivers 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay @ 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay -1 siblings, 0 replies; 15+ messages in thread From: Takahiro Kuwano @ 2026-10-16 1:43 UTC (permalink / raw) To: u-boot Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev, Takahiro Kuwano Move chip specific fixups from core to manufacturer drivers. As manufacturer drivers are used in tiny as well, all fixups migrated from core need to be excluded in CONFIG_SPI_FLASH_TINY. Some helper functions used in fixups are exposed from core and some need to be guarded by CONFIG_SPI_FLASH_TINY to avoid name conflict with local functions in tiny. Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com> --- drivers/mtd/spi/macronix.c | 89 ++++ drivers/mtd/spi/micron-st.c | 99 +++++ drivers/mtd/spi/sf_internal.h | 10 + drivers/mtd/spi/spansion.c | 627 +++++++++++++++++++++++++++ drivers/mtd/spi/spi-nor-core.c | 929 +---------------------------------------- drivers/mtd/spi/winbond.c | 104 +++++ 6 files changed, 938 insertions(+), 920 deletions(-) diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c index 87843978cad..9ca55fc4f99 100644 --- a/drivers/mtd/spi/macronix.c +++ b/drivers/mtd/spi/macronix.c @@ -5,6 +5,7 @@ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <dm/device_compat.h> #include <linux/mtd/spi-nor.h> #include "sf_internal.h" @@ -59,7 +60,95 @@ static const struct flash_info macronix_nor_parts[] = { { INFO("mx25uw6345g", 0xc28437, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, }; +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) +/** + * spi_nor_macronix_octal_dtr_enable() - Enable octal DTR on Macronix flashes. + * @nor: pointer to a 'struct spi_nor' + * + * Set Macronix max dummy cycles 20 to allow the flash to run at fastest frequency. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_macronix_octal_dtr_enable(struct spi_nor *nor) +{ + struct spi_mem_op op; + int ret; + u8 buf; + + ret = write_enable(nor); + if (ret) + return ret; + + buf = SPINOR_REG_MXIC_DC_20; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1), + SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_DC, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + return ret; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + return ret; + + nor->read_dummy = MXIC_MAX_DC; + ret = write_enable(nor); + if (ret) + return ret; + + buf = SPINOR_REG_MXIC_OPI_DTR_EN; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1), + SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_MODE, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) { + dev_err(nor->dev, "Failed to enable octal DTR mode\n"); + return ret; + } + nor->reg_proto = SNOR_PROTO_8_8_8_DTR; + + return 0; +} + +static void macronix_octal_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->octal_dtr_enable = spi_nor_macronix_octal_dtr_enable; +} + +static void macronix_octal_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* + * Adding SNOR_HWCAPS_PP_8_8_8_DTR in hwcaps.mask when + * SPI_NOR_OCTAL_DTR_READ flag exists. + */ + if (params->hwcaps.mask & SNOR_HWCAPS_READ_8_8_8_DTR) + params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; +} + +static struct spi_nor_fixups macronix_octal_fixups = { + .post_sfdp = macronix_octal_post_sfdp_fixup, + .late_init = macronix_octal_late_init, +}; + +static void macronix_set_fixups(struct spi_nor *nor) +{ + if (nor->info->flags & SPI_NOR_OCTAL_DTR_READ) + nor->fixups = ¯onix_octal_fixups; +} +#endif + const struct spi_nor_manufacturer spi_nor_macronix = { .parts = macronix_nor_parts, .nparts = ARRAY_SIZE(macronix_nor_parts), +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + .set_fixups = macronix_set_fixups, +#endif }; diff --git a/drivers/mtd/spi/micron-st.c b/drivers/mtd/spi/micron-st.c index 2d47f1c60c0..9982e9d660a 100644 --- a/drivers/mtd/spi/micron-st.c +++ b/drivers/mtd/spi/micron-st.c @@ -5,6 +5,7 @@ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <dm/device_compat.h> #include <linux/mtd/spi-nor.h> #include "sf_internal.h" @@ -59,9 +60,107 @@ static const struct flash_info st_nor_parts[] = { { INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0) }, }; +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) && CONFIG_IS_ENABLED(SPI_FLASH_MT35XU) +static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor) +{ + struct spi_mem_op op; + u8 buf; + u8 addr_width = 3; + int ret; + + /* Set dummy cycles for Fast Read to the default of 20. */ + ret = write_enable(nor); + if (ret) + return ret; + + buf = 20; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), + SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR1V, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + return ret; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + return ret; + + nor->read_dummy = 20; + + ret = write_enable(nor); + if (ret) + return ret; + + buf = SPINOR_MT_OCT_DTR; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), + SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR0V, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) { + dev_err(nor->dev, "Failed to enable octal DTR mode\n"); + return ret; + } + + return 0; +} + +static void mt35xu512aba_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->octal_dtr_enable = spi_nor_micron_octal_dtr_enable; +} + +static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* Set the Fast Read settings. */ + params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], + 0, 20, SPINOR_OP_MT_DTR_RD, + SNOR_PROTO_8_8_8_DTR); + + params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; + + nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; + params->rdsr_dummy = 8; + params->rdsr_addr_nbytes = 0; + + /* + * SCCR Map 22nd DWORD does not indicate DTR Octal Mode Enable + * for MT35XU512ABA but is actually supported by device. + */ + nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; + + /* + * The BFPT quad enable field is set to a reserved value so the quad + * enable function is ignored by spi_nor_parse_bfpt(). Make sure we + * disable it. + */ + params->quad_enable = NULL; +} + +static struct spi_nor_fixups mt35xu512aba_fixups = { + .post_sfdp = mt35xu512aba_post_sfdp_fixup, + .late_init = mt35xu512aba_late_init, +}; + +static void micron_set_fixups(struct spi_nor *nor) +{ + if (!strcmp(nor->info->name, "mt35xu512aba")) + nor->fixups = &mt35xu512aba_fixups; +} +#endif + const struct spi_nor_manufacturer spi_nor_micron = { .parts = micron_nor_parts, .nparts = ARRAY_SIZE(micron_nor_parts), +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) && CONFIG_IS_ENABLED(SPI_FLASH_MT35XU) + .set_fixups = micron_set_fixups, +#endif }; const struct spi_nor_manufacturer spi_nor_st = { diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index f96895c7439..2be206b2651 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -203,6 +203,12 @@ static inline int spi_nor_parse_sfdp(struct spi_nor *nor, #endif #if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) +int write_enable(struct spi_nor *nor); +int set_4byte(struct spi_nor *nor, const struct flash_info *info, int enable); +int spi_nor_sr_ready(struct spi_nor *nor); +int spi_nor_wait_till_ready(struct spi_nor *nor); +int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op *op, + void *buf); void spi_nor_set_read_settings(struct spi_nor_read_command *read, u8 num_mode_clocks, u8 num_wait_states, @@ -212,6 +218,10 @@ int spansion_read_cr_quad_enable(struct spi_nor *nor); int macronix_quad_enable(struct spi_nor *nor); #endif +void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode, + enum spi_nor_protocol proto); +int spi_nor_default_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params); int spi_nor_hwcaps_read2cmd(u32 hwcaps); int spansion_no_read_cr_quad_enable(struct spi_nor *nor); diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index 405f5bf5e79..1dd38667062 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -5,6 +5,8 @@ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <dm/device_compat.h> +#include <linux/sizes.h> #include <linux/mtd/spi-nor.h> #include "sf_internal.h" @@ -67,7 +69,632 @@ static const struct flash_info spansion_nor_parts[] = { #endif }; +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + +/* Use ID byte 4 to distinguish S25FS256T and S25Hx-T */ +#define S25FS256T_ID4 (0x08) + +/* Number of dummy cycle for Read Any Register (RDAR) op. */ +#define S25FS_S_RDAR_DUMMY 8 + +static int spansion_read_any_reg(struct spi_nor *nor, u32 addr, u8 dummy, + u8 *val) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), + SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 0), + SPI_MEM_OP_DUMMY(dummy, 0), + SPI_MEM_OP_DATA_IN(1, NULL, 0)); + u8 buf[2]; + int ret; + + spi_nor_setup_op(nor, &op, nor->reg_proto); + + /* + * In Octal DTR mode, the number of address bytes is always 4 regardless + * of addressing mode setting. + */ + if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) + op.addr.nbytes = 4; + + /* + * We don't want to read only one byte in DTR mode. So, read 2 and then + * discard the second byte. + */ + if (spi_nor_protocol_is_dtr(nor->reg_proto)) + op.data.nbytes = 2; + + ret = spi_nor_read_write_reg(nor, &op, buf); + if (ret) + return ret; + + *val = buf[0]; + + return 0; +} + +static int spansion_write_any_reg(struct spi_nor *nor, u32 addr, u8 val) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), + SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, NULL, 1)); + + return spi_nor_read_write_reg(nor, &op, &val); +} + +/** + * spansion_quad_enable_volatile() - enable Quad I/O mode in volatile register. + * @nor: pointer to a 'struct spi_nor' + * @addr_base: base address of register (can be >0 in multi-die parts) + * @dummy: number of dummy cycles for register read + * + * It is recommended to update volatile registers in the field application due + * to a risk of the non-volatile registers corruption by power interrupt. This + * function sets Quad Enable bit in CFR1 volatile. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_quad_enable_volatile(struct spi_nor *nor, u32 addr_base, + u8 dummy) +{ + u32 addr = addr_base + SPINOR_REG_CYPRESS_CFR1V; + + u8 cr; + int ret; + + /* Check current Quad Enable bit value. */ + ret = spansion_read_any_reg(nor, addr, dummy, &cr); + if (ret < 0) { + dev_dbg(nor->dev, + "error while reading configuration register\n"); + return -EINVAL; + } + + if (cr & CR_QUAD_EN_SPAN) + return 0; + + cr |= CR_QUAD_EN_SPAN; + + write_enable(nor); + + ret = spansion_write_any_reg(nor, addr, cr); + + if (ret < 0) { + dev_dbg(nor->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* Read back and check it. */ + ret = spansion_read_any_reg(nor, addr, dummy, &cr); + if (ret || !(cr & CR_QUAD_EN_SPAN)) { + dev_dbg(nor->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +/* + * Read status register 1 by using Read Any Register command to support multi + * die package parts. + */ +static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy) +{ + u32 reg_addr = addr_base + SPINOR_REG_CYPRESS_STR1V; + u8 sr; + int ret; + + ret = spansion_read_any_reg(nor, reg_addr, dummy, &sr); + if (ret < 0) + return ret; + + if (sr & (SR_E_ERR | SR_P_ERR)) { + if (sr & SR_E_ERR) + dev_dbg(nor->dev, "Erase Error occurred\n"); + else + dev_dbg(nor->dev, "Programming Error occurred\n"); + + nor->write_reg(nor, SPINOR_OP_CYPRESS_CLPEF, NULL, 0); + return -EIO; + } + + return !(sr & SR_WIP); +} + +/** + * spansion_erase_non_uniform() - erase non-uniform sectors for Spansion/Cypress + * chips + * @nor: pointer to a 'struct spi_nor' + * @addr: address of the sector to erase + * @opcode_4k: opcode for 4K sector erase + * @ovlsz_top: size of overlaid portion at the top address + * @ovlsz_btm: size of overlaid portion at the bottom address + * + * Erase an address range on the nor chip that can contain 4KB sectors overlaid + * on top and/or bottom. The appropriate erase opcode and size are chosen by + * address to erase and size of overlaid portion. + * + * Return: number of bytes erased on success, -errno otherwise. + */ +static int spansion_erase_non_uniform(struct spi_nor *nor, u32 addr, + u8 opcode_4k, u32 ovlsz_top, + u32 ovlsz_btm) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_width, addr, 0), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); + struct mtd_info *mtd = &nor->mtd; + u32 erasesize; + int ret; + + /* 4KB sectors */ + if (op.addr.val < ovlsz_btm || + op.addr.val >= mtd->size - ovlsz_top) { + op.cmd.opcode = opcode_4k; + erasesize = SZ_4K; + + /* Non-overlaid portion in the normal sector at the bottom */ + } else if (op.addr.val == ovlsz_btm) { + op.cmd.opcode = nor->erase_opcode; + erasesize = mtd->erasesize - ovlsz_btm; + + /* Non-overlaid portion in the normal sector at the top */ + } else if (op.addr.val == mtd->size - mtd->erasesize) { + op.cmd.opcode = nor->erase_opcode; + erasesize = mtd->erasesize - ovlsz_top; + + /* Normal sectors */ + } else { + op.cmd.opcode = nor->erase_opcode; + erasesize = mtd->erasesize; + } + + spi_nor_setup_op(nor, &op, nor->write_proto); + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + return ret; + + return erasesize; +} + +static int s25fs_s_quad_enable(struct spi_nor *nor) +{ + return spansion_quad_enable_volatile(nor, 0, S25FS_S_RDAR_DUMMY); +} + +static int s25fs_s_erase_non_uniform(struct spi_nor *nor, loff_t addr) +{ + u8 opcode = nor->addr_width == 4 ? SPINOR_OP_BE_4K_4B : SPINOR_OP_BE_4K; + + /* Support 8 x 4KB sectors at bottom */ + return spansion_erase_non_uniform(nor, addr, opcode, 0, SZ_32K); +} + +static int s25fs_s_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) +{ + int ret; + u8 cfr3v; + + /* Bank Address Register is not supported */ + if (CONFIG_IS_ENABLED(SPI_FLASH_BAR)) + return -EOPNOTSUPP; + + /* + * Read CR3V to check if uniform sector is selected. If not, assign an + * erase hook that supports non-uniform erase. + */ + ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_CFR3V, + S25FS_S_RDAR_DUMMY, &cfr3v); + if (ret) + return ret; + if (!(cfr3v & SPINOR_REG_CYPRESS_CFR3_UNISECT)) + nor->erase = s25fs_s_erase_non_uniform; + + return spi_nor_default_setup(nor, info, params); +} + +static void s25fs_s_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->setup = s25fs_s_setup; +} + +static int s25fs_s_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + /* The erase size is set to 4K from BFPT, but it's wrong. Fix it. */ + nor->erase_opcode = SPINOR_OP_SE; + nor->mtd.erasesize = nor->info->sector_size; + + /* The S25FS-S chip family reports 512-byte pages in BFPT but + * in reality the write buffer still wraps at the safe default + * of 256 bytes. Overwrite the page size advertised by BFPT + * to get the writes working. + */ + params->page_size = 256; + + return 0; +} + +static void s25fs_s_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* + * The S25FS064S(8MB) supports 1-1-2 and 1-1-4 commands, but params for + * read ops in SFDP are wrong. The other density parts do not support + * 1-1-2 and 1-1-4 commands. + */ + if (params->size == SZ_8M) { + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_2], + 0, 8, SPINOR_OP_READ_1_1_2, + SNOR_PROTO_1_1_2); + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_4], + 0, 8, SPINOR_OP_READ_1_1_4, + SNOR_PROTO_1_1_4); + } else { + params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_2; + params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_4; + params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; + } + + /* Use volatile register to enable quad */ + params->quad_enable = s25fs_s_quad_enable; +} + +static struct spi_nor_fixups s25fs_s_fixups = { + .post_bfpt = s25fs_s_post_bfpt_fixup, + .post_sfdp = s25fs_s_post_sfdp_fixup, + .late_init = s25fs_s_late_init, +}; + +static int s25_s28_mdp_ready(struct spi_nor *nor) +{ + u32 addr; + int ret; + + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_sr_ready(nor, addr, nor->rdsr_dummy); + if (ret < 0) + return ret; + else if (ret == 0) + return 0; + } + + return 1; +} + +static int s25_quad_enable(struct spi_nor *nor) +{ + u32 addr; + int ret; + + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_quad_enable_volatile(nor, addr, 0); + if (ret) + return ret; + } + + return 0; +} + +static int s25_s28_erase_non_uniform(struct spi_nor *nor, loff_t addr) +{ + /* Support 32 x 4KB sectors at bottom */ + return spansion_erase_non_uniform(nor, addr, SPINOR_OP_BE_4K_4B, 0, + SZ_128K); +} + +static int s25_s28_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) +{ + int ret; + u8 cr; + +#if CONFIG_IS_ENABLED(SPI_FLASH_BAR) + return -ENOTSUPP; /* Bank Address Register is not supported */ +#endif + /* + * S25FS256T has multiple sector architecture options, with selection of + * count and location of 128KB and 64KB sectors. This driver supports + * uniform 128KB only due to complexity of non-uniform layout. + */ + if (nor->info->id[4] == S25FS256T_ID4) { + ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_ARCFN, 8, + &cr); + if (ret) + return ret; + + if (cr) /* Option 0 (ARCFN[7:0] == 0x00) is uniform */ + return -EOPNOTSUPP; + + return spi_nor_default_setup(nor, info, params); + } + + /* + * Read CFR3V to check if uniform sector is selected. If not, assign an + * erase hook that supports non-uniform erase. + */ + ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_CFR3V, 0, &cr); + if (ret) + return ret; + if (!(cr & SPINOR_REG_CYPRESS_CFR3_UNISECT)) + nor->erase = s25_s28_erase_non_uniform; + + /* + * For the multi-die package parts, the ready() hook is needed to check + * all dies' status via read any register. + */ + if (nor->mtd.size > SZ_128M) + nor->ready = s25_s28_mdp_ready; + + return spi_nor_default_setup(nor, info, params); +} + +static void s25_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->setup = s25_s28_setup; + + /* + * Programming is supported only in 16-byte ECC data unit granularity. + * Byte-programming, bit-walking, or multiple program operations to the + * same ECC data unit without an erase are not allowed. + */ + params->writesize = 16; +} + +static int s25_s28_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + int ret; + u32 addr; + u8 cfr3v; + + /* erase size in case it is set to 4K from BFPT */ + nor->erase_opcode = SPINOR_OP_SE_4B; + nor->mtd.erasesize = nor->info->sector_size; + + /* + * The default address mode in multi-die package parts (>1Gb) may be + * 3- or 4-byte, depending on model number. BootROM code in some SoCs + * use 3-byte mode for backward compatibility and should switch to + * 4-byte mode after BootROM phase. Since registers in the 2nd die are + * mapped within 32-bit address space, we need to make sure the flash is + * in 4-byte address mode. The default address mode can be distinguished + * by BFPT 16th DWORD. Power cycle exits 4-byte address mode if default + * is 3-byte address mode. + */ + if (params->size > SZ_128M) { + if (bfpt->dwords[BFPT_DWORD(16)] & BFPT_DWORD16_EX4B_PWRCYC) { + ret = set_4byte(nor, nor->info, 1); + if (ret) + return ret; + } + nor->addr_mode_nbytes = 4; + } + + /* The default address mode in S25FS256T is 4. */ + if (nor->info->id[4] == S25FS256T_ID4) + nor->addr_mode_nbytes = 4; + + /* + * The page_size is set to 512B from BFPT, but it actually depends on + * the configuration register. Look up the CFR3V and determine the + * page_size. For multi-die package parts, use 512B only when the all + * dies are configured to 512B buffer. + */ + for (addr = 0; addr < params->size; addr += SZ_128M) { + ret = spansion_read_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR3V, 0, + &cfr3v); + if (ret) + return ret; + + if (!(cfr3v & SPINOR_REG_CYPRESS_CFR3_PGSZ)) { + params->page_size = 256; + return 0; + } + } + params->page_size = 512; + + return 0; +} + +static void s25_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + if (nor->info->id[4] == S25FS256T_ID4) { + /* PP_1_1_4 is supported */ + params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; + } else { + /* READ_FAST_4B (0Ch) requires mode cycles*/ + params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; + /* PP_1_1_4 is not supported */ + params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; + /* Use volatile register to enable quad */ + params->quad_enable = s25_quad_enable; + } +} + +static struct spi_nor_fixups s25_fixups = { + .post_bfpt = s25_s28_post_bfpt_fixup, + .post_sfdp = s25_post_sfdp_fixup, + .late_init = s25_late_init, +}; + +static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) +{ + return -ENOTSUPP; /* Bank Address Register is not supported */ +} + +static void s25fl256l_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->setup = s25fl256l_setup; +} + +static struct spi_nor_fixups s25fl256l_fixups = { + .late_init = s25fl256l_late_init, +}; + +#ifdef CONFIG_SPI_FLASH_S28HX_T +/** + * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes. + * @nor: pointer to a 'struct spi_nor' + * + * This also sets the memory access latency cycles to 24 to allow the flash to + * run at up to 200MHz. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor) +{ + u32 addr; + u8 buf; + int ret; + + ret = write_enable(nor); + if (ret) + return ret; + + /* Use 24 dummy cycles for memory array reads. */ + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_read_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR2V, 0, + &buf); + if (ret) + return ret; + + buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK; + buf |= SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24; + ret = spansion_write_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR2V, + buf); + if (ret) { + dev_warn(nor->dev, "failed to set default memory latency value: %d\n", ret); + return ret; + } + } + nor->read_dummy = 24; + + ret = write_enable(nor); + if (ret) + return ret; + + /* Set the octal and DTR enable bits. */ + buf = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN; + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_write_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR5V, + buf); + if (ret) { + dev_warn(nor->dev, "Failed to enable octal DTR mode\n"); + return ret; + } + } + + return 0; +} + +static void s28hx_t_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable; + nor->setup = s25_s28_setup; + + /* + * Programming is supported only in 16-byte ECC data unit granularity. + * Byte-programming, bit-walking, or multiple program operations to the + * same ECC data unit without an erase are not allowed. + */ + params->writesize = 16; +} + +static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* + * On older versions of the flash the xSPI Profile 1.0 table has the + * 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE. + */ + if (params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0) + params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode = + SPINOR_OP_CYPRESS_RD_FAST; + + params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; + + /* This flash is also missing the 4-byte Page Program opcode bit. */ + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], + SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1); + /* + * Since xSPI Page Program opcode is backward compatible with + * Legacy SPI, use Legacy SPI opcode there as well. + */ + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8_8_8_DTR], + SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR); + + /* + * The xSPI Profile 1.0 table advertises the number of additional + * address bytes needed for Read Status Register command as 0 but the + * actual value for that is 4. + */ + params->rdsr_addr_nbytes = 4; +} + +static struct spi_nor_fixups s28hx_t_fixups = { + .post_sfdp = s28hx_t_post_sfdp_fixup, + .post_bfpt = s25_s28_post_bfpt_fixup, + .late_init = s28hx_t_late_init, +}; +#endif /* CONFIG_SPI_FLASH_S28HX_T */ + +static void spansion_set_fixups(struct spi_nor *nor) +{ + if (JEDEC_MFR(nor->info) == SNOR_MFR_CYPRESS) { + switch (nor->info->id[1]) { + case 0x2a: /* S25HL (QSPI, 3.3V) */ + case 0x2b: /* S25HS (QSPI, 1.8V) */ + nor->fixups = &s25_fixups; + break; + +#ifdef CONFIG_SPI_FLASH_S28HX_T + case 0x5a: /* S28HL (Octal, 3.3V) */ + case 0x5b: /* S28HS (Octal, 1.8V) */ + nor->fixups = &s28hx_t_fixups; + break; +#endif + + default: + break; + } + } + + if (CONFIG_IS_ENABLED(SPI_FLASH_BAR) && + !strcmp(nor->info->name, "s25fl256l")) + nor->fixups = &s25fl256l_fixups; + + /* For FS-S (family ID = 0x81) */ + if (JEDEC_MFR(nor->info) == SNOR_MFR_SPANSION && nor->info->id[5] == 0x81) + nor->fixups = &s25fs_s_fixups; +} +#endif /* !CONFIG_IS_ENABLED(SPI_FLASH_TINY) */ + const struct spi_nor_manufacturer spi_nor_spansion = { .parts = spansion_nor_parts, .nparts = ARRAY_SIZE(spansion_nor_parts), +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + .set_fixups = spansion_set_fixups, +#endif }; diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index d107828092c..6e61b5653bd 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -123,8 +123,8 @@ void spi_nor_setup_op(const struct spi_nor *nor, } } -static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op - *op, void *buf) +int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op *op, + void *buf) { if (op->data.dir == SPI_MEM_DATA_IN) op->data.buf.in = buf; @@ -165,55 +165,6 @@ static int spi_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) return spi_nor_read_write_reg(nor, &op, buf); } -#ifdef CONFIG_SPI_FLASH_SPANSION -static int spansion_read_any_reg(struct spi_nor *nor, u32 addr, u8 dummy, - u8 *val) -{ - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), - SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 0), - SPI_MEM_OP_DUMMY(dummy, 0), - SPI_MEM_OP_DATA_IN(1, NULL, 0)); - u8 buf[2]; - int ret; - - spi_nor_setup_op(nor, &op, nor->reg_proto); - - /* - * In Octal DTR mode, the number of address bytes is always 4 regardless - * of addressing mode setting. - */ - if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) - op.addr.nbytes = 4; - - /* - * We don't want to read only one byte in DTR mode. So, read 2 and then - * discard the second byte. - */ - if (spi_nor_protocol_is_dtr(nor->reg_proto)) - op.data.nbytes = 2; - - ret = spi_nor_read_write_reg(nor, &op, buf); - if (ret) - return ret; - - *val = buf[0]; - - return 0; -} - -static int spansion_write_any_reg(struct spi_nor *nor, u32 addr, u8 val) -{ - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), - SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, NULL, 1)); - - return spi_nor_read_write_reg(nor, &op, &val); -} -#endif - static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, u_char *buf) { @@ -472,7 +423,7 @@ static int write_sr3(struct spi_nor *nor, u8 val) * Set write enable latch with Write Enable command. * Returns negative if error occurred. */ -static int write_enable(struct spi_nor *nor) +int write_enable(struct spi_nor *nor) { return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0); } @@ -577,8 +528,7 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, #endif /* !CONFIG_IS_ENABLED(SPI_FLASH_BAR) */ /* Enable/disable 4-byte addressing mode. */ -static int set_4byte(struct spi_nor *nor, const struct flash_info *info, - int enable) +int set_4byte(struct spi_nor *nor, const struct flash_info *info, int enable) { int status; bool need_wren = false; @@ -626,36 +576,7 @@ static int set_4byte(struct spi_nor *nor, const struct flash_info *info, } } -#ifdef CONFIG_SPI_FLASH_SPANSION -/* - * Read status register 1 by using Read Any Register command to support multi - * die package parts. - */ -static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy) -{ - u32 reg_addr = addr_base + SPINOR_REG_CYPRESS_STR1V; - u8 sr; - int ret; - - ret = spansion_read_any_reg(nor, reg_addr, dummy, &sr); - if (ret < 0) - return ret; - - if (sr & (SR_E_ERR | SR_P_ERR)) { - if (sr & SR_E_ERR) - dev_dbg(nor->dev, "Erase Error occurred\n"); - else - dev_dbg(nor->dev, "Programming Error occurred\n"); - - nor->write_reg(nor, SPINOR_OP_CYPRESS_CLPEF, NULL, 0); - return -EIO; - } - - return !(sr & SR_WIP); -} -#endif - -static int spi_nor_sr_ready(struct spi_nor *nor) +int spi_nor_sr_ready(struct spi_nor *nor) { int sr = read_sr(nor); @@ -745,7 +666,7 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor, return -ETIMEDOUT; } -static int spi_nor_wait_till_ready(struct spi_nor *nor) +int spi_nor_wait_till_ready(struct spi_nor *nor) { return spi_nor_wait_till_ready_with_timeout(nor, DEFAULT_READY_WAIT_JIFFIES); @@ -1035,67 +956,6 @@ err: return ret; } -#ifdef CONFIG_SPI_FLASH_SPANSION -/** - * spansion_erase_non_uniform() - erase non-uniform sectors for Spansion/Cypress - * chips - * @nor: pointer to a 'struct spi_nor' - * @addr: address of the sector to erase - * @opcode_4k: opcode for 4K sector erase - * @ovlsz_top: size of overlaid portion at the top address - * @ovlsz_btm: size of overlaid portion at the bottom address - * - * Erase an address range on the nor chip that can contain 4KB sectors overlaid - * on top and/or bottom. The appropriate erase opcode and size are chosen by - * address to erase and size of overlaid portion. - * - * Return: number of bytes erased on success, -errno otherwise. - */ -static int spansion_erase_non_uniform(struct spi_nor *nor, u32 addr, - u8 opcode_4k, u32 ovlsz_top, - u32 ovlsz_btm) -{ - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_width, addr, 0), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); - struct mtd_info *mtd = &nor->mtd; - u32 erasesize; - int ret; - - /* 4KB sectors */ - if (op.addr.val < ovlsz_btm || - op.addr.val >= mtd->size - ovlsz_top) { - op.cmd.opcode = opcode_4k; - erasesize = SZ_4K; - - /* Non-overlaid portion in the normal sector at the bottom */ - } else if (op.addr.val == ovlsz_btm) { - op.cmd.opcode = nor->erase_opcode; - erasesize = mtd->erasesize - ovlsz_btm; - - /* Non-overlaid portion in the normal sector at the top */ - } else if (op.addr.val == mtd->size - mtd->erasesize) { - op.cmd.opcode = nor->erase_opcode; - erasesize = mtd->erasesize - ovlsz_top; - - /* Normal sectors */ - } else { - op.cmd.opcode = nor->erase_opcode; - erasesize = mtd->erasesize; - } - - spi_nor_setup_op(nor, &op, nor->write_proto); - - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) - return ret; - - return erasesize; -} -#endif - #if defined(CONFIG_SPI_FLASH_LOCK) #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) /* Write status register and ensure bits in mask match written values */ @@ -1980,61 +1840,6 @@ int macronix_quad_enable(struct spi_nor *nor) } #endif -#ifdef CONFIG_SPI_FLASH_SPANSION -/** - * spansion_quad_enable_volatile() - enable Quad I/O mode in volatile register. - * @nor: pointer to a 'struct spi_nor' - * @addr_base: base address of register (can be >0 in multi-die parts) - * @dummy: number of dummy cycles for register read - * - * It is recommended to update volatile registers in the field application due - * to a risk of the non-volatile registers corruption by power interrupt. This - * function sets Quad Enable bit in CFR1 volatile. - * - * Return: 0 on success, -errno otherwise. - */ -static int spansion_quad_enable_volatile(struct spi_nor *nor, u32 addr_base, - u8 dummy) -{ - u32 addr = addr_base + SPINOR_REG_CYPRESS_CFR1V; - - u8 cr; - int ret; - - /* Check current Quad Enable bit value. */ - ret = spansion_read_any_reg(nor, addr, dummy, &cr); - if (ret < 0) { - dev_dbg(nor->dev, - "error while reading configuration register\n"); - return -EINVAL; - } - - if (cr & CR_QUAD_EN_SPAN) - return 0; - - cr |= CR_QUAD_EN_SPAN; - - write_enable(nor); - - ret = spansion_write_any_reg(nor, addr, cr); - - if (ret < 0) { - dev_dbg(nor->dev, - "error while writing configuration register\n"); - return -EINVAL; - } - - /* Read back and check it. */ - ret = spansion_read_any_reg(nor, addr, dummy, &cr); - if (ret || !(cr & CR_QUAD_EN_SPAN)) { - dev_dbg(nor->dev, "Spansion Quad bit not set\n"); - return -EINVAL; - } - - return 0; -} -#endif - #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) /* * Write status Register and configuration register with 2 bytes @@ -2165,7 +1970,7 @@ spi_nor_set_read_settings(struct spi_nor_read_command *read, read->proto = proto; } -static void +void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode, enum spi_nor_protocol proto) @@ -2755,9 +2560,8 @@ static int spi_nor_select_erase(struct spi_nor *nor, return 0; } -static int spi_nor_default_setup(struct spi_nor *nor, - const struct flash_info *info, - const struct spi_nor_flash_parameter *params) +int spi_nor_default_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) { u32 shared_mask; bool enable_quad_io; @@ -2809,664 +2613,6 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, return nor->setup(nor, info, params); } -#ifdef CONFIG_SPI_FLASH_SPANSION - -/* Use ID byte 4 to distinguish S25FS256T and S25Hx-T */ -#define S25FS256T_ID4 (0x08) - -/* Number of dummy cycle for Read Any Register (RDAR) op. */ -#define S25FS_S_RDAR_DUMMY 8 - -static int s25fs_s_quad_enable(struct spi_nor *nor) -{ - return spansion_quad_enable_volatile(nor, 0, S25FS_S_RDAR_DUMMY); -} - -static int s25fs_s_erase_non_uniform(struct spi_nor *nor, loff_t addr) -{ - u8 opcode = nor->addr_width == 4 ? SPINOR_OP_BE_4K_4B : SPINOR_OP_BE_4K; - - /* Support 8 x 4KB sectors at bottom */ - return spansion_erase_non_uniform(nor, addr, opcode, 0, SZ_32K); -} - -static int s25fs_s_setup(struct spi_nor *nor, const struct flash_info *info, - const struct spi_nor_flash_parameter *params) -{ - int ret; - u8 cfr3v; - - /* Bank Address Register is not supported */ - if (CONFIG_IS_ENABLED(SPI_FLASH_BAR)) - return -EOPNOTSUPP; - - /* - * Read CR3V to check if uniform sector is selected. If not, assign an - * erase hook that supports non-uniform erase. - */ - ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_CFR3V, - S25FS_S_RDAR_DUMMY, &cfr3v); - if (ret) - return ret; - if (!(cfr3v & SPINOR_REG_CYPRESS_CFR3_UNISECT)) - nor->erase = s25fs_s_erase_non_uniform; - - return spi_nor_default_setup(nor, info, params); -} - -static void s25fs_s_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->setup = s25fs_s_setup; -} - -static int s25fs_s_post_bfpt_fixup(struct spi_nor *nor, - const struct sfdp_parameter_header *header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) -{ - /* The erase size is set to 4K from BFPT, but it's wrong. Fix it. */ - nor->erase_opcode = SPINOR_OP_SE; - nor->mtd.erasesize = nor->info->sector_size; - - /* The S25FS-S chip family reports 512-byte pages in BFPT but - * in reality the write buffer still wraps at the safe default - * of 256 bytes. Overwrite the page size advertised by BFPT - * to get the writes working. - */ - params->page_size = 256; - - return 0; -} - -static void s25fs_s_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - /* - * The S25FS064S(8MB) supports 1-1-2 and 1-1-4 commands, but params for - * read ops in SFDP are wrong. The other density parts do not support - * 1-1-2 and 1-1-4 commands. - */ - if (params->size == SZ_8M) { - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_2], - 0, 8, SPINOR_OP_READ_1_1_2, - SNOR_PROTO_1_1_2); - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_4], - 0, 8, SPINOR_OP_READ_1_1_4, - SNOR_PROTO_1_1_4); - } else { - params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_2; - params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_4; - params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; - } - - /* Use volatile register to enable quad */ - params->quad_enable = s25fs_s_quad_enable; -} - -static struct spi_nor_fixups s25fs_s_fixups = { - .post_bfpt = s25fs_s_post_bfpt_fixup, - .post_sfdp = s25fs_s_post_sfdp_fixup, - .late_init = s25fs_s_late_init, -}; - -static int s25_s28_mdp_ready(struct spi_nor *nor) -{ - u32 addr; - int ret; - - for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { - ret = spansion_sr_ready(nor, addr, nor->rdsr_dummy); - if (ret < 0) - return ret; - else if (ret == 0) - return 0; - } - - return 1; -} - -static int s25_quad_enable(struct spi_nor *nor) -{ - u32 addr; - int ret; - - for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { - ret = spansion_quad_enable_volatile(nor, addr, 0); - if (ret) - return ret; - } - - return 0; -} - -static int s25_s28_erase_non_uniform(struct spi_nor *nor, loff_t addr) -{ - /* Support 32 x 4KB sectors at bottom */ - return spansion_erase_non_uniform(nor, addr, SPINOR_OP_BE_4K_4B, 0, - SZ_128K); -} - -static int s25_s28_setup(struct spi_nor *nor, const struct flash_info *info, - const struct spi_nor_flash_parameter *params) -{ - int ret; - u8 cr; - -#if CONFIG_IS_ENABLED(SPI_FLASH_BAR) - return -ENOTSUPP; /* Bank Address Register is not supported */ -#endif - /* - * S25FS256T has multiple sector architecture options, with selection of - * count and location of 128KB and 64KB sectors. This driver supports - * uniform 128KB only due to complexity of non-uniform layout. - */ - if (nor->info->id[4] == S25FS256T_ID4) { - ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_ARCFN, 8, - &cr); - if (ret) - return ret; - - if (cr) /* Option 0 (ARCFN[7:0] == 0x00) is uniform */ - return -EOPNOTSUPP; - - return spi_nor_default_setup(nor, info, params); - } - - /* - * Read CFR3V to check if uniform sector is selected. If not, assign an - * erase hook that supports non-uniform erase. - */ - ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_CFR3V, 0, &cr); - if (ret) - return ret; - if (!(cr & SPINOR_REG_CYPRESS_CFR3_UNISECT)) - nor->erase = s25_s28_erase_non_uniform; - - /* - * For the multi-die package parts, the ready() hook is needed to check - * all dies' status via read any register. - */ - if (nor->mtd.size > SZ_128M) - nor->ready = s25_s28_mdp_ready; - - return spi_nor_default_setup(nor, info, params); -} - -static void s25_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->setup = s25_s28_setup; - - /* - * Programming is supported only in 16-byte ECC data unit granularity. - * Byte-programming, bit-walking, or multiple program operations to the - * same ECC data unit without an erase are not allowed. - */ - params->writesize = 16; -} - -static int s25_s28_post_bfpt_fixup(struct spi_nor *nor, - const struct sfdp_parameter_header *header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) -{ - int ret; - u32 addr; - u8 cfr3v; - - /* erase size in case it is set to 4K from BFPT */ - nor->erase_opcode = SPINOR_OP_SE_4B; - nor->mtd.erasesize = nor->info->sector_size; - - /* - * The default address mode in multi-die package parts (>1Gb) may be - * 3- or 4-byte, depending on model number. BootROM code in some SoCs - * use 3-byte mode for backward compatibility and should switch to - * 4-byte mode after BootROM phase. Since registers in the 2nd die are - * mapped within 32-bit address space, we need to make sure the flash is - * in 4-byte address mode. The default address mode can be distinguished - * by BFPT 16th DWORD. Power cycle exits 4-byte address mode if default - * is 3-byte address mode. - */ - if (params->size > SZ_128M) { - if (bfpt->dwords[BFPT_DWORD(16)] & BFPT_DWORD16_EX4B_PWRCYC) { - ret = set_4byte(nor, nor->info, 1); - if (ret) - return ret; - } - nor->addr_mode_nbytes = 4; - } - - /* The default address mode in S25FS256T is 4. */ - if (nor->info->id[4] == S25FS256T_ID4) - nor->addr_mode_nbytes = 4; - - /* - * The page_size is set to 512B from BFPT, but it actually depends on - * the configuration register. Look up the CFR3V and determine the - * page_size. For multi-die package parts, use 512B only when the all - * dies are configured to 512B buffer. - */ - for (addr = 0; addr < params->size; addr += SZ_128M) { - ret = spansion_read_any_reg(nor, - addr + SPINOR_REG_CYPRESS_CFR3V, 0, - &cfr3v); - if (ret) - return ret; - - if (!(cfr3v & SPINOR_REG_CYPRESS_CFR3_PGSZ)) { - params->page_size = 256; - return 0; - } - } - params->page_size = 512; - - return 0; -} - -static void s25_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - if (nor->info->id[4] == S25FS256T_ID4) { - /* PP_1_1_4 is supported */ - params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; - } else { - /* READ_FAST_4B (0Ch) requires mode cycles*/ - params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; - /* PP_1_1_4 is not supported */ - params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; - /* Use volatile register to enable quad */ - params->quad_enable = s25_quad_enable; - } -} - -static struct spi_nor_fixups s25_fixups = { - .post_bfpt = s25_s28_post_bfpt_fixup, - .post_sfdp = s25_post_sfdp_fixup, - .late_init = s25_late_init, -}; - -static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info, - const struct spi_nor_flash_parameter *params) -{ - return -ENOTSUPP; /* Bank Address Register is not supported */ -} - -static void s25fl256l_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->setup = s25fl256l_setup; -} - -static struct spi_nor_fixups s25fl256l_fixups = { - .late_init = s25fl256l_late_init, -}; -#endif - -#ifdef CONFIG_SPI_FLASH_S28HX_T -/** - * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes. - * @nor: pointer to a 'struct spi_nor' - * - * This also sets the memory access latency cycles to 24 to allow the flash to - * run at up to 200MHz. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor) -{ - u32 addr; - u8 buf; - int ret; - - ret = write_enable(nor); - if (ret) - return ret; - - /* Use 24 dummy cycles for memory array reads. */ - for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { - ret = spansion_read_any_reg(nor, - addr + SPINOR_REG_CYPRESS_CFR2V, 0, - &buf); - if (ret) - return ret; - - buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK; - buf |= SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24; - ret = spansion_write_any_reg(nor, - addr + SPINOR_REG_CYPRESS_CFR2V, - buf); - if (ret) { - dev_warn(nor->dev, "failed to set default memory latency value: %d\n", ret); - return ret; - } - } - nor->read_dummy = 24; - - ret = write_enable(nor); - if (ret) - return ret; - - /* Set the octal and DTR enable bits. */ - buf = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN; - for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { - ret = spansion_write_any_reg(nor, - addr + SPINOR_REG_CYPRESS_CFR5V, - buf); - if (ret) { - dev_warn(nor->dev, "Failed to enable octal DTR mode\n"); - return ret; - } - } - - return 0; -} - -static void s28hx_t_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable; - nor->setup = s25_s28_setup; - - /* - * Programming is supported only in 16-byte ECC data unit granularity. - * Byte-programming, bit-walking, or multiple program operations to the - * same ECC data unit without an erase are not allowed. - */ - params->writesize = 16; -} - -static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - /* - * On older versions of the flash the xSPI Profile 1.0 table has the - * 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE. - */ - if (params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0) - params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode = - SPINOR_OP_CYPRESS_RD_FAST; - - params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; - - /* This flash is also missing the 4-byte Page Program opcode bit. */ - spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], - SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1); - /* - * Since xSPI Page Program opcode is backward compatible with - * Legacy SPI, use Legacy SPI opcode there as well. - */ - spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8_8_8_DTR], - SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR); - - /* - * The xSPI Profile 1.0 table advertises the number of additional - * address bytes needed for Read Status Register command as 0 but the - * actual value for that is 4. - */ - params->rdsr_addr_nbytes = 4; -} - -static struct spi_nor_fixups s28hx_t_fixups = { - .post_sfdp = s28hx_t_post_sfdp_fixup, - .post_bfpt = s25_s28_post_bfpt_fixup, - .late_init = s28hx_t_late_init, -}; -#endif /* CONFIG_SPI_FLASH_S28HX_T */ - -#ifdef CONFIG_SPI_FLASH_MT35XU -static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor) -{ - struct spi_mem_op op; - u8 buf; - u8 addr_width = 3; - int ret; - - /* Set dummy cycles for Fast Read to the default of 20. */ - ret = write_enable(nor); - if (ret) - return ret; - - buf = 20; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), - SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR1V, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &buf, 1)); - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) - return ret; - - ret = spi_nor_wait_till_ready(nor); - if (ret) - return ret; - - nor->read_dummy = 20; - - ret = write_enable(nor); - if (ret) - return ret; - - buf = SPINOR_MT_OCT_DTR; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), - SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR0V, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &buf, 1)); - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) { - dev_err(nor->dev, "Failed to enable octal DTR mode\n"); - return ret; - } - - return 0; -} - -static void mt35xu512aba_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->octal_dtr_enable = spi_nor_micron_octal_dtr_enable; -} - -static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - /* Set the Fast Read settings. */ - params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], - 0, 20, SPINOR_OP_MT_DTR_RD, - SNOR_PROTO_8_8_8_DTR); - - params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; - - nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; - params->rdsr_dummy = 8; - params->rdsr_addr_nbytes = 0; - - /* - * SCCR Map 22nd DWORD does not indicate DTR Octal Mode Enable - * for MT35XU512ABA but is actually supported by device. - */ - nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; - - /* - * The BFPT quad enable field is set to a reserved value so the quad - * enable function is ignored by spi_nor_parse_bfpt(). Make sure we - * disable it. - */ - params->quad_enable = NULL; -} - -static struct spi_nor_fixups mt35xu512aba_fixups = { - .post_sfdp = mt35xu512aba_post_sfdp_fixup, - .late_init = mt35xu512aba_late_init, -}; -#endif /* CONFIG_SPI_FLASH_MT35XU */ - -#if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX) -/** - * spi_nor_macronix_octal_dtr_enable() - Enable octal DTR on Macronix flashes. - * @nor: pointer to a 'struct spi_nor' - * - * Set Macronix max dummy cycles 20 to allow the flash to run at fastest frequency. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_macronix_octal_dtr_enable(struct spi_nor *nor) -{ - struct spi_mem_op op; - int ret; - u8 buf; - - ret = write_enable(nor); - if (ret) - return ret; - - buf = SPINOR_REG_MXIC_DC_20; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1), - SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_DC, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &buf, 1)); - - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) - return ret; - - ret = spi_nor_wait_till_ready(nor); - if (ret) - return ret; - - nor->read_dummy = MXIC_MAX_DC; - ret = write_enable(nor); - if (ret) - return ret; - - buf = SPINOR_REG_MXIC_OPI_DTR_EN; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1), - SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_MODE, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &buf, 1)); - - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) { - dev_err(nor->dev, "Failed to enable octal DTR mode\n"); - return ret; - } - nor->reg_proto = SNOR_PROTO_8_8_8_DTR; - - return 0; -} - -static void macronix_octal_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->octal_dtr_enable = spi_nor_macronix_octal_dtr_enable; -} - -static void macronix_octal_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - /* - * Adding SNOR_HWCAPS_PP_8_8_8_DTR in hwcaps.mask when - * SPI_NOR_OCTAL_DTR_READ flag exists. - */ - if (params->hwcaps.mask & SNOR_HWCAPS_READ_8_8_8_DTR) - params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; -} - -static struct spi_nor_fixups macronix_octal_fixups = { - .post_sfdp = macronix_octal_post_sfdp_fixup, - .late_init = macronix_octal_late_init, -}; -#endif /* CONFIG_SPI_FLASH_MACRONIX */ - -#if CONFIG_IS_ENABLED(SPI_FLASH_WINBOND) - -#define WINBOND_NOR_OP_SELDIE 0xc2 /* Select active die */ - -struct winbond_nor_priv { - unsigned int n_dice; -}; - -/** - * winbond_nor_select_die() - Set active die. - * @nor: pointer to 'struct spi_nor'. - * @die: die to set active. - * - * Certain Winbond chips feature more than a single die. This is mostly hidden - * to the user, except that some chips may experience time deviation when - * modifying the status bits between dies, which in some corner cases may - * produce problematic races. Being able to explicitly select a die to check its - * state in this case may be useful. - * - * Return: 0 on success, -errno otherwise. - */ -static int winbond_nor_select_die(struct spi_nor *nor, u8 die) -{ - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(WINBOND_NOR_OP_SELDIE, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &die, 0)); - - int ret; - - spi_nor_setup_op(nor, &op, SNOR_PROTO_1_1_1); - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) - debug("Error %d selecting die %d\n", ret, die); - - return ret; -} - -static int winbond_nor_multi_die_ready(struct spi_nor *nor) -{ - struct winbond_nor_priv *winbond_priv = nor->priv; - unsigned int n_dice = winbond_priv ? winbond_priv->n_dice : 1; - int ret, i; - - for (i = 0; i < n_dice; i++) { - ret = winbond_nor_select_die(nor, i); - if (ret) - return ret; - - ret = spi_nor_sr_ready(nor); - if (ret <= 0) - return ret; - } - - return 1; -} - -static void winbond_nor_multi_die_post_sfdp_fixups(struct spi_nor *nor, - struct spi_nor_flash_parameter *param) -{ - struct winbond_nor_priv *winbond_priv; - - winbond_priv = kmalloc(sizeof(*winbond_priv), GFP_KERNEL); - if (!winbond_priv) - return; - - winbond_priv->n_dice = param->size / SZ_64M; - - /* - * SFDP supports dice numbers, but this information is only available in - * optional additional tables which are not provided by these chips. - * Dice number has an impact though, because these devices need extra - * care when reading the busy bit. - */ - nor->priv = winbond_priv; - nor->ready = winbond_nor_multi_die_ready; -} - -static struct spi_nor_fixups winbond_nor_multi_die_fixups = { - .post_sfdp = winbond_nor_multi_die_post_sfdp_fixups, -}; -#endif /* CONFIG_SPI_FLASH_WINBOND */ - /** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed * @nor: pointer to a 'struct spi_nor' * @@ -3644,63 +2790,6 @@ void spi_nor_set_fixups(struct spi_nor *nor) { if (nor->manufacturer->set_fixups) nor->manufacturer->set_fixups(nor); - -#ifdef CONFIG_SPI_FLASH_SPANSION - if (JEDEC_MFR(nor->info) == SNOR_MFR_CYPRESS) { - switch (nor->info->id[1]) { - case 0x2a: /* S25HL (QSPI, 3.3V) */ - case 0x2b: /* S25HS (QSPI, 1.8V) */ - nor->fixups = &s25_fixups; - break; - -#ifdef CONFIG_SPI_FLASH_S28HX_T - case 0x5a: /* S28HL (Octal, 3.3V) */ - case 0x5b: /* S28HS (Octal, 1.8V) */ - nor->fixups = &s28hx_t_fixups; - break; -#endif - - default: - break; - } - } - - if (CONFIG_IS_ENABLED(SPI_FLASH_BAR) && - !strcmp(nor->info->name, "s25fl256l")) - nor->fixups = &s25fl256l_fixups; - - /* For FS-S (family ID = 0x81) */ - if (JEDEC_MFR(nor->info) == SNOR_MFR_SPANSION && nor->info->id[5] == 0x81) - nor->fixups = &s25fs_s_fixups; -#endif - -#ifdef CONFIG_SPI_FLASH_MT35XU - if (!strcmp(nor->info->name, "mt35xu512aba")) - nor->fixups = &mt35xu512aba_fixups; -#endif - -#if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX) - if (JEDEC_MFR(nor->info) == SNOR_MFR_MACRONIX && - nor->info->flags & SPI_NOR_OCTAL_DTR_READ) - nor->fixups = ¯onix_octal_fixups; -#endif /* SPI_FLASH_MACRONIX */ - -#if CONFIG_IS_ENABLED(SPI_FLASH_WINBOND) - if (JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND) { - u8 multi_die_models[][2] = { - { 0x40, 0x21 }, /* W25Q01JV */ - { 0x70, 0x22 }, /* W25Q02JV */ - }; - int i; - - for (i = 0; i < sizeof(multi_die_models) / 2; i++) { - if (!memcmp(nor->info->id + 1, multi_die_models[i], 2)) { - nor->fixups = &winbond_nor_multi_die_fixups; - break; - } - } - } -#endif /* SPI_FLASH_WINBOND */ } int spi_nor_scan(struct spi_nor *nor) diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index 02c29ccf78c..d1030959b2c 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -5,6 +5,7 @@ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <linux/sizes.h> #include <linux/mtd/spi-nor.h> #include "sf_internal.h" @@ -140,7 +141,110 @@ static const struct flash_info winbond_nor_parts[] = { { INFO("w77q51nw", 0xef8a1a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, }; +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + +#define WINBOND_NOR_OP_SELDIE 0xc2 /* Select active die */ + +struct winbond_nor_priv { + unsigned int n_dice; +}; + +/** + * winbond_nor_select_die() - Set active die. + * @nor: pointer to 'struct spi_nor'. + * @die: die to set active. + * + * Certain Winbond chips feature more than a single die. This is mostly hidden + * to the user, except that some chips may experience time deviation when + * modifying the status bits between dies, which in some corner cases may + * produce problematic races. Being able to explicitly select a die to check its + * state in this case may be useful. + * + * Return: 0 on success, -errno otherwise. + */ +static int winbond_nor_select_die(struct spi_nor *nor, u8 die) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(WINBOND_NOR_OP_SELDIE, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &die, 0)); + + int ret; + + spi_nor_setup_op(nor, &op, SNOR_PROTO_1_1_1); + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + debug("Error %d selecting die %d\n", ret, die); + + return ret; +} + +static int winbond_nor_multi_die_ready(struct spi_nor *nor) +{ + struct winbond_nor_priv *winbond_priv = nor->priv; + unsigned int n_dice = winbond_priv ? winbond_priv->n_dice : 1; + int ret, i; + + for (i = 0; i < n_dice; i++) { + ret = winbond_nor_select_die(nor, i); + if (ret) + return ret; + + ret = spi_nor_sr_ready(nor); + if (ret <= 0) + return ret; + } + + return 1; +} + +static void winbond_nor_multi_die_post_sfdp_fixups(struct spi_nor *nor, + struct spi_nor_flash_parameter *param) +{ + struct winbond_nor_priv *winbond_priv; + + winbond_priv = kmalloc(sizeof(*winbond_priv), GFP_KERNEL); + if (!winbond_priv) + return; + + winbond_priv->n_dice = param->size / SZ_64M; + + /* + * SFDP supports dice numbers, but this information is only available in + * optional additional tables which are not provided by these chips. + * Dice number has an impact though, because these devices need extra + * care when reading the busy bit. + */ + nor->priv = winbond_priv; + nor->ready = winbond_nor_multi_die_ready; +} + +static struct spi_nor_fixups winbond_nor_multi_die_fixups = { + .post_sfdp = winbond_nor_multi_die_post_sfdp_fixups, +}; + +static void winbond_set_fixups(struct spi_nor *nor) +{ + u8 multi_die_models[][2] = { + { 0x40, 0x21 }, /* W25Q01JV */ + { 0x70, 0x22 }, /* W25Q02JV */ + }; + int i; + + for (i = 0; i < sizeof(multi_die_models) / 2; i++) { + if (!memcmp(nor->info->id + 1, multi_die_models[i], 2)) { + nor->fixups = &winbond_nor_multi_die_fixups; + break; + } + } +} +#endif /* !CONFIG_IS_ENABLED(SPI_FLASH_TINY) */ + const struct spi_nor_manufacturer spi_nor_winbond = { .parts = winbond_nor_parts, .nparts = ARRAY_SIZE(winbond_nor_parts), +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + .set_fixups = winbond_set_fixups, +#endif }; -- 2.53.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 4/4] mtd: spi-nor: move fixups to manufacturer drivers @ 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay 0 siblings, 0 replies; 15+ messages in thread From: Takahiro Kuwano via B4 Relay @ 2026-10-16 1:43 UTC (permalink / raw) To: u-boot Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev, Takahiro Kuwano From: Takahiro Kuwano <takahiro.kuwano@infineon.com> Move chip specific fixups from core to manufacturer drivers. As manufacturer drivers are used in tiny as well, all fixups migrated from core need to be excluded in CONFIG_SPI_FLASH_TINY. Some helper functions used in fixups are exposed from core and some need to be guarded by CONFIG_SPI_FLASH_TINY to avoid name conflict with local functions in tiny. Signed-off-by: Takahiro Kuwano <takahiro.kuwano@infineon.com> --- drivers/mtd/spi/macronix.c | 89 ++++ drivers/mtd/spi/micron-st.c | 99 +++++ drivers/mtd/spi/sf_internal.h | 10 + drivers/mtd/spi/spansion.c | 627 +++++++++++++++++++++++++++ drivers/mtd/spi/spi-nor-core.c | 929 +---------------------------------------- drivers/mtd/spi/winbond.c | 104 +++++ 6 files changed, 938 insertions(+), 920 deletions(-) diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c index 87843978cad..9ca55fc4f99 100644 --- a/drivers/mtd/spi/macronix.c +++ b/drivers/mtd/spi/macronix.c @@ -5,6 +5,7 @@ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <dm/device_compat.h> #include <linux/mtd/spi-nor.h> #include "sf_internal.h" @@ -59,7 +60,95 @@ static const struct flash_info macronix_nor_parts[] = { { INFO("mx25uw6345g", 0xc28437, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, }; +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) +/** + * spi_nor_macronix_octal_dtr_enable() - Enable octal DTR on Macronix flashes. + * @nor: pointer to a 'struct spi_nor' + * + * Set Macronix max dummy cycles 20 to allow the flash to run at fastest frequency. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_macronix_octal_dtr_enable(struct spi_nor *nor) +{ + struct spi_mem_op op; + int ret; + u8 buf; + + ret = write_enable(nor); + if (ret) + return ret; + + buf = SPINOR_REG_MXIC_DC_20; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1), + SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_DC, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + return ret; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + return ret; + + nor->read_dummy = MXIC_MAX_DC; + ret = write_enable(nor); + if (ret) + return ret; + + buf = SPINOR_REG_MXIC_OPI_DTR_EN; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1), + SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_MODE, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) { + dev_err(nor->dev, "Failed to enable octal DTR mode\n"); + return ret; + } + nor->reg_proto = SNOR_PROTO_8_8_8_DTR; + + return 0; +} + +static void macronix_octal_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->octal_dtr_enable = spi_nor_macronix_octal_dtr_enable; +} + +static void macronix_octal_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* + * Adding SNOR_HWCAPS_PP_8_8_8_DTR in hwcaps.mask when + * SPI_NOR_OCTAL_DTR_READ flag exists. + */ + if (params->hwcaps.mask & SNOR_HWCAPS_READ_8_8_8_DTR) + params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; +} + +static struct spi_nor_fixups macronix_octal_fixups = { + .post_sfdp = macronix_octal_post_sfdp_fixup, + .late_init = macronix_octal_late_init, +}; + +static void macronix_set_fixups(struct spi_nor *nor) +{ + if (nor->info->flags & SPI_NOR_OCTAL_DTR_READ) + nor->fixups = ¯onix_octal_fixups; +} +#endif + const struct spi_nor_manufacturer spi_nor_macronix = { .parts = macronix_nor_parts, .nparts = ARRAY_SIZE(macronix_nor_parts), +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + .set_fixups = macronix_set_fixups, +#endif }; diff --git a/drivers/mtd/spi/micron-st.c b/drivers/mtd/spi/micron-st.c index 2d47f1c60c0..9982e9d660a 100644 --- a/drivers/mtd/spi/micron-st.c +++ b/drivers/mtd/spi/micron-st.c @@ -5,6 +5,7 @@ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <dm/device_compat.h> #include <linux/mtd/spi-nor.h> #include "sf_internal.h" @@ -59,9 +60,107 @@ static const struct flash_info st_nor_parts[] = { { INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0) }, }; +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) && CONFIG_IS_ENABLED(SPI_FLASH_MT35XU) +static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor) +{ + struct spi_mem_op op; + u8 buf; + u8 addr_width = 3; + int ret; + + /* Set dummy cycles for Fast Read to the default of 20. */ + ret = write_enable(nor); + if (ret) + return ret; + + buf = 20; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), + SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR1V, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + return ret; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + return ret; + + nor->read_dummy = 20; + + ret = write_enable(nor); + if (ret) + return ret; + + buf = SPINOR_MT_OCT_DTR; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), + SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR0V, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) { + dev_err(nor->dev, "Failed to enable octal DTR mode\n"); + return ret; + } + + return 0; +} + +static void mt35xu512aba_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->octal_dtr_enable = spi_nor_micron_octal_dtr_enable; +} + +static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* Set the Fast Read settings. */ + params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], + 0, 20, SPINOR_OP_MT_DTR_RD, + SNOR_PROTO_8_8_8_DTR); + + params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; + + nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; + params->rdsr_dummy = 8; + params->rdsr_addr_nbytes = 0; + + /* + * SCCR Map 22nd DWORD does not indicate DTR Octal Mode Enable + * for MT35XU512ABA but is actually supported by device. + */ + nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; + + /* + * The BFPT quad enable field is set to a reserved value so the quad + * enable function is ignored by spi_nor_parse_bfpt(). Make sure we + * disable it. + */ + params->quad_enable = NULL; +} + +static struct spi_nor_fixups mt35xu512aba_fixups = { + .post_sfdp = mt35xu512aba_post_sfdp_fixup, + .late_init = mt35xu512aba_late_init, +}; + +static void micron_set_fixups(struct spi_nor *nor) +{ + if (!strcmp(nor->info->name, "mt35xu512aba")) + nor->fixups = &mt35xu512aba_fixups; +} +#endif + const struct spi_nor_manufacturer spi_nor_micron = { .parts = micron_nor_parts, .nparts = ARRAY_SIZE(micron_nor_parts), +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) && CONFIG_IS_ENABLED(SPI_FLASH_MT35XU) + .set_fixups = micron_set_fixups, +#endif }; const struct spi_nor_manufacturer spi_nor_st = { diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index f96895c7439..2be206b2651 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -203,6 +203,12 @@ static inline int spi_nor_parse_sfdp(struct spi_nor *nor, #endif #if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) +int write_enable(struct spi_nor *nor); +int set_4byte(struct spi_nor *nor, const struct flash_info *info, int enable); +int spi_nor_sr_ready(struct spi_nor *nor); +int spi_nor_wait_till_ready(struct spi_nor *nor); +int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op *op, + void *buf); void spi_nor_set_read_settings(struct spi_nor_read_command *read, u8 num_mode_clocks, u8 num_wait_states, @@ -212,6 +218,10 @@ int spansion_read_cr_quad_enable(struct spi_nor *nor); int macronix_quad_enable(struct spi_nor *nor); #endif +void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode, + enum spi_nor_protocol proto); +int spi_nor_default_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params); int spi_nor_hwcaps_read2cmd(u32 hwcaps); int spansion_no_read_cr_quad_enable(struct spi_nor *nor); diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index 405f5bf5e79..1dd38667062 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -5,6 +5,8 @@ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <dm/device_compat.h> +#include <linux/sizes.h> #include <linux/mtd/spi-nor.h> #include "sf_internal.h" @@ -67,7 +69,632 @@ static const struct flash_info spansion_nor_parts[] = { #endif }; +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + +/* Use ID byte 4 to distinguish S25FS256T and S25Hx-T */ +#define S25FS256T_ID4 (0x08) + +/* Number of dummy cycle for Read Any Register (RDAR) op. */ +#define S25FS_S_RDAR_DUMMY 8 + +static int spansion_read_any_reg(struct spi_nor *nor, u32 addr, u8 dummy, + u8 *val) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), + SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 0), + SPI_MEM_OP_DUMMY(dummy, 0), + SPI_MEM_OP_DATA_IN(1, NULL, 0)); + u8 buf[2]; + int ret; + + spi_nor_setup_op(nor, &op, nor->reg_proto); + + /* + * In Octal DTR mode, the number of address bytes is always 4 regardless + * of addressing mode setting. + */ + if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) + op.addr.nbytes = 4; + + /* + * We don't want to read only one byte in DTR mode. So, read 2 and then + * discard the second byte. + */ + if (spi_nor_protocol_is_dtr(nor->reg_proto)) + op.data.nbytes = 2; + + ret = spi_nor_read_write_reg(nor, &op, buf); + if (ret) + return ret; + + *val = buf[0]; + + return 0; +} + +static int spansion_write_any_reg(struct spi_nor *nor, u32 addr, u8 val) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), + SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, NULL, 1)); + + return spi_nor_read_write_reg(nor, &op, &val); +} + +/** + * spansion_quad_enable_volatile() - enable Quad I/O mode in volatile register. + * @nor: pointer to a 'struct spi_nor' + * @addr_base: base address of register (can be >0 in multi-die parts) + * @dummy: number of dummy cycles for register read + * + * It is recommended to update volatile registers in the field application due + * to a risk of the non-volatile registers corruption by power interrupt. This + * function sets Quad Enable bit in CFR1 volatile. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_quad_enable_volatile(struct spi_nor *nor, u32 addr_base, + u8 dummy) +{ + u32 addr = addr_base + SPINOR_REG_CYPRESS_CFR1V; + + u8 cr; + int ret; + + /* Check current Quad Enable bit value. */ + ret = spansion_read_any_reg(nor, addr, dummy, &cr); + if (ret < 0) { + dev_dbg(nor->dev, + "error while reading configuration register\n"); + return -EINVAL; + } + + if (cr & CR_QUAD_EN_SPAN) + return 0; + + cr |= CR_QUAD_EN_SPAN; + + write_enable(nor); + + ret = spansion_write_any_reg(nor, addr, cr); + + if (ret < 0) { + dev_dbg(nor->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* Read back and check it. */ + ret = spansion_read_any_reg(nor, addr, dummy, &cr); + if (ret || !(cr & CR_QUAD_EN_SPAN)) { + dev_dbg(nor->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +/* + * Read status register 1 by using Read Any Register command to support multi + * die package parts. + */ +static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy) +{ + u32 reg_addr = addr_base + SPINOR_REG_CYPRESS_STR1V; + u8 sr; + int ret; + + ret = spansion_read_any_reg(nor, reg_addr, dummy, &sr); + if (ret < 0) + return ret; + + if (sr & (SR_E_ERR | SR_P_ERR)) { + if (sr & SR_E_ERR) + dev_dbg(nor->dev, "Erase Error occurred\n"); + else + dev_dbg(nor->dev, "Programming Error occurred\n"); + + nor->write_reg(nor, SPINOR_OP_CYPRESS_CLPEF, NULL, 0); + return -EIO; + } + + return !(sr & SR_WIP); +} + +/** + * spansion_erase_non_uniform() - erase non-uniform sectors for Spansion/Cypress + * chips + * @nor: pointer to a 'struct spi_nor' + * @addr: address of the sector to erase + * @opcode_4k: opcode for 4K sector erase + * @ovlsz_top: size of overlaid portion at the top address + * @ovlsz_btm: size of overlaid portion at the bottom address + * + * Erase an address range on the nor chip that can contain 4KB sectors overlaid + * on top and/or bottom. The appropriate erase opcode and size are chosen by + * address to erase and size of overlaid portion. + * + * Return: number of bytes erased on success, -errno otherwise. + */ +static int spansion_erase_non_uniform(struct spi_nor *nor, u32 addr, + u8 opcode_4k, u32 ovlsz_top, + u32 ovlsz_btm) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_width, addr, 0), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); + struct mtd_info *mtd = &nor->mtd; + u32 erasesize; + int ret; + + /* 4KB sectors */ + if (op.addr.val < ovlsz_btm || + op.addr.val >= mtd->size - ovlsz_top) { + op.cmd.opcode = opcode_4k; + erasesize = SZ_4K; + + /* Non-overlaid portion in the normal sector at the bottom */ + } else if (op.addr.val == ovlsz_btm) { + op.cmd.opcode = nor->erase_opcode; + erasesize = mtd->erasesize - ovlsz_btm; + + /* Non-overlaid portion in the normal sector at the top */ + } else if (op.addr.val == mtd->size - mtd->erasesize) { + op.cmd.opcode = nor->erase_opcode; + erasesize = mtd->erasesize - ovlsz_top; + + /* Normal sectors */ + } else { + op.cmd.opcode = nor->erase_opcode; + erasesize = mtd->erasesize; + } + + spi_nor_setup_op(nor, &op, nor->write_proto); + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + return ret; + + return erasesize; +} + +static int s25fs_s_quad_enable(struct spi_nor *nor) +{ + return spansion_quad_enable_volatile(nor, 0, S25FS_S_RDAR_DUMMY); +} + +static int s25fs_s_erase_non_uniform(struct spi_nor *nor, loff_t addr) +{ + u8 opcode = nor->addr_width == 4 ? SPINOR_OP_BE_4K_4B : SPINOR_OP_BE_4K; + + /* Support 8 x 4KB sectors at bottom */ + return spansion_erase_non_uniform(nor, addr, opcode, 0, SZ_32K); +} + +static int s25fs_s_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) +{ + int ret; + u8 cfr3v; + + /* Bank Address Register is not supported */ + if (CONFIG_IS_ENABLED(SPI_FLASH_BAR)) + return -EOPNOTSUPP; + + /* + * Read CR3V to check if uniform sector is selected. If not, assign an + * erase hook that supports non-uniform erase. + */ + ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_CFR3V, + S25FS_S_RDAR_DUMMY, &cfr3v); + if (ret) + return ret; + if (!(cfr3v & SPINOR_REG_CYPRESS_CFR3_UNISECT)) + nor->erase = s25fs_s_erase_non_uniform; + + return spi_nor_default_setup(nor, info, params); +} + +static void s25fs_s_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->setup = s25fs_s_setup; +} + +static int s25fs_s_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + /* The erase size is set to 4K from BFPT, but it's wrong. Fix it. */ + nor->erase_opcode = SPINOR_OP_SE; + nor->mtd.erasesize = nor->info->sector_size; + + /* The S25FS-S chip family reports 512-byte pages in BFPT but + * in reality the write buffer still wraps at the safe default + * of 256 bytes. Overwrite the page size advertised by BFPT + * to get the writes working. + */ + params->page_size = 256; + + return 0; +} + +static void s25fs_s_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* + * The S25FS064S(8MB) supports 1-1-2 and 1-1-4 commands, but params for + * read ops in SFDP are wrong. The other density parts do not support + * 1-1-2 and 1-1-4 commands. + */ + if (params->size == SZ_8M) { + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_2], + 0, 8, SPINOR_OP_READ_1_1_2, + SNOR_PROTO_1_1_2); + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_4], + 0, 8, SPINOR_OP_READ_1_1_4, + SNOR_PROTO_1_1_4); + } else { + params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_2; + params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_4; + params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; + } + + /* Use volatile register to enable quad */ + params->quad_enable = s25fs_s_quad_enable; +} + +static struct spi_nor_fixups s25fs_s_fixups = { + .post_bfpt = s25fs_s_post_bfpt_fixup, + .post_sfdp = s25fs_s_post_sfdp_fixup, + .late_init = s25fs_s_late_init, +}; + +static int s25_s28_mdp_ready(struct spi_nor *nor) +{ + u32 addr; + int ret; + + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_sr_ready(nor, addr, nor->rdsr_dummy); + if (ret < 0) + return ret; + else if (ret == 0) + return 0; + } + + return 1; +} + +static int s25_quad_enable(struct spi_nor *nor) +{ + u32 addr; + int ret; + + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_quad_enable_volatile(nor, addr, 0); + if (ret) + return ret; + } + + return 0; +} + +static int s25_s28_erase_non_uniform(struct spi_nor *nor, loff_t addr) +{ + /* Support 32 x 4KB sectors at bottom */ + return spansion_erase_non_uniform(nor, addr, SPINOR_OP_BE_4K_4B, 0, + SZ_128K); +} + +static int s25_s28_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) +{ + int ret; + u8 cr; + +#if CONFIG_IS_ENABLED(SPI_FLASH_BAR) + return -ENOTSUPP; /* Bank Address Register is not supported */ +#endif + /* + * S25FS256T has multiple sector architecture options, with selection of + * count and location of 128KB and 64KB sectors. This driver supports + * uniform 128KB only due to complexity of non-uniform layout. + */ + if (nor->info->id[4] == S25FS256T_ID4) { + ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_ARCFN, 8, + &cr); + if (ret) + return ret; + + if (cr) /* Option 0 (ARCFN[7:0] == 0x00) is uniform */ + return -EOPNOTSUPP; + + return spi_nor_default_setup(nor, info, params); + } + + /* + * Read CFR3V to check if uniform sector is selected. If not, assign an + * erase hook that supports non-uniform erase. + */ + ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_CFR3V, 0, &cr); + if (ret) + return ret; + if (!(cr & SPINOR_REG_CYPRESS_CFR3_UNISECT)) + nor->erase = s25_s28_erase_non_uniform; + + /* + * For the multi-die package parts, the ready() hook is needed to check + * all dies' status via read any register. + */ + if (nor->mtd.size > SZ_128M) + nor->ready = s25_s28_mdp_ready; + + return spi_nor_default_setup(nor, info, params); +} + +static void s25_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->setup = s25_s28_setup; + + /* + * Programming is supported only in 16-byte ECC data unit granularity. + * Byte-programming, bit-walking, or multiple program operations to the + * same ECC data unit without an erase are not allowed. + */ + params->writesize = 16; +} + +static int s25_s28_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + int ret; + u32 addr; + u8 cfr3v; + + /* erase size in case it is set to 4K from BFPT */ + nor->erase_opcode = SPINOR_OP_SE_4B; + nor->mtd.erasesize = nor->info->sector_size; + + /* + * The default address mode in multi-die package parts (>1Gb) may be + * 3- or 4-byte, depending on model number. BootROM code in some SoCs + * use 3-byte mode for backward compatibility and should switch to + * 4-byte mode after BootROM phase. Since registers in the 2nd die are + * mapped within 32-bit address space, we need to make sure the flash is + * in 4-byte address mode. The default address mode can be distinguished + * by BFPT 16th DWORD. Power cycle exits 4-byte address mode if default + * is 3-byte address mode. + */ + if (params->size > SZ_128M) { + if (bfpt->dwords[BFPT_DWORD(16)] & BFPT_DWORD16_EX4B_PWRCYC) { + ret = set_4byte(nor, nor->info, 1); + if (ret) + return ret; + } + nor->addr_mode_nbytes = 4; + } + + /* The default address mode in S25FS256T is 4. */ + if (nor->info->id[4] == S25FS256T_ID4) + nor->addr_mode_nbytes = 4; + + /* + * The page_size is set to 512B from BFPT, but it actually depends on + * the configuration register. Look up the CFR3V and determine the + * page_size. For multi-die package parts, use 512B only when the all + * dies are configured to 512B buffer. + */ + for (addr = 0; addr < params->size; addr += SZ_128M) { + ret = spansion_read_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR3V, 0, + &cfr3v); + if (ret) + return ret; + + if (!(cfr3v & SPINOR_REG_CYPRESS_CFR3_PGSZ)) { + params->page_size = 256; + return 0; + } + } + params->page_size = 512; + + return 0; +} + +static void s25_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + if (nor->info->id[4] == S25FS256T_ID4) { + /* PP_1_1_4 is supported */ + params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; + } else { + /* READ_FAST_4B (0Ch) requires mode cycles*/ + params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; + /* PP_1_1_4 is not supported */ + params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; + /* Use volatile register to enable quad */ + params->quad_enable = s25_quad_enable; + } +} + +static struct spi_nor_fixups s25_fixups = { + .post_bfpt = s25_s28_post_bfpt_fixup, + .post_sfdp = s25_post_sfdp_fixup, + .late_init = s25_late_init, +}; + +static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) +{ + return -ENOTSUPP; /* Bank Address Register is not supported */ +} + +static void s25fl256l_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->setup = s25fl256l_setup; +} + +static struct spi_nor_fixups s25fl256l_fixups = { + .late_init = s25fl256l_late_init, +}; + +#ifdef CONFIG_SPI_FLASH_S28HX_T +/** + * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes. + * @nor: pointer to a 'struct spi_nor' + * + * This also sets the memory access latency cycles to 24 to allow the flash to + * run at up to 200MHz. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor) +{ + u32 addr; + u8 buf; + int ret; + + ret = write_enable(nor); + if (ret) + return ret; + + /* Use 24 dummy cycles for memory array reads. */ + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_read_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR2V, 0, + &buf); + if (ret) + return ret; + + buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK; + buf |= SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24; + ret = spansion_write_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR2V, + buf); + if (ret) { + dev_warn(nor->dev, "failed to set default memory latency value: %d\n", ret); + return ret; + } + } + nor->read_dummy = 24; + + ret = write_enable(nor); + if (ret) + return ret; + + /* Set the octal and DTR enable bits. */ + buf = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN; + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_write_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR5V, + buf); + if (ret) { + dev_warn(nor->dev, "Failed to enable octal DTR mode\n"); + return ret; + } + } + + return 0; +} + +static void s28hx_t_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + nor->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable; + nor->setup = s25_s28_setup; + + /* + * Programming is supported only in 16-byte ECC data unit granularity. + * Byte-programming, bit-walking, or multiple program operations to the + * same ECC data unit without an erase are not allowed. + */ + params->writesize = 16; +} + +static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* + * On older versions of the flash the xSPI Profile 1.0 table has the + * 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE. + */ + if (params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0) + params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode = + SPINOR_OP_CYPRESS_RD_FAST; + + params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; + + /* This flash is also missing the 4-byte Page Program opcode bit. */ + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], + SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1); + /* + * Since xSPI Page Program opcode is backward compatible with + * Legacy SPI, use Legacy SPI opcode there as well. + */ + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8_8_8_DTR], + SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR); + + /* + * The xSPI Profile 1.0 table advertises the number of additional + * address bytes needed for Read Status Register command as 0 but the + * actual value for that is 4. + */ + params->rdsr_addr_nbytes = 4; +} + +static struct spi_nor_fixups s28hx_t_fixups = { + .post_sfdp = s28hx_t_post_sfdp_fixup, + .post_bfpt = s25_s28_post_bfpt_fixup, + .late_init = s28hx_t_late_init, +}; +#endif /* CONFIG_SPI_FLASH_S28HX_T */ + +static void spansion_set_fixups(struct spi_nor *nor) +{ + if (JEDEC_MFR(nor->info) == SNOR_MFR_CYPRESS) { + switch (nor->info->id[1]) { + case 0x2a: /* S25HL (QSPI, 3.3V) */ + case 0x2b: /* S25HS (QSPI, 1.8V) */ + nor->fixups = &s25_fixups; + break; + +#ifdef CONFIG_SPI_FLASH_S28HX_T + case 0x5a: /* S28HL (Octal, 3.3V) */ + case 0x5b: /* S28HS (Octal, 1.8V) */ + nor->fixups = &s28hx_t_fixups; + break; +#endif + + default: + break; + } + } + + if (CONFIG_IS_ENABLED(SPI_FLASH_BAR) && + !strcmp(nor->info->name, "s25fl256l")) + nor->fixups = &s25fl256l_fixups; + + /* For FS-S (family ID = 0x81) */ + if (JEDEC_MFR(nor->info) == SNOR_MFR_SPANSION && nor->info->id[5] == 0x81) + nor->fixups = &s25fs_s_fixups; +} +#endif /* !CONFIG_IS_ENABLED(SPI_FLASH_TINY) */ + const struct spi_nor_manufacturer spi_nor_spansion = { .parts = spansion_nor_parts, .nparts = ARRAY_SIZE(spansion_nor_parts), +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + .set_fixups = spansion_set_fixups, +#endif }; diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index d107828092c..6e61b5653bd 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -123,8 +123,8 @@ void spi_nor_setup_op(const struct spi_nor *nor, } } -static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op - *op, void *buf) +int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op *op, + void *buf) { if (op->data.dir == SPI_MEM_DATA_IN) op->data.buf.in = buf; @@ -165,55 +165,6 @@ static int spi_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) return spi_nor_read_write_reg(nor, &op, buf); } -#ifdef CONFIG_SPI_FLASH_SPANSION -static int spansion_read_any_reg(struct spi_nor *nor, u32 addr, u8 dummy, - u8 *val) -{ - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), - SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 0), - SPI_MEM_OP_DUMMY(dummy, 0), - SPI_MEM_OP_DATA_IN(1, NULL, 0)); - u8 buf[2]; - int ret; - - spi_nor_setup_op(nor, &op, nor->reg_proto); - - /* - * In Octal DTR mode, the number of address bytes is always 4 regardless - * of addressing mode setting. - */ - if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) - op.addr.nbytes = 4; - - /* - * We don't want to read only one byte in DTR mode. So, read 2 and then - * discard the second byte. - */ - if (spi_nor_protocol_is_dtr(nor->reg_proto)) - op.data.nbytes = 2; - - ret = spi_nor_read_write_reg(nor, &op, buf); - if (ret) - return ret; - - *val = buf[0]; - - return 0; -} - -static int spansion_write_any_reg(struct spi_nor *nor, u32 addr, u8 val) -{ - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), - SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, NULL, 1)); - - return spi_nor_read_write_reg(nor, &op, &val); -} -#endif - static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, u_char *buf) { @@ -472,7 +423,7 @@ static int write_sr3(struct spi_nor *nor, u8 val) * Set write enable latch with Write Enable command. * Returns negative if error occurred. */ -static int write_enable(struct spi_nor *nor) +int write_enable(struct spi_nor *nor) { return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0); } @@ -577,8 +528,7 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, #endif /* !CONFIG_IS_ENABLED(SPI_FLASH_BAR) */ /* Enable/disable 4-byte addressing mode. */ -static int set_4byte(struct spi_nor *nor, const struct flash_info *info, - int enable) +int set_4byte(struct spi_nor *nor, const struct flash_info *info, int enable) { int status; bool need_wren = false; @@ -626,36 +576,7 @@ static int set_4byte(struct spi_nor *nor, const struct flash_info *info, } } -#ifdef CONFIG_SPI_FLASH_SPANSION -/* - * Read status register 1 by using Read Any Register command to support multi - * die package parts. - */ -static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy) -{ - u32 reg_addr = addr_base + SPINOR_REG_CYPRESS_STR1V; - u8 sr; - int ret; - - ret = spansion_read_any_reg(nor, reg_addr, dummy, &sr); - if (ret < 0) - return ret; - - if (sr & (SR_E_ERR | SR_P_ERR)) { - if (sr & SR_E_ERR) - dev_dbg(nor->dev, "Erase Error occurred\n"); - else - dev_dbg(nor->dev, "Programming Error occurred\n"); - - nor->write_reg(nor, SPINOR_OP_CYPRESS_CLPEF, NULL, 0); - return -EIO; - } - - return !(sr & SR_WIP); -} -#endif - -static int spi_nor_sr_ready(struct spi_nor *nor) +int spi_nor_sr_ready(struct spi_nor *nor) { int sr = read_sr(nor); @@ -745,7 +666,7 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor, return -ETIMEDOUT; } -static int spi_nor_wait_till_ready(struct spi_nor *nor) +int spi_nor_wait_till_ready(struct spi_nor *nor) { return spi_nor_wait_till_ready_with_timeout(nor, DEFAULT_READY_WAIT_JIFFIES); @@ -1035,67 +956,6 @@ err: return ret; } -#ifdef CONFIG_SPI_FLASH_SPANSION -/** - * spansion_erase_non_uniform() - erase non-uniform sectors for Spansion/Cypress - * chips - * @nor: pointer to a 'struct spi_nor' - * @addr: address of the sector to erase - * @opcode_4k: opcode for 4K sector erase - * @ovlsz_top: size of overlaid portion at the top address - * @ovlsz_btm: size of overlaid portion at the bottom address - * - * Erase an address range on the nor chip that can contain 4KB sectors overlaid - * on top and/or bottom. The appropriate erase opcode and size are chosen by - * address to erase and size of overlaid portion. - * - * Return: number of bytes erased on success, -errno otherwise. - */ -static int spansion_erase_non_uniform(struct spi_nor *nor, u32 addr, - u8 opcode_4k, u32 ovlsz_top, - u32 ovlsz_btm) -{ - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_width, addr, 0), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); - struct mtd_info *mtd = &nor->mtd; - u32 erasesize; - int ret; - - /* 4KB sectors */ - if (op.addr.val < ovlsz_btm || - op.addr.val >= mtd->size - ovlsz_top) { - op.cmd.opcode = opcode_4k; - erasesize = SZ_4K; - - /* Non-overlaid portion in the normal sector at the bottom */ - } else if (op.addr.val == ovlsz_btm) { - op.cmd.opcode = nor->erase_opcode; - erasesize = mtd->erasesize - ovlsz_btm; - - /* Non-overlaid portion in the normal sector at the top */ - } else if (op.addr.val == mtd->size - mtd->erasesize) { - op.cmd.opcode = nor->erase_opcode; - erasesize = mtd->erasesize - ovlsz_top; - - /* Normal sectors */ - } else { - op.cmd.opcode = nor->erase_opcode; - erasesize = mtd->erasesize; - } - - spi_nor_setup_op(nor, &op, nor->write_proto); - - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) - return ret; - - return erasesize; -} -#endif - #if defined(CONFIG_SPI_FLASH_LOCK) #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) /* Write status register and ensure bits in mask match written values */ @@ -1980,61 +1840,6 @@ int macronix_quad_enable(struct spi_nor *nor) } #endif -#ifdef CONFIG_SPI_FLASH_SPANSION -/** - * spansion_quad_enable_volatile() - enable Quad I/O mode in volatile register. - * @nor: pointer to a 'struct spi_nor' - * @addr_base: base address of register (can be >0 in multi-die parts) - * @dummy: number of dummy cycles for register read - * - * It is recommended to update volatile registers in the field application due - * to a risk of the non-volatile registers corruption by power interrupt. This - * function sets Quad Enable bit in CFR1 volatile. - * - * Return: 0 on success, -errno otherwise. - */ -static int spansion_quad_enable_volatile(struct spi_nor *nor, u32 addr_base, - u8 dummy) -{ - u32 addr = addr_base + SPINOR_REG_CYPRESS_CFR1V; - - u8 cr; - int ret; - - /* Check current Quad Enable bit value. */ - ret = spansion_read_any_reg(nor, addr, dummy, &cr); - if (ret < 0) { - dev_dbg(nor->dev, - "error while reading configuration register\n"); - return -EINVAL; - } - - if (cr & CR_QUAD_EN_SPAN) - return 0; - - cr |= CR_QUAD_EN_SPAN; - - write_enable(nor); - - ret = spansion_write_any_reg(nor, addr, cr); - - if (ret < 0) { - dev_dbg(nor->dev, - "error while writing configuration register\n"); - return -EINVAL; - } - - /* Read back and check it. */ - ret = spansion_read_any_reg(nor, addr, dummy, &cr); - if (ret || !(cr & CR_QUAD_EN_SPAN)) { - dev_dbg(nor->dev, "Spansion Quad bit not set\n"); - return -EINVAL; - } - - return 0; -} -#endif - #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) /* * Write status Register and configuration register with 2 bytes @@ -2165,7 +1970,7 @@ spi_nor_set_read_settings(struct spi_nor_read_command *read, read->proto = proto; } -static void +void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode, enum spi_nor_protocol proto) @@ -2755,9 +2560,8 @@ static int spi_nor_select_erase(struct spi_nor *nor, return 0; } -static int spi_nor_default_setup(struct spi_nor *nor, - const struct flash_info *info, - const struct spi_nor_flash_parameter *params) +int spi_nor_default_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) { u32 shared_mask; bool enable_quad_io; @@ -2809,664 +2613,6 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, return nor->setup(nor, info, params); } -#ifdef CONFIG_SPI_FLASH_SPANSION - -/* Use ID byte 4 to distinguish S25FS256T and S25Hx-T */ -#define S25FS256T_ID4 (0x08) - -/* Number of dummy cycle for Read Any Register (RDAR) op. */ -#define S25FS_S_RDAR_DUMMY 8 - -static int s25fs_s_quad_enable(struct spi_nor *nor) -{ - return spansion_quad_enable_volatile(nor, 0, S25FS_S_RDAR_DUMMY); -} - -static int s25fs_s_erase_non_uniform(struct spi_nor *nor, loff_t addr) -{ - u8 opcode = nor->addr_width == 4 ? SPINOR_OP_BE_4K_4B : SPINOR_OP_BE_4K; - - /* Support 8 x 4KB sectors at bottom */ - return spansion_erase_non_uniform(nor, addr, opcode, 0, SZ_32K); -} - -static int s25fs_s_setup(struct spi_nor *nor, const struct flash_info *info, - const struct spi_nor_flash_parameter *params) -{ - int ret; - u8 cfr3v; - - /* Bank Address Register is not supported */ - if (CONFIG_IS_ENABLED(SPI_FLASH_BAR)) - return -EOPNOTSUPP; - - /* - * Read CR3V to check if uniform sector is selected. If not, assign an - * erase hook that supports non-uniform erase. - */ - ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_CFR3V, - S25FS_S_RDAR_DUMMY, &cfr3v); - if (ret) - return ret; - if (!(cfr3v & SPINOR_REG_CYPRESS_CFR3_UNISECT)) - nor->erase = s25fs_s_erase_non_uniform; - - return spi_nor_default_setup(nor, info, params); -} - -static void s25fs_s_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->setup = s25fs_s_setup; -} - -static int s25fs_s_post_bfpt_fixup(struct spi_nor *nor, - const struct sfdp_parameter_header *header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) -{ - /* The erase size is set to 4K from BFPT, but it's wrong. Fix it. */ - nor->erase_opcode = SPINOR_OP_SE; - nor->mtd.erasesize = nor->info->sector_size; - - /* The S25FS-S chip family reports 512-byte pages in BFPT but - * in reality the write buffer still wraps at the safe default - * of 256 bytes. Overwrite the page size advertised by BFPT - * to get the writes working. - */ - params->page_size = 256; - - return 0; -} - -static void s25fs_s_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - /* - * The S25FS064S(8MB) supports 1-1-2 and 1-1-4 commands, but params for - * read ops in SFDP are wrong. The other density parts do not support - * 1-1-2 and 1-1-4 commands. - */ - if (params->size == SZ_8M) { - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_2], - 0, 8, SPINOR_OP_READ_1_1_2, - SNOR_PROTO_1_1_2); - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_4], - 0, 8, SPINOR_OP_READ_1_1_4, - SNOR_PROTO_1_1_4); - } else { - params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_2; - params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_4; - params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; - } - - /* Use volatile register to enable quad */ - params->quad_enable = s25fs_s_quad_enable; -} - -static struct spi_nor_fixups s25fs_s_fixups = { - .post_bfpt = s25fs_s_post_bfpt_fixup, - .post_sfdp = s25fs_s_post_sfdp_fixup, - .late_init = s25fs_s_late_init, -}; - -static int s25_s28_mdp_ready(struct spi_nor *nor) -{ - u32 addr; - int ret; - - for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { - ret = spansion_sr_ready(nor, addr, nor->rdsr_dummy); - if (ret < 0) - return ret; - else if (ret == 0) - return 0; - } - - return 1; -} - -static int s25_quad_enable(struct spi_nor *nor) -{ - u32 addr; - int ret; - - for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { - ret = spansion_quad_enable_volatile(nor, addr, 0); - if (ret) - return ret; - } - - return 0; -} - -static int s25_s28_erase_non_uniform(struct spi_nor *nor, loff_t addr) -{ - /* Support 32 x 4KB sectors at bottom */ - return spansion_erase_non_uniform(nor, addr, SPINOR_OP_BE_4K_4B, 0, - SZ_128K); -} - -static int s25_s28_setup(struct spi_nor *nor, const struct flash_info *info, - const struct spi_nor_flash_parameter *params) -{ - int ret; - u8 cr; - -#if CONFIG_IS_ENABLED(SPI_FLASH_BAR) - return -ENOTSUPP; /* Bank Address Register is not supported */ -#endif - /* - * S25FS256T has multiple sector architecture options, with selection of - * count and location of 128KB and 64KB sectors. This driver supports - * uniform 128KB only due to complexity of non-uniform layout. - */ - if (nor->info->id[4] == S25FS256T_ID4) { - ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_ARCFN, 8, - &cr); - if (ret) - return ret; - - if (cr) /* Option 0 (ARCFN[7:0] == 0x00) is uniform */ - return -EOPNOTSUPP; - - return spi_nor_default_setup(nor, info, params); - } - - /* - * Read CFR3V to check if uniform sector is selected. If not, assign an - * erase hook that supports non-uniform erase. - */ - ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_CFR3V, 0, &cr); - if (ret) - return ret; - if (!(cr & SPINOR_REG_CYPRESS_CFR3_UNISECT)) - nor->erase = s25_s28_erase_non_uniform; - - /* - * For the multi-die package parts, the ready() hook is needed to check - * all dies' status via read any register. - */ - if (nor->mtd.size > SZ_128M) - nor->ready = s25_s28_mdp_ready; - - return spi_nor_default_setup(nor, info, params); -} - -static void s25_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->setup = s25_s28_setup; - - /* - * Programming is supported only in 16-byte ECC data unit granularity. - * Byte-programming, bit-walking, or multiple program operations to the - * same ECC data unit without an erase are not allowed. - */ - params->writesize = 16; -} - -static int s25_s28_post_bfpt_fixup(struct spi_nor *nor, - const struct sfdp_parameter_header *header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) -{ - int ret; - u32 addr; - u8 cfr3v; - - /* erase size in case it is set to 4K from BFPT */ - nor->erase_opcode = SPINOR_OP_SE_4B; - nor->mtd.erasesize = nor->info->sector_size; - - /* - * The default address mode in multi-die package parts (>1Gb) may be - * 3- or 4-byte, depending on model number. BootROM code in some SoCs - * use 3-byte mode for backward compatibility and should switch to - * 4-byte mode after BootROM phase. Since registers in the 2nd die are - * mapped within 32-bit address space, we need to make sure the flash is - * in 4-byte address mode. The default address mode can be distinguished - * by BFPT 16th DWORD. Power cycle exits 4-byte address mode if default - * is 3-byte address mode. - */ - if (params->size > SZ_128M) { - if (bfpt->dwords[BFPT_DWORD(16)] & BFPT_DWORD16_EX4B_PWRCYC) { - ret = set_4byte(nor, nor->info, 1); - if (ret) - return ret; - } - nor->addr_mode_nbytes = 4; - } - - /* The default address mode in S25FS256T is 4. */ - if (nor->info->id[4] == S25FS256T_ID4) - nor->addr_mode_nbytes = 4; - - /* - * The page_size is set to 512B from BFPT, but it actually depends on - * the configuration register. Look up the CFR3V and determine the - * page_size. For multi-die package parts, use 512B only when the all - * dies are configured to 512B buffer. - */ - for (addr = 0; addr < params->size; addr += SZ_128M) { - ret = spansion_read_any_reg(nor, - addr + SPINOR_REG_CYPRESS_CFR3V, 0, - &cfr3v); - if (ret) - return ret; - - if (!(cfr3v & SPINOR_REG_CYPRESS_CFR3_PGSZ)) { - params->page_size = 256; - return 0; - } - } - params->page_size = 512; - - return 0; -} - -static void s25_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - if (nor->info->id[4] == S25FS256T_ID4) { - /* PP_1_1_4 is supported */ - params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; - } else { - /* READ_FAST_4B (0Ch) requires mode cycles*/ - params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; - /* PP_1_1_4 is not supported */ - params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; - /* Use volatile register to enable quad */ - params->quad_enable = s25_quad_enable; - } -} - -static struct spi_nor_fixups s25_fixups = { - .post_bfpt = s25_s28_post_bfpt_fixup, - .post_sfdp = s25_post_sfdp_fixup, - .late_init = s25_late_init, -}; - -static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info, - const struct spi_nor_flash_parameter *params) -{ - return -ENOTSUPP; /* Bank Address Register is not supported */ -} - -static void s25fl256l_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->setup = s25fl256l_setup; -} - -static struct spi_nor_fixups s25fl256l_fixups = { - .late_init = s25fl256l_late_init, -}; -#endif - -#ifdef CONFIG_SPI_FLASH_S28HX_T -/** - * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes. - * @nor: pointer to a 'struct spi_nor' - * - * This also sets the memory access latency cycles to 24 to allow the flash to - * run at up to 200MHz. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor) -{ - u32 addr; - u8 buf; - int ret; - - ret = write_enable(nor); - if (ret) - return ret; - - /* Use 24 dummy cycles for memory array reads. */ - for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { - ret = spansion_read_any_reg(nor, - addr + SPINOR_REG_CYPRESS_CFR2V, 0, - &buf); - if (ret) - return ret; - - buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK; - buf |= SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24; - ret = spansion_write_any_reg(nor, - addr + SPINOR_REG_CYPRESS_CFR2V, - buf); - if (ret) { - dev_warn(nor->dev, "failed to set default memory latency value: %d\n", ret); - return ret; - } - } - nor->read_dummy = 24; - - ret = write_enable(nor); - if (ret) - return ret; - - /* Set the octal and DTR enable bits. */ - buf = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN; - for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { - ret = spansion_write_any_reg(nor, - addr + SPINOR_REG_CYPRESS_CFR5V, - buf); - if (ret) { - dev_warn(nor->dev, "Failed to enable octal DTR mode\n"); - return ret; - } - } - - return 0; -} - -static void s28hx_t_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable; - nor->setup = s25_s28_setup; - - /* - * Programming is supported only in 16-byte ECC data unit granularity. - * Byte-programming, bit-walking, or multiple program operations to the - * same ECC data unit without an erase are not allowed. - */ - params->writesize = 16; -} - -static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - /* - * On older versions of the flash the xSPI Profile 1.0 table has the - * 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE. - */ - if (params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0) - params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode = - SPINOR_OP_CYPRESS_RD_FAST; - - params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; - - /* This flash is also missing the 4-byte Page Program opcode bit. */ - spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], - SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1); - /* - * Since xSPI Page Program opcode is backward compatible with - * Legacy SPI, use Legacy SPI opcode there as well. - */ - spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8_8_8_DTR], - SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR); - - /* - * The xSPI Profile 1.0 table advertises the number of additional - * address bytes needed for Read Status Register command as 0 but the - * actual value for that is 4. - */ - params->rdsr_addr_nbytes = 4; -} - -static struct spi_nor_fixups s28hx_t_fixups = { - .post_sfdp = s28hx_t_post_sfdp_fixup, - .post_bfpt = s25_s28_post_bfpt_fixup, - .late_init = s28hx_t_late_init, -}; -#endif /* CONFIG_SPI_FLASH_S28HX_T */ - -#ifdef CONFIG_SPI_FLASH_MT35XU -static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor) -{ - struct spi_mem_op op; - u8 buf; - u8 addr_width = 3; - int ret; - - /* Set dummy cycles for Fast Read to the default of 20. */ - ret = write_enable(nor); - if (ret) - return ret; - - buf = 20; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), - SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR1V, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &buf, 1)); - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) - return ret; - - ret = spi_nor_wait_till_ready(nor); - if (ret) - return ret; - - nor->read_dummy = 20; - - ret = write_enable(nor); - if (ret) - return ret; - - buf = SPINOR_MT_OCT_DTR; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), - SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR0V, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &buf, 1)); - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) { - dev_err(nor->dev, "Failed to enable octal DTR mode\n"); - return ret; - } - - return 0; -} - -static void mt35xu512aba_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->octal_dtr_enable = spi_nor_micron_octal_dtr_enable; -} - -static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - /* Set the Fast Read settings. */ - params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], - 0, 20, SPINOR_OP_MT_DTR_RD, - SNOR_PROTO_8_8_8_DTR); - - params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; - - nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; - params->rdsr_dummy = 8; - params->rdsr_addr_nbytes = 0; - - /* - * SCCR Map 22nd DWORD does not indicate DTR Octal Mode Enable - * for MT35XU512ABA but is actually supported by device. - */ - nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; - - /* - * The BFPT quad enable field is set to a reserved value so the quad - * enable function is ignored by spi_nor_parse_bfpt(). Make sure we - * disable it. - */ - params->quad_enable = NULL; -} - -static struct spi_nor_fixups mt35xu512aba_fixups = { - .post_sfdp = mt35xu512aba_post_sfdp_fixup, - .late_init = mt35xu512aba_late_init, -}; -#endif /* CONFIG_SPI_FLASH_MT35XU */ - -#if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX) -/** - * spi_nor_macronix_octal_dtr_enable() - Enable octal DTR on Macronix flashes. - * @nor: pointer to a 'struct spi_nor' - * - * Set Macronix max dummy cycles 20 to allow the flash to run at fastest frequency. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_macronix_octal_dtr_enable(struct spi_nor *nor) -{ - struct spi_mem_op op; - int ret; - u8 buf; - - ret = write_enable(nor); - if (ret) - return ret; - - buf = SPINOR_REG_MXIC_DC_20; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1), - SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_DC, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &buf, 1)); - - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) - return ret; - - ret = spi_nor_wait_till_ready(nor); - if (ret) - return ret; - - nor->read_dummy = MXIC_MAX_DC; - ret = write_enable(nor); - if (ret) - return ret; - - buf = SPINOR_REG_MXIC_OPI_DTR_EN; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1), - SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_MODE, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &buf, 1)); - - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) { - dev_err(nor->dev, "Failed to enable octal DTR mode\n"); - return ret; - } - nor->reg_proto = SNOR_PROTO_8_8_8_DTR; - - return 0; -} - -static void macronix_octal_late_init(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - nor->octal_dtr_enable = spi_nor_macronix_octal_dtr_enable; -} - -static void macronix_octal_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - /* - * Adding SNOR_HWCAPS_PP_8_8_8_DTR in hwcaps.mask when - * SPI_NOR_OCTAL_DTR_READ flag exists. - */ - if (params->hwcaps.mask & SNOR_HWCAPS_READ_8_8_8_DTR) - params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; -} - -static struct spi_nor_fixups macronix_octal_fixups = { - .post_sfdp = macronix_octal_post_sfdp_fixup, - .late_init = macronix_octal_late_init, -}; -#endif /* CONFIG_SPI_FLASH_MACRONIX */ - -#if CONFIG_IS_ENABLED(SPI_FLASH_WINBOND) - -#define WINBOND_NOR_OP_SELDIE 0xc2 /* Select active die */ - -struct winbond_nor_priv { - unsigned int n_dice; -}; - -/** - * winbond_nor_select_die() - Set active die. - * @nor: pointer to 'struct spi_nor'. - * @die: die to set active. - * - * Certain Winbond chips feature more than a single die. This is mostly hidden - * to the user, except that some chips may experience time deviation when - * modifying the status bits between dies, which in some corner cases may - * produce problematic races. Being able to explicitly select a die to check its - * state in this case may be useful. - * - * Return: 0 on success, -errno otherwise. - */ -static int winbond_nor_select_die(struct spi_nor *nor, u8 die) -{ - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(WINBOND_NOR_OP_SELDIE, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &die, 0)); - - int ret; - - spi_nor_setup_op(nor, &op, SNOR_PROTO_1_1_1); - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) - debug("Error %d selecting die %d\n", ret, die); - - return ret; -} - -static int winbond_nor_multi_die_ready(struct spi_nor *nor) -{ - struct winbond_nor_priv *winbond_priv = nor->priv; - unsigned int n_dice = winbond_priv ? winbond_priv->n_dice : 1; - int ret, i; - - for (i = 0; i < n_dice; i++) { - ret = winbond_nor_select_die(nor, i); - if (ret) - return ret; - - ret = spi_nor_sr_ready(nor); - if (ret <= 0) - return ret; - } - - return 1; -} - -static void winbond_nor_multi_die_post_sfdp_fixups(struct spi_nor *nor, - struct spi_nor_flash_parameter *param) -{ - struct winbond_nor_priv *winbond_priv; - - winbond_priv = kmalloc(sizeof(*winbond_priv), GFP_KERNEL); - if (!winbond_priv) - return; - - winbond_priv->n_dice = param->size / SZ_64M; - - /* - * SFDP supports dice numbers, but this information is only available in - * optional additional tables which are not provided by these chips. - * Dice number has an impact though, because these devices need extra - * care when reading the busy bit. - */ - nor->priv = winbond_priv; - nor->ready = winbond_nor_multi_die_ready; -} - -static struct spi_nor_fixups winbond_nor_multi_die_fixups = { - .post_sfdp = winbond_nor_multi_die_post_sfdp_fixups, -}; -#endif /* CONFIG_SPI_FLASH_WINBOND */ - /** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed * @nor: pointer to a 'struct spi_nor' * @@ -3644,63 +2790,6 @@ void spi_nor_set_fixups(struct spi_nor *nor) { if (nor->manufacturer->set_fixups) nor->manufacturer->set_fixups(nor); - -#ifdef CONFIG_SPI_FLASH_SPANSION - if (JEDEC_MFR(nor->info) == SNOR_MFR_CYPRESS) { - switch (nor->info->id[1]) { - case 0x2a: /* S25HL (QSPI, 3.3V) */ - case 0x2b: /* S25HS (QSPI, 1.8V) */ - nor->fixups = &s25_fixups; - break; - -#ifdef CONFIG_SPI_FLASH_S28HX_T - case 0x5a: /* S28HL (Octal, 3.3V) */ - case 0x5b: /* S28HS (Octal, 1.8V) */ - nor->fixups = &s28hx_t_fixups; - break; -#endif - - default: - break; - } - } - - if (CONFIG_IS_ENABLED(SPI_FLASH_BAR) && - !strcmp(nor->info->name, "s25fl256l")) - nor->fixups = &s25fl256l_fixups; - - /* For FS-S (family ID = 0x81) */ - if (JEDEC_MFR(nor->info) == SNOR_MFR_SPANSION && nor->info->id[5] == 0x81) - nor->fixups = &s25fs_s_fixups; -#endif - -#ifdef CONFIG_SPI_FLASH_MT35XU - if (!strcmp(nor->info->name, "mt35xu512aba")) - nor->fixups = &mt35xu512aba_fixups; -#endif - -#if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX) - if (JEDEC_MFR(nor->info) == SNOR_MFR_MACRONIX && - nor->info->flags & SPI_NOR_OCTAL_DTR_READ) - nor->fixups = ¯onix_octal_fixups; -#endif /* SPI_FLASH_MACRONIX */ - -#if CONFIG_IS_ENABLED(SPI_FLASH_WINBOND) - if (JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND) { - u8 multi_die_models[][2] = { - { 0x40, 0x21 }, /* W25Q01JV */ - { 0x70, 0x22 }, /* W25Q02JV */ - }; - int i; - - for (i = 0; i < sizeof(multi_die_models) / 2; i++) { - if (!memcmp(nor->info->id + 1, multi_die_models[i], 2)) { - nor->fixups = &winbond_nor_multi_die_fixups; - break; - } - } - } -#endif /* SPI_FLASH_WINBOND */ } int spi_nor_scan(struct spi_nor *nor) diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index 02c29ccf78c..d1030959b2c 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -5,6 +5,7 @@ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <linux/sizes.h> #include <linux/mtd/spi-nor.h> #include "sf_internal.h" @@ -140,7 +141,110 @@ static const struct flash_info winbond_nor_parts[] = { { INFO("w77q51nw", 0xef8a1a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, }; +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + +#define WINBOND_NOR_OP_SELDIE 0xc2 /* Select active die */ + +struct winbond_nor_priv { + unsigned int n_dice; +}; + +/** + * winbond_nor_select_die() - Set active die. + * @nor: pointer to 'struct spi_nor'. + * @die: die to set active. + * + * Certain Winbond chips feature more than a single die. This is mostly hidden + * to the user, except that some chips may experience time deviation when + * modifying the status bits between dies, which in some corner cases may + * produce problematic races. Being able to explicitly select a die to check its + * state in this case may be useful. + * + * Return: 0 on success, -errno otherwise. + */ +static int winbond_nor_select_die(struct spi_nor *nor, u8 die) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(WINBOND_NOR_OP_SELDIE, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &die, 0)); + + int ret; + + spi_nor_setup_op(nor, &op, SNOR_PROTO_1_1_1); + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + debug("Error %d selecting die %d\n", ret, die); + + return ret; +} + +static int winbond_nor_multi_die_ready(struct spi_nor *nor) +{ + struct winbond_nor_priv *winbond_priv = nor->priv; + unsigned int n_dice = winbond_priv ? winbond_priv->n_dice : 1; + int ret, i; + + for (i = 0; i < n_dice; i++) { + ret = winbond_nor_select_die(nor, i); + if (ret) + return ret; + + ret = spi_nor_sr_ready(nor); + if (ret <= 0) + return ret; + } + + return 1; +} + +static void winbond_nor_multi_die_post_sfdp_fixups(struct spi_nor *nor, + struct spi_nor_flash_parameter *param) +{ + struct winbond_nor_priv *winbond_priv; + + winbond_priv = kmalloc(sizeof(*winbond_priv), GFP_KERNEL); + if (!winbond_priv) + return; + + winbond_priv->n_dice = param->size / SZ_64M; + + /* + * SFDP supports dice numbers, but this information is only available in + * optional additional tables which are not provided by these chips. + * Dice number has an impact though, because these devices need extra + * care when reading the busy bit. + */ + nor->priv = winbond_priv; + nor->ready = winbond_nor_multi_die_ready; +} + +static struct spi_nor_fixups winbond_nor_multi_die_fixups = { + .post_sfdp = winbond_nor_multi_die_post_sfdp_fixups, +}; + +static void winbond_set_fixups(struct spi_nor *nor) +{ + u8 multi_die_models[][2] = { + { 0x40, 0x21 }, /* W25Q01JV */ + { 0x70, 0x22 }, /* W25Q02JV */ + }; + int i; + + for (i = 0; i < sizeof(multi_die_models) / 2; i++) { + if (!memcmp(nor->info->id + 1, multi_die_models[i], 2)) { + nor->fixups = &winbond_nor_multi_die_fixups; + break; + } + } +} +#endif /* !CONFIG_IS_ENABLED(SPI_FLASH_TINY) */ + const struct spi_nor_manufacturer spi_nor_winbond = { .parts = winbond_nor_parts, .nparts = ARRAY_SIZE(winbond_nor_parts), +#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY) + .set_fixups = winbond_set_fixups, +#endif }; -- 2.53.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v3 0/4] mtd: spi-nor: split SFDP, ID database, and fixups 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay ` (4 preceding siblings ...) (?) @ 2026-10-16 18:26 ` Tom Rini 2026-10-21 1:42 ` Takahiro.Kuwano -1 siblings, 1 reply; 15+ messages in thread From: Tom Rini @ 2026-10-16 18:26 UTC (permalink / raw) To: Takahiro Kuwano Cc: u-boot, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev [-- Attachment #1: Type: text/plain, Size: 1431 bytes --] On Fri, Oct 16, 2026 at 10:43:41AM +0900, Takahiro Kuwano wrote: > The spi-nor-core.c contains optional logics like SFDP and manufcaturer > specific fixups. The spi-nor-ids.c has single large ID database. There > are many #ifdef directives in those files and that negatively affects > readability and maintainability. > > This series, as the first step of cleanup, move SFDP logic, IDs, and > fixups to newly source files. Reworking, renaming, and reformating > existing code is not a scope of this series and further cleanup will be > taken place in follow-up patches. > > Here is the code size impact when applying this series. > Measured by my AMD Zynq-7000 (ARM32) environment with SFDP and all > manufcaturers are enabled. > > SPI-NOR: > text data bss dec hex filename > BEFORE 720685 14084 0 734769 b3631 u-boot > AFTER 721827 14156 0 735983 b3aef u-boot > DELTA +1142 +72 > > TINY: > text data bss dec hex filename > BEFORE 77399 3128 248 80775 13b87 spl/u-boot-spl > AFTER 77589 3200 248 81037 13c8d spl/u-boot-spl > DELTA +190 +72 So this leads to imx28_btt3 and imx28_xea overflowing in CI on link. Maybe it needs the tiny flag set? I think the rest of the growth is reasonable enough, and boards can disable part vendors they don't need. -- Tom [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 228 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* RE: [PATCH v3 0/4] mtd: spi-nor: split SFDP, ID database, and fixups 2026-10-16 18:26 ` [PATCH v3 0/4] mtd: spi-nor: split SFDP, ID database, and fixups Tom Rini @ 2026-10-21 1:42 ` Takahiro.Kuwano 2026-10-21 14:37 ` Tom Rini 0 siblings, 1 reply; 15+ messages in thread From: Takahiro.Kuwano @ 2026-10-21 1:42 UTC (permalink / raw) To: trini; +Cc: u-boot, vigneshr, raymond.mao, vjardin, festevam, ehristev Hi Tom, > On Fri, Oct 16, 2026 at 10:43:41AM +0900, Takahiro Kuwano wrote: > > > The spi-nor-core.c contains optional logics like SFDP and manufcaturer > > specific fixups. The spi-nor-ids.c has single large ID database. There > > are many #ifdef directives in those files and that negatively affects > > readability and maintainability. > > > > This series, as the first step of cleanup, move SFDP logic, IDs, and > > fixups to newly source files. Reworking, renaming, and reformating > > existing code is not a scope of this series and further cleanup will be > > taken place in follow-up patches. > > > > Here is the code size impact when applying this series. > > Measured by my AMD Zynq-7000 (ARM32) environment with SFDP and all > > manufcaturers are enabled. > > > > SPI-NOR: > > text data bss dec hex filename > > BEFORE 720685 14084 0 734769 b3631 u-boot > > AFTER 721827 14156 0 735983 b3aef u-boot > > DELTA +1142 +72 > > > > TINY: > > text data bss dec hex filename > > BEFORE 77399 3128 248 80775 13b87 spl/u-boot-spl > > AFTER 77589 3200 248 81037 13c8d spl/u-boot-spl > > DELTA +190 +72 > > So this leads to imx28_btt3 and imx28_xea overflowing in CI on link. I don't see any errors in my local. Something different from CI config. imx28_btt3_defconfig: text data bss dec hex filename BEFORE 37947 2896 0 40843 9f8b spl/u-boot-spl AFTER 38003 2912 0 40915 9fd3 spl/u-boot-spl +56 +16 imx28_xea_defconfig: text data bss dec hex filename BEFORE 38004 2816 0 40820 9f74 spl/u-boot-spl AFTER 38060 2832 0 40892 9fbc spl/u-boot-spl +56 +16 Could you share the exact CI error or size report? > Maybe it needs the tiny flag set? I think the rest of the growth is > reasonable enough, and boards can disable part vendors they don't need. SPI_FLASH_TINY is set by default in SPL build and I confirmed spi-nor-tiny.o in both builds. > > -- > Tom Thanks, Takahiro ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 0/4] mtd: spi-nor: split SFDP, ID database, and fixups 2026-10-21 1:42 ` Takahiro.Kuwano @ 2026-10-21 14:37 ` Tom Rini 2026-10-22 2:58 ` Takahiro.Kuwano 0 siblings, 1 reply; 15+ messages in thread From: Tom Rini @ 2026-10-21 14:37 UTC (permalink / raw) To: Takahiro.Kuwano Cc: u-boot, vigneshr, raymond.mao, vjardin, festevam, ehristev [-- Attachment #1: Type: text/plain, Size: 2354 bytes --] On Wed, Oct 21, 2026 at 01:42:00AM +0000, Takahiro.Kuwano@infineon.com wrote: > Hi Tom, > > > On Fri, Oct 16, 2026 at 10:43:41AM +0900, Takahiro Kuwano wrote: > > > > > The spi-nor-core.c contains optional logics like SFDP and manufcaturer > > > specific fixups. The spi-nor-ids.c has single large ID database. There > > > are many #ifdef directives in those files and that negatively affects > > > readability and maintainability. > > > > > > This series, as the first step of cleanup, move SFDP logic, IDs, and > > > fixups to newly source files. Reworking, renaming, and reformating > > > existing code is not a scope of this series and further cleanup will be > > > taken place in follow-up patches. > > > > > > Here is the code size impact when applying this series. > > > Measured by my AMD Zynq-7000 (ARM32) environment with SFDP and all > > > manufcaturers are enabled. > > > > > > SPI-NOR: > > > text data bss dec hex filename > > > BEFORE 720685 14084 0 734769 b3631 u-boot > > > AFTER 721827 14156 0 735983 b3aef u-boot > > > DELTA +1142 +72 > > > > > > TINY: > > > text data bss dec hex filename > > > BEFORE 77399 3128 248 80775 13b87 spl/u-boot-spl > > > AFTER 77589 3200 248 81037 13c8d spl/u-boot-spl > > > DELTA +190 +72 > > > > So this leads to imx28_btt3 and imx28_xea overflowing in CI on link. > > I don't see any errors in my local. Something different from CI config. > > imx28_btt3_defconfig: > text data bss dec hex filename > BEFORE 37947 2896 0 40843 9f8b spl/u-boot-spl > AFTER 38003 2912 0 40915 9fd3 spl/u-boot-spl > +56 +16 > > imx28_xea_defconfig: > text data bss dec hex filename > BEFORE 38004 2816 0 40820 9f74 spl/u-boot-spl > AFTER 38060 2832 0 40892 9fbc spl/u-boot-spl > +56 +16 > > Could you share the exact CI error or size report? What toolchain are you using? CI uses the 14.2.0 ones from kernel.org: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/14.2.0/ and the CI run is: https://git.u-boot-project.org/u-boot/u-boot/-/jobs/115650#L3163 -- Tom [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 228 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* RE: [PATCH v3 0/4] mtd: spi-nor: split SFDP, ID database, and fixups 2026-10-21 14:37 ` Tom Rini @ 2026-10-22 2:58 ` Takahiro.Kuwano 0 siblings, 0 replies; 15+ messages in thread From: Takahiro.Kuwano @ 2026-10-22 2:58 UTC (permalink / raw) To: trini; +Cc: u-boot, vigneshr, raymond.mao, vjardin, festevam, ehristev > On Wed, Oct 21, 2026 at 01:42:00AM +0000, Takahiro.Kuwano@infineon.com wrote: > > Hi Tom, > > > > > On Fri, Oct 16, 2026 at 10:43:41AM +0900, Takahiro Kuwano wrote: > > > > > > > The spi-nor-core.c contains optional logics like SFDP and manufcaturer > > > > specific fixups. The spi-nor-ids.c has single large ID database. There > > > > are many #ifdef directives in those files and that negatively affects > > > > readability and maintainability. > > > > > > > > This series, as the first step of cleanup, move SFDP logic, IDs, and > > > > fixups to newly source files. Reworking, renaming, and reformating > > > > existing code is not a scope of this series and further cleanup will be > > > > taken place in follow-up patches. > > > > > > > > Here is the code size impact when applying this series. > > > > Measured by my AMD Zynq-7000 (ARM32) environment with SFDP and all > > > > manufcaturers are enabled. > > > > > > > > SPI-NOR: > > > > text data bss dec hex filename > > > > BEFORE 720685 14084 0 734769 b3631 u-boot > > > > AFTER 721827 14156 0 735983 b3aef u-boot > > > > DELTA +1142 +72 > > > > > > > > TINY: > > > > text data bss dec hex filename > > > > BEFORE 77399 3128 248 80775 13b87 spl/u-boot-spl > > > > AFTER 77589 3200 248 81037 13c8d spl/u-boot-spl > > > > DELTA +190 +72 > > > > > > So this leads to imx28_btt3 and imx28_xea overflowing in CI on link. > > > > I don't see any errors in my local. Something different from CI config. > > > > imx28_btt3_defconfig: > > text data bss dec hex filename > > BEFORE 37947 2896 0 40843 9f8b spl/u-boot-spl > > AFTER 38003 2912 0 40915 9fd3 spl/u-boot-spl > > +56 +16 > > > > imx28_xea_defconfig: > > text data bss dec hex filename > > BEFORE 38004 2816 0 40820 9f74 spl/u-boot-spl > > AFTER 38060 2832 0 40892 9fbc spl/u-boot-spl > > +56 +16 > > > > Could you share the exact CI error or size report? > > What toolchain are you using? CI uses the 14.2.0 ones from kernel.org: > https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/14.2.0/ > and the CI run is: > https://git.u-boot-project.org/u-boot/u-boot/-/jobs/115650#L3163 Thanks for the links. I was using arm-none-eabi 14.2.1. I need a little more time to reduce the size. Maybe we can optimize the flash_info structure by dropping unused parameters. Takahiro ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 0/4] mtd: spi-nor: split SFDP, ID database, and fixups 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay ` (5 preceding siblings ...) (?) @ 2026-10-22 8:44 ` Bastien Curutchet -1 siblings, 0 replies; 15+ messages in thread From: Bastien Curutchet @ 2026-10-22 8:44 UTC (permalink / raw) To: takahiro.kuwano, u-boot Cc: Tom Rini, Vignesh R, Raymond Mao, Vincent Jardin, Fabio Estevam, Eugen Hristev Hi, On 10/16/26 3:43 AM, Takahiro Kuwano via B4 Relay wrote: > The spi-nor-core.c contains optional logics like SFDP and manufcaturer > specific fixups. The spi-nor-ids.c has single large ID database. There > are many #ifdef directives in those files and that negatively affects > readability and maintainability. > > This series, as the first step of cleanup, move SFDP logic, IDs, and > fixups to newly source files. Reworking, renaming, and reformating > existing code is not a scope of this series and further cleanup will be > taken place in follow-up patches. > > Here is the code size impact when applying this series. > Measured by my AMD Zynq-7000 (ARM32) environment with SFDP and all > manufcaturers are enabled. > > SPI-NOR: > text data bss dec hex filename > BEFORE 720685 14084 0 734769 b3631 u-boot > AFTER 721827 14156 0 735983 b3aef u-boot > DELTA +1142 +72 > > TINY: > text data bss dec hex filename > BEFORE 77399 3128 248 80775 13b87 spl/u-boot-spl > AFTER 77589 3200 248 81037 13c8d spl/u-boot-spl > DELTA +190 +72 > I tested it on a PicoZed board with a Macronix flash (mx25uw51245g), it works like a charm. FYI, below the size differences with only Macronix enabled: SPI-NOR: text data bss dec hex filename BEFORE 931951 44980 0 976931 ee823 u-boot AFTER 932523 44988 0 977511 eea67 u-boot DELTA +572 +8 TINY: text data bss dec hex filename BEFORE 91612 3252 248 95112 17388 spl/u-boot-spl AFTER 91680 3264 248 95192 173d8 spl/u-boot-spl DELTA +68 +12 Tested-by: Bastien Curutchet <bastien.curutchet@bootlin.com> # mx25uw51245g Best regards, Bastien ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-10-22 8:44 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-16 1:43 [PATCH v3 0/4] mtd: spi-nor: split SFDP, ID database, and fixups Takahiro Kuwano 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay 2026-10-16 1:43 ` [PATCH v3 1/4] mtd: spi-nor: move SFDP logic out of the core Takahiro Kuwano 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay 2026-10-16 1:43 ` [PATCH v3 2/4] mtd: spi-nor: import manufacturer driver concept from Linux Takahiro Kuwano 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay 2026-10-16 1:43 ` [PATCH v3 3/4] mtd: spi-nor: move flash info entries to manufacturer drivers Takahiro Kuwano 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay 2026-10-16 1:43 ` [PATCH v3 4/4] mtd: spi-nor: move fixups " Takahiro Kuwano 2026-10-16 1:43 ` Takahiro Kuwano via B4 Relay 2026-10-16 18:26 ` [PATCH v3 0/4] mtd: spi-nor: split SFDP, ID database, and fixups Tom Rini 2026-10-21 1:42 ` Takahiro.Kuwano 2026-10-21 14:37 ` Tom Rini 2026-10-22 2:58 ` Takahiro.Kuwano 2026-10-22 8:44 ` Bastien Curutchet
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.