summaryrefslogtreecommitdiff
path: root/drivers/mtd/spi-nor
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-03-25 23:35:34 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2022-03-25 23:35:34 +0300
commite35a4a4e13c35f500a8d38e836b5e335c7515494 (patch)
tree32940f68475c16ddee8ed2933c9a4ae6e9b44265 /drivers/mtd/spi-nor
parent8eb48fc7c54ed627a693a205570f0eceea64274c (diff)
parent6cadd424abb63120f8346a4509dc43bddc9401d3 (diff)
downloadlinux-e35a4a4e13c35f500a8d38e836b5e335c7515494.tar.xz
Merge tag 'mtd/changes-for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull MTD updates from Miquel Raynal: "There has been a lot of activity in the MTD subsystem recently, with a number of SPI-NOR cleanups as well as the introduction of ECC engines that can be used by SPI controllers (hence a few SPI patches in here). Core MTD changes: - Replace the expert mode symbols with a single helper - Fix misuses of of_match_ptr() - Remove partid and partname debugfs files - tests: Fix eraseblock read speed miscalculation for lower partition sizes - TRX parser: Allow to use on MediaTek MIPS SoCs MTD driver changes: - spear_smi: use GFP_KERNEL - mchp48l640: Add SPI ID table - mchp23k256: Add SPI ID table - blkdevs: Avoid soft lockups with some mtd/spi devices - aspeed-smc: Improve probe resilience Hyperbus changes: - HBMC_AM654 should depend on ARCH_K3 NAND core changes: - ECC: - Add infrastructure to support hardware engines - Add a new helper to retrieve the ECC context - Provide a helper to retrieve a pilelined engine device NAND-ECC changes: - Macronix ECC engine: - Add Macronix external ECC engine support - Support SPI pipelined mode - Make two read-only arrays static const - Fix compile test issue Raw NAND core changes: - Fix misuses of of_match_node() - Rework of_get_nand_bus_width() - Remove of_get_nand_on_flash_bbt() wrapper - Protect access to rawnand devices while in suspend - bindings: Document the wp-gpios property Rax NAND controller driver changes: - atmel: Fix refcount issue in atmel_nand_controller_init - nandsim: - Add NS_PAGE_BYTE_SHIFT macro to replace the repeat pattern - Merge repeat codes in ns_switch_state - Replace overflow check with kzalloc to single kcalloc - rockchip: Fix platform_get_irq.cocci warning - stm32_fmc2: Add NAND Write Protect support - pl353: Set the nand chip node as the flash node - brcmnand: Fix sparse warnings in bcma_nand - omap_elm: Remove redundant variable 'errors' - gpmi: - Support fast edo timings for mx28 - Validate controller clock rate - Fix controller timings setting - brcmnand: - Add BCMA shim - BCMA controller uses command shift of 0 - Allow platform data instantation - Add platform data structure for BCMA - Allow working without interrupts - Move OF operations out of brcmnand_init_cs() - Avoid pdev in brcmnand_init_cs() - Allow SoC to provide I/O operations - Assign soc as early as possible Onenand changes: - Check for error irq SPI-NAND core changes: - Delay a little bit the dirmap creation - Create direct mapping descriptors for ECC operations SPI-NAND driver changes: - macronix: Use random program load SPI NOR core changes: - Move vendor specific code out of the core into vendor drivers. - Unify all function and object names in the vendor modules. - Make setup() callback optional to improve readability. - Skip erase logic when the SPI_NOR_NO_ERASE flag is set at flash declaration. SPI changes: - Macronix SPI controller: - Fix the transmit path - Create a helper to configure the controller before an operation - Create a helper to ease the start of an operation - Add support for direct mapping - Add support for pipelined ECC operations - spi-mem: - Introduce a capability structure - Check the controller extra capabilities - cadence-quadspi/mxic: Provide capability structures - Kill the spi_mem_dtr_supports_op() helper - Add an ecc parameter to the spi_mem_op structure Binding changes: - Dropped mtd/cortina,gemini-flash.txt - Convert BCM47xx partitions to json-schema - Vendor prefixes: Clarify Macronix prefix - SPI NAND: Convert spi-nand description file to yaml - Raw NAND chip: Create a NAND chip description - Raw NAND controller: - Harmonize the property types - Fix a comment in the examples - Fix the reg property description - Describe Macronix NAND ECC engine - Macronix SPI controller: - Document the nand-ecc-engine property - Convert to yaml - The interrupt property is not mandatory" * tag 'mtd/changes-for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (104 commits) mtd: nand: ecc: mxic: Fix compile test issue mtd: nand: mxic-ecc: make two read-only arrays static const mtd: hyperbus: HBMC_AM654 should depend on ARCH_K3 mtd: core: Remove partid and partname debugfs files dt-bindings: mtd: partitions: convert BCM47xx to the json-schema mtd: tests: Fix eraseblock read speed miscalculation for lower partition sizes mtd: rawnand: atmel: fix refcount issue in atmel_nand_controller_init mtd: rawnand: rockchip: fix platform_get_irq.cocci warning mtd: spi-nor: Skip erase logic when SPI_NOR_NO_ERASE is set mtd: spi-nor: renumber flags mtd: spi-nor: slightly change code style in spi_nor_sr_ready() mtd: spi-nor: spansion: rename vendor specific functions and defines mtd: spi-nor: spansion: convert USE_CLSR to a manufacturer flag mtd: spi-nor: move all spansion specifics into spansion.c mtd: spi-nor: spansion: slightly rework control flow in late_init() mtd: spi-nor: micron-st: rename vendor specific functions and defines mtd: spi-nor: micron-st: convert USE_FSR to a manufacturer flag mtd: spi-nor: move all micron-st specifics into micron-st.c mtd: spi-nor: xilinx: correct the debug message mtd: spi-nor: xilinx: rename vendor specific functions and defines ...
Diffstat (limited to 'drivers/mtd/spi-nor')
-rw-r--r--drivers/mtd/spi-nor/atmel.c81
-rw-r--r--drivers/mtd/spi-nor/catalyst.c6
-rw-r--r--drivers/mtd/spi-nor/controllers/aspeed-smc.c15
-rw-r--r--drivers/mtd/spi-nor/core.c268
-rw-r--r--drivers/mtd/spi-nor/core.h70
-rw-r--r--drivers/mtd/spi-nor/eon.c6
-rw-r--r--drivers/mtd/spi-nor/esmt.c6
-rw-r--r--drivers/mtd/spi-nor/everspin.c6
-rw-r--r--drivers/mtd/spi-nor/fujitsu.c6
-rw-r--r--drivers/mtd/spi-nor/gigadevice.c6
-rw-r--r--drivers/mtd/spi-nor/intel.c6
-rw-r--r--drivers/mtd/spi-nor/issi.c10
-rw-r--r--drivers/mtd/spi-nor/macronix.c14
-rw-r--r--drivers/mtd/spi-nor/micron-st.c259
-rw-r--r--drivers/mtd/spi-nor/spansion.c168
-rw-r--r--drivers/mtd/spi-nor/sst.c44
-rw-r--r--drivers/mtd/spi-nor/winbond.c29
-rw-r--r--drivers/mtd/spi-nor/xilinx.c97
-rw-r--r--drivers/mtd/spi-nor/xmc.c6
19 files changed, 594 insertions, 509 deletions
diff --git a/drivers/mtd/spi-nor/atmel.c b/drivers/mtd/spi-nor/atmel.c
index d6d889ce8876..656dd80a0be7 100644
--- a/drivers/mtd/spi-nor/atmel.c
+++ b/drivers/mtd/spi-nor/atmel.c
@@ -16,12 +16,12 @@
* is to unlock the whole flash array on startup. Therefore, we have to support
* exactly this operation.
*/
-static int atmel_at25fs_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int at25fs_nor_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
return -EOPNOTSUPP;
}
-static int atmel_at25fs_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int at25fs_nor_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
int ret;
@@ -37,28 +37,28 @@ static int atmel_at25fs_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
return ret;
}
-static int atmel_at25fs_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int at25fs_nor_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
return -EOPNOTSUPP;
}
-static const struct spi_nor_locking_ops atmel_at25fs_locking_ops = {
- .lock = atmel_at25fs_lock,
- .unlock = atmel_at25fs_unlock,
- .is_locked = atmel_at25fs_is_locked,
+static const struct spi_nor_locking_ops at25fs_nor_locking_ops = {
+ .lock = at25fs_nor_lock,
+ .unlock = at25fs_nor_unlock,
+ .is_locked = at25fs_nor_is_locked,
};
-static void atmel_at25fs_late_init(struct spi_nor *nor)
+static void at25fs_nor_late_init(struct spi_nor *nor)
{
- nor->params->locking_ops = &atmel_at25fs_locking_ops;
+ nor->params->locking_ops = &at25fs_nor_locking_ops;
}
-static const struct spi_nor_fixups atmel_at25fs_fixups = {
- .late_init = atmel_at25fs_late_init,
+static const struct spi_nor_fixups at25fs_nor_fixups = {
+ .late_init = at25fs_nor_late_init,
};
/**
- * atmel_set_global_protection - Do a Global Protect or Unprotect command
+ * atmel_nor_set_global_protection - Do a Global Protect or Unprotect command
* @nor: pointer to 'struct spi_nor'
* @ofs: offset in bytes
* @len: len in bytes
@@ -66,8 +66,8 @@ static const struct spi_nor_fixups atmel_at25fs_fixups = {
*
* Return: 0 on success, -error otherwise.
*/
-static int atmel_set_global_protection(struct spi_nor *nor, loff_t ofs,
- uint64_t len, bool is_protect)
+static int atmel_nor_set_global_protection(struct spi_nor *nor, loff_t ofs,
+ uint64_t len, bool is_protect)
{
int ret;
u8 sr;
@@ -116,17 +116,20 @@ static int atmel_set_global_protection(struct spi_nor *nor, loff_t ofs,
return spi_nor_write_sr(nor, nor->bouncebuf, 1);
}
-static int atmel_global_protect(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int atmel_nor_global_protect(struct spi_nor *nor, loff_t ofs,
+ uint64_t len)
{
- return atmel_set_global_protection(nor, ofs, len, true);
+ return atmel_nor_set_global_protection(nor, ofs, len, true);
}
-static int atmel_global_unprotect(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int atmel_nor_global_unprotect(struct spi_nor *nor, loff_t ofs,
+ uint64_t len)
{
- return atmel_set_global_protection(nor, ofs, len, false);
+ return atmel_nor_set_global_protection(nor, ofs, len, false);
}
-static int atmel_is_global_protected(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int atmel_nor_is_global_protected(struct spi_nor *nor, loff_t ofs,
+ uint64_t len)
{
int ret;
@@ -140,47 +143,47 @@ static int atmel_is_global_protected(struct spi_nor *nor, loff_t ofs, uint64_t l
return ((nor->bouncebuf[0] & ATMEL_SR_GLOBAL_PROTECT_MASK) == ATMEL_SR_GLOBAL_PROTECT_MASK);
}
-static const struct spi_nor_locking_ops atmel_global_protection_ops = {
- .lock = atmel_global_protect,
- .unlock = atmel_global_unprotect,
- .is_locked = atmel_is_global_protected,
+static const struct spi_nor_locking_ops atmel_nor_global_protection_ops = {
+ .lock = atmel_nor_global_protect,
+ .unlock = atmel_nor_global_unprotect,
+ .is_locked = atmel_nor_is_global_protected,
};
-static void atmel_global_protection_late_init(struct spi_nor *nor)
+static void atmel_nor_global_protection_late_init(struct spi_nor *nor)
{
- nor->params->locking_ops = &atmel_global_protection_ops;
+ nor->params->locking_ops = &atmel_nor_global_protection_ops;
}
-static const struct spi_nor_fixups atmel_global_protection_fixups = {
- .late_init = atmel_global_protection_late_init,
+static const struct spi_nor_fixups atmel_nor_global_protection_fixups = {
+ .late_init = atmel_nor_global_protection_late_init,
};
-static const struct flash_info atmel_parts[] = {
+static const struct flash_info atmel_nor_parts[] = {
/* Atmel -- some are (confusingly) marketed as "DataFlash" */
{ "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4)
FLAGS(SPI_NOR_HAS_LOCK)
NO_SFDP_FLAGS(SECT_4K)
- .fixups = &atmel_at25fs_fixups },
+ .fixups = &at25fs_nor_fixups },
{ "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8)
FLAGS(SPI_NOR_HAS_LOCK)
NO_SFDP_FLAGS(SECT_4K)
- .fixups = &atmel_at25fs_fixups },
+ .fixups = &at25fs_nor_fixups },
{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
NO_SFDP_FLAGS(SECT_4K)
- .fixups = &atmel_global_protection_fixups },
+ .fixups = &atmel_nor_global_protection_fixups },
{ "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
NO_SFDP_FLAGS(SECT_4K)
- .fixups = &atmel_global_protection_fixups },
+ .fixups = &atmel_nor_global_protection_fixups },
{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
NO_SFDP_FLAGS(SECT_4K)
- .fixups = &atmel_global_protection_fixups },
+ .fixups = &atmel_nor_global_protection_fixups },
{ "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
NO_SFDP_FLAGS(SECT_4K)
- .fixups = &atmel_global_protection_fixups },
+ .fixups = &atmel_nor_global_protection_fixups },
{ "at25sl321", INFO(0x1f4216, 0, 64 * 1024, 64)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8)
@@ -188,21 +191,21 @@ static const struct flash_info atmel_parts[] = {
{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
NO_SFDP_FLAGS(SECT_4K)
- .fixups = &atmel_global_protection_fixups },
+ .fixups = &atmel_nor_global_protection_fixups },
{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
NO_SFDP_FLAGS(SECT_4K)
- .fixups = &atmel_global_protection_fixups },
+ .fixups = &atmel_nor_global_protection_fixups },
{ "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
NO_SFDP_FLAGS(SECT_4K)
- .fixups = &atmel_global_protection_fixups },
+ .fixups = &atmel_nor_global_protection_fixups },
{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16)
NO_SFDP_FLAGS(SECT_4K) },
};
const struct spi_nor_manufacturer spi_nor_atmel = {
.name = "atmel",
- .parts = atmel_parts,
- .nparts = ARRAY_SIZE(atmel_parts),
+ .parts = atmel_nor_parts,
+ .nparts = ARRAY_SIZE(atmel_nor_parts),
};
diff --git a/drivers/mtd/spi-nor/catalyst.c b/drivers/mtd/spi-nor/catalyst.c
index ae4d67e01bb3..6d310815fb12 100644
--- a/drivers/mtd/spi-nor/catalyst.c
+++ b/drivers/mtd/spi-nor/catalyst.c
@@ -8,7 +8,7 @@
#include "core.h"
-static const struct flash_info catalyst_parts[] = {
+static const struct flash_info catalyst_nor_parts[] = {
/* Catalyst / On Semiconductor -- non-JEDEC */
{ "cat25c11", CAT25_INFO(16, 8, 16, 1) },
{ "cat25c03", CAT25_INFO(32, 8, 16, 2) },
@@ -19,6 +19,6 @@ static const struct flash_info catalyst_parts[] = {
const struct spi_nor_manufacturer spi_nor_catalyst = {
.name = "catalyst",
- .parts = catalyst_parts,
- .nparts = ARRAY_SIZE(catalyst_parts),
+ .parts = catalyst_nor_parts,
+ .nparts = ARRAY_SIZE(catalyst_nor_parts),
};
diff --git a/drivers/mtd/spi-nor/controllers/aspeed-smc.c b/drivers/mtd/spi-nor/controllers/aspeed-smc.c
index 7225870e8b18..acfe010f9dd7 100644
--- a/drivers/mtd/spi-nor/controllers/aspeed-smc.c
+++ b/drivers/mtd/spi-nor/controllers/aspeed-smc.c
@@ -769,6 +769,7 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
struct device_node *child;
unsigned int cs;
int ret = -ENODEV;
+ bool found_one = false;
for_each_available_child_of_node(np, child) {
struct aspeed_smc_chip *chip;
@@ -827,8 +828,17 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
* by of property.
*/
ret = spi_nor_scan(nor, NULL, &hwcaps);
- if (ret)
- break;
+ /*
+ * If we fail to scan the device it might not be present or
+ * broken. Don't fail the whole controller if others work.
+ */
+ if (ret) {
+ if (found_one)
+ ret = 0;
+
+ devm_kfree(controller->dev, chip);
+ continue;
+ }
ret = aspeed_smc_chip_setup_finish(chip);
if (ret)
@@ -839,6 +849,7 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
break;
controller->chips[cs] = chip;
+ found_one = true;
}
if (ret) {
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 04ea180118e3..b4f141ad9c9c 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -157,8 +157,8 @@ static int spi_nor_spimem_exec_op(struct spi_nor *nor, struct spi_mem_op *op)
return spi_mem_exec_op(nor->spimem, op);
}
-static int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode,
- u8 *buf, size_t len)
+int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode,
+ u8 *buf, size_t len)
{
if (spi_nor_protocol_is_dtr(nor->reg_proto))
return -EOPNOTSUPP;
@@ -166,8 +166,8 @@ static int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode,
return nor->controller_ops->read_reg(nor, opcode, buf, len);
}
-static int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode,
- const u8 *buf, size_t len)
+int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode,
+ const u8 *buf, size_t len)
{
if (spi_nor_protocol_is_dtr(nor->reg_proto))
return -EOPNOTSUPP;
@@ -413,50 +413,6 @@ int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
}
/**
- * spi_nor_read_fsr() - Read the Flag Status Register.
- * @nor: pointer to 'struct spi_nor'
- * @fsr: pointer to a DMA-able buffer where the value of the
- * Flag Status Register will be written. Should be at least 2
- * bytes.
- *
- * Return: 0 on success, -errno otherwise.
- */
-static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
-{
- int ret;
-
- if (nor->spimem) {
- struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0),
- SPI_MEM_OP_NO_ADDR,
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(1, fsr, 0));
-
- if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
- op.addr.nbytes = nor->params->rdsr_addr_nbytes;
- op.dummy.nbytes = nor->params->rdsr_dummy;
- /*
- * We don't want to read only one byte in DTR mode. So,
- * read 2 and then discard the second byte.
- */
- op.data.nbytes = 2;
- }
-
- spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
-
- ret = spi_mem_exec_op(nor->spimem, &op);
- } else {
- ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr,
- 1);
- }
-
- if (ret)
- dev_dbg(nor->dev, "error %d reading FSR\n", ret);
-
- return ret;
-}
-
-/**
* spi_nor_read_cr() - Read the Configuration Register using the
* SPINOR_OP_RDCR (35h) command.
* @nor: pointer to 'struct spi_nor'
@@ -599,189 +555,21 @@ int spi_nor_write_ear(struct spi_nor *nor, u8 ear)
}
/**
- * spi_nor_xread_sr() - Read the Status Register on S3AN flashes.
- * @nor: pointer to 'struct spi_nor'.
- * @sr: pointer to a DMA-able buffer where the value of the
- * Status Register will be written.
- *
- * Return: 0 on success, -errno otherwise.
- */
-int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr)
-{
- int ret;
-
- if (nor->spimem) {
- struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_XRDSR, 0),
- SPI_MEM_OP_NO_ADDR,
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(1, sr, 0));
-
- spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
-
- ret = spi_mem_exec_op(nor->spimem, &op);
- } else {
- ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_XRDSR, sr,
- 1);
- }
-
- if (ret)
- dev_dbg(nor->dev, "error %d reading XRDSR\n", ret);
-
- return ret;
-}
-
-/**
- * spi_nor_xsr_ready() - Query the Status Register of the S3AN flash to see if
- * the flash is ready for new commands.
- * @nor: pointer to 'struct spi_nor'.
- *
- * Return: 1 if ready, 0 if not ready, -errno on errors.
- */
-static int spi_nor_xsr_ready(struct spi_nor *nor)
-{
- int ret;
-
- ret = spi_nor_xread_sr(nor, nor->bouncebuf);
- if (ret)
- return ret;
-
- return !!(nor->bouncebuf[0] & XSR_RDY);
-}
-
-/**
- * spi_nor_clear_sr() - Clear the Status Register.
- * @nor: pointer to 'struct spi_nor'.
- */
-static void spi_nor_clear_sr(struct spi_nor *nor)
-{
- int ret;
-
- if (nor->spimem) {
- struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0),
- SPI_MEM_OP_NO_ADDR,
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_NO_DATA);
-
- spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
-
- ret = spi_mem_exec_op(nor->spimem, &op);
- } else {
- ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR,
- NULL, 0);
- }
-
- if (ret)
- dev_dbg(nor->dev, "error %d clearing SR\n", ret);
-}
-
-/**
* spi_nor_sr_ready() - Query the Status Register to see if the flash is ready
* for new commands.
* @nor: pointer to 'struct spi_nor'.
*
* Return: 1 if ready, 0 if not ready, -errno on errors.
*/
-static int spi_nor_sr_ready(struct spi_nor *nor)
-{
- int ret = spi_nor_read_sr(nor, nor->bouncebuf);
-
- if (ret)
- return ret;
-
- if (nor->flags & SNOR_F_USE_CLSR &&
- nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) {
- if (nor->bouncebuf[0] & SR_E_ERR)
- dev_err(nor->dev, "Erase Error occurred\n");
- else
- dev_err(nor->dev, "Programming Error occurred\n");
-
- spi_nor_clear_sr(nor);
-
- /*
- * WEL bit remains set to one when an erase or page program
- * error occurs. Issue a Write Disable command to protect
- * against inadvertent writes that can possibly corrupt the
- * contents of the memory.
- */
- ret = spi_nor_write_disable(nor);
- if (ret)
- return ret;
-
- return -EIO;
- }
-
- return !(nor->bouncebuf[0] & SR_WIP);
-}
-
-/**
- * spi_nor_clear_fsr() - Clear the Flag Status Register.
- * @nor: pointer to 'struct spi_nor'.
- */
-static void spi_nor_clear_fsr(struct spi_nor *nor)
+int spi_nor_sr_ready(struct spi_nor *nor)
{
int ret;
- if (nor->spimem) {
- struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 0),
- SPI_MEM_OP_NO_ADDR,
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_NO_DATA);
-
- spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
-
- ret = spi_mem_exec_op(nor->spimem, &op);
- } else {
- ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR,
- NULL, 0);
- }
-
- if (ret)
- dev_dbg(nor->dev, "error %d clearing FSR\n", ret);
-}
-
-/**
- * spi_nor_fsr_ready() - Query the Flag Status Register to see if the flash is
- * ready for new commands.
- * @nor: pointer to 'struct spi_nor'.
- *
- * Return: 1 if ready, 0 if not ready, -errno on errors.
- */
-static int spi_nor_fsr_ready(struct spi_nor *nor)
-{
- int ret = spi_nor_read_fsr(nor, nor->bouncebuf);
-
+ ret = spi_nor_read_sr(nor, nor->bouncebuf);
if (ret)
return ret;
- if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) {
- if (nor->bouncebuf[0] & FSR_E_ERR)
- dev_err(nor->dev, "Erase operation failed.\n");
- else
- dev_err(nor->dev, "Program operation failed.\n");
-
- if (nor->bouncebuf[0] & FSR_PT_ERR)
- dev_err(nor->dev,
- "Attempted to modify a protected sector.\n");
-
- spi_nor_clear_fsr(nor);
-
- /*
- * WEL bit remains set to one when an erase or page program
- * error occurs. Issue a Write Disable command to protect
- * against inadvertent writes that can possibly corrupt the
- * contents of the memory.
- */
- ret = spi_nor_write_disable(nor);
- if (ret)
- return ret;
-
- return -EIO;
- }
-
- return !!(nor->bouncebuf[0] & FSR_READY);
+ return !(nor->bouncebuf[0] & SR_WIP);
}
/**
@@ -792,18 +580,11 @@ static int spi_nor_fsr_ready(struct spi_nor *nor)
*/
static int spi_nor_ready(struct spi_nor *nor)
{
- int sr, fsr;
+ /* Flashes might override the standard routine. */
+ if (nor->params->ready)
+ return nor->params->ready(nor);
- if (nor->flags & SNOR_F_READY_XSR_RDY)
- sr = spi_nor_xsr_ready(nor);
- else
- sr = spi_nor_sr_ready(nor);
- if (sr < 0)
- return sr;
- fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1;
- if (fsr < 0)
- return fsr;
- return sr && fsr;
+ return spi_nor_sr_ready(nor);
}
/**
@@ -2532,11 +2313,12 @@ static int spi_nor_setup(struct spi_nor *nor,
{
int ret;
- if (nor->params->setup) {
+ if (nor->params->setup)
ret = nor->params->setup(nor, hwcaps);
- if (ret)
- return ret;
- }
+ else
+ ret = spi_nor_default_setup(nor, hwcaps);
+ if (ret)
+ return ret;
return spi_nor_set_addr_width(nor);
}
@@ -2666,20 +2448,6 @@ static void spi_nor_init_flags(struct spi_nor *nor)
if (flags & NO_CHIP_ERASE)
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
-
- if (flags & USE_CLSR)
- nor->flags |= SNOR_F_USE_CLSR;
-
- if (flags & USE_FSR)
- nor->flags |= SNOR_F_USE_FSR;
-
- /*
- * Make sure the XSR_RDY flag is set before calling
- * spi_nor_wait_till_ready(). Xilinx S3AN share MFR
- * with Atmel SPI NOR.
- */
- if (flags & SPI_NOR_XSR_RDY)
- nor->flags |= SNOR_F_READY_XSR_RDY;
}
/**
@@ -2786,7 +2554,6 @@ static void spi_nor_init_default_params(struct spi_nor *nor)
params->quad_enable = spi_nor_sr2_bit1_quad_enable;
params->set_4byte_addr_mode = spansion_set_4byte_addr_mode;
- params->setup = spi_nor_default_setup;
params->otp.org = &info->otp_org;
/* Default to 16-bit Write Status (01h) Command */
@@ -3181,10 +2948,11 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor)
mtd->flags = MTD_CAP_NORFLASH;
if (nor->info->flags & SPI_NOR_NO_ERASE)
mtd->flags |= MTD_NO_ERASE;
+ else
+ mtd->_erase = spi_nor_erase;
mtd->writesize = nor->params->writesize;
mtd->writebufsize = nor->params->page_size;
mtd->size = nor->params->size;
- mtd->_erase = spi_nor_erase;
mtd->_read = spi_nor_read;
/* Might be already set by some SST flashes. */
if (!mtd->_write)
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 2afb610853a9..b7fd760e3b47 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -12,23 +12,20 @@
#define SPI_NOR_MAX_ID_LEN 6
enum spi_nor_option_flags {
- SNOR_F_USE_FSR = BIT(0),
- SNOR_F_HAS_SR_TB = BIT(1),
- SNOR_F_NO_OP_CHIP_ERASE = BIT(2),
- SNOR_F_READY_XSR_RDY = BIT(3),
- SNOR_F_USE_CLSR = BIT(4),
- SNOR_F_BROKEN_RESET = BIT(5),
- SNOR_F_4B_OPCODES = BIT(6),
- SNOR_F_HAS_4BAIT = BIT(7),
- SNOR_F_HAS_LOCK = BIT(8),
- SNOR_F_HAS_16BIT_SR = BIT(9),
- SNOR_F_NO_READ_CR = BIT(10),
- SNOR_F_HAS_SR_TB_BIT6 = BIT(11),
- SNOR_F_HAS_4BIT_BP = BIT(12),
- SNOR_F_HAS_SR_BP3_BIT6 = BIT(13),
- SNOR_F_IO_MODE_EN_VOLATILE = BIT(14),
- SNOR_F_SOFT_RESET = BIT(15),
- SNOR_F_SWP_IS_VOLATILE = BIT(16),
+ SNOR_F_HAS_SR_TB = BIT(0),
+ SNOR_F_NO_OP_CHIP_ERASE = BIT(1),
+ SNOR_F_BROKEN_RESET = BIT(2),
+ SNOR_F_4B_OPCODES = BIT(3),
+ SNOR_F_HAS_4BAIT = BIT(4),
+ SNOR_F_HAS_LOCK = BIT(5),
+ SNOR_F_HAS_16BIT_SR = BIT(6),
+ SNOR_F_NO_READ_CR = BIT(7),
+ SNOR_F_HAS_SR_TB_BIT6 = BIT(8),
+ SNOR_F_HAS_4BIT_BP = BIT(9),
+ SNOR_F_HAS_SR_BP3_BIT6 = BIT(10),
+ SNOR_F_IO_MODE_EN_VOLATILE = BIT(11),
+ SNOR_F_SOFT_RESET = BIT(12),
+ SNOR_F_SWP_IS_VOLATILE = BIT(13),
};
struct spi_nor_read_command {
@@ -257,10 +254,13 @@ struct spi_nor_otp {
* @convert_addr: converts an absolute address into something the flash
* will understand. Particularly useful when pagesize is
* not a power-of-2.
- * @setup: configures the SPI NOR memory. Useful for SPI NOR
- * flashes that have peculiarities to the SPI NOR standard
- * e.g. different opcodes, specific address calculation,
- * page size, etc.
+ * @setup: (optional) configures the SPI NOR memory. Useful for
+ * SPI NOR flashes that have peculiarities to the SPI NOR
+ * standard e.g. different opcodes, specific address
+ * calculation, page size, etc.
+ * @ready: (optional) flashes might use a different mechanism
+ * than reading the status register to indicate they
+ * are ready for a new command
* @locking_ops: SPI NOR locking methods.
*/
struct spi_nor_flash_parameter {
@@ -282,6 +282,7 @@ struct spi_nor_flash_parameter {
int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable);
u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps);
+ int (*ready)(struct spi_nor *nor);
const struct spi_nor_locking_ops *locking_ops;
};
@@ -345,10 +346,6 @@ struct spi_nor_fixups {
* SPI_NOR_NO_ERASE: no erase command needed.
* NO_CHIP_ERASE: chip does not support chip erase.
* SPI_NOR_NO_FR: can't do fastread.
- * USE_CLSR: use CLSR command.
- * USE_FSR: use flag status register
- * SPI_NOR_XSR_RDY: S3AN flashes have specific opcode to read the
- * status register.
*
* @no_sfdp_flags: flags that indicate support that can be discovered via SFDP.
* Used when SFDP tables are not defined in the flash. These
@@ -399,9 +396,6 @@ struct flash_info {
#define SPI_NOR_NO_ERASE BIT(6)
#define NO_CHIP_ERASE BIT(7)
#define SPI_NOR_NO_FR BIT(8)
-#define USE_CLSR BIT(9)
-#define USE_FSR BIT(10)
-#define SPI_NOR_XSR_RDY BIT(11)
u8 no_sfdp_flags;
#define SPI_NOR_SKIP_SFDP BIT(0)
@@ -458,19 +452,6 @@ struct flash_info {
.addr_width = (_addr_width), \
.flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR, \
-#define S3AN_INFO(_jedec_id, _n_sectors, _page_size) \
- .id = { \
- ((_jedec_id) >> 16) & 0xff, \
- ((_jedec_id) >> 8) & 0xff, \
- (_jedec_id) & 0xff \
- }, \
- .id_len = 3, \
- .sector_size = (8*_page_size), \
- .n_sectors = (_n_sectors), \
- .page_size = _page_size, \
- .addr_width = 3, \
- .flags = SPI_NOR_NO_FR | SPI_NOR_XSR_RDY,
-
#define OTP_INFO(_len, _n_regions, _base, _offset) \
.otp_org = { \
.len = (_len), \
@@ -554,12 +535,12 @@ int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor);
int spi_nor_read_sr(struct spi_nor *nor, u8 *sr);
+int spi_nor_sr_ready(struct spi_nor *nor);
int spi_nor_read_cr(struct spi_nor *nor, u8 *cr);
int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len);
int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr);
-int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr);
ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
u8 *buf);
ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
@@ -599,6 +580,11 @@ void spi_nor_try_unlock_all(struct spi_nor *nor);
void spi_nor_set_mtd_locking_ops(struct spi_nor *nor);
void spi_nor_set_mtd_otp_ops(struct spi_nor *nor);
+int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode,
+ u8 *buf, size_t len);
+int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode,
+ const u8 *buf, size_t len);
+
static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
{
return container_of(mtd, struct spi_nor, mtd);
diff --git a/drivers/mtd/spi-nor/eon.c b/drivers/mtd/spi-nor/eon.c
index 4f3ee6331f37..8c1c57530281 100644
--- a/drivers/mtd/spi-nor/eon.c
+++ b/drivers/mtd/spi-nor/eon.c
@@ -8,7 +8,7 @@
#include "core.h"
-static const struct flash_info eon_parts[] = {
+static const struct flash_info eon_nor_parts[] = {
/* EON -- en25xxx */
{ "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64)
NO_SFDP_FLAGS(SECT_4K) },
@@ -32,6 +32,6 @@ static const struct flash_info eon_parts[] = {
const struct spi_nor_manufacturer spi_nor_eon = {
.name = "eon",
- .parts = eon_parts,
- .nparts = ARRAY_SIZE(eon_parts),
+ .parts = eon_nor_parts,
+ .nparts = ARRAY_SIZE(eon_nor_parts),
};
diff --git a/drivers/mtd/spi-nor/esmt.c b/drivers/mtd/spi-nor/esmt.c
index ace1da221566..79e2408f4998 100644
--- a/drivers/mtd/spi-nor/esmt.c
+++ b/drivers/mtd/spi-nor/esmt.c
@@ -8,7 +8,7 @@
#include "core.h"
-static const struct flash_info esmt_parts[] = {
+static const struct flash_info esmt_nor_parts[] = {
/* ESMT */
{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
@@ -23,6 +23,6 @@ static const struct flash_info esmt_parts[] = {
const struct spi_nor_manufacturer spi_nor_esmt = {
.name = "esmt",
- .parts = esmt_parts,
- .nparts = ARRAY_SIZE(esmt_parts),
+ .parts = esmt_nor_parts,
+ .nparts = ARRAY_SIZE(esmt_nor_parts),
};
diff --git a/drivers/mtd/spi-nor/everspin.c b/drivers/mtd/spi-nor/everspin.c
index f6c6fb36a428..84a07c2e0536 100644
--- a/drivers/mtd/spi-nor/everspin.c
+++ b/drivers/mtd/spi-nor/everspin.c
@@ -8,7 +8,7 @@
#include "core.h"
-static const struct flash_info everspin_parts[] = {
+static const struct flash_info everspin_nor_parts[] = {
/* Everspin */
{ "mr25h128", CAT25_INFO(16 * 1024, 1, 256, 2) },
{ "mr25h256", CAT25_INFO(32 * 1024, 1, 256, 2) },
@@ -18,6 +18,6 @@ static const struct flash_info everspin_parts[] = {
const struct spi_nor_manufacturer spi_nor_everspin = {
.name = "everspin",
- .parts = everspin_parts,
- .nparts = ARRAY_SIZE(everspin_parts),
+ .parts = everspin_nor_parts,
+ .nparts = ARRAY_SIZE(everspin_nor_parts),
};
diff --git a/drivers/mtd/spi-nor/fujitsu.c b/drivers/mtd/spi-nor/fujitsu.c
index 5fa8f04f2e35..69cffc5c73ef 100644
--- a/drivers/mtd/spi-nor/fujitsu.c
+++ b/drivers/mtd/spi-nor/fujitsu.c
@@ -8,7 +8,7 @@
#include "core.h"
-static const struct flash_info fujitsu_parts[] = {
+static const struct flash_info fujitsu_nor_parts[] = {
/* Fujitsu */
{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1)
FLAGS(SPI_NOR_NO_ERASE) },
@@ -16,6 +16,6 @@ static const struct flash_info fujitsu_parts[] = {
const struct spi_nor_manufacturer spi_nor_fujitsu = {
.name = "fujitsu",
- .parts = fujitsu_parts,
- .nparts = ARRAY_SIZE(fujitsu_parts),
+ .parts = fujitsu_nor_parts,
+ .nparts = ARRAY_SIZE(fujitsu_nor_parts),
};
diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c
index 0807d0263808..119b38e6fc2a 100644
--- a/drivers/mtd/spi-nor/gigadevice.c
+++ b/drivers/mtd/spi-nor/gigadevice.c
@@ -23,7 +23,7 @@ static const struct spi_nor_fixups gd25q256_fixups = {
.default_init = gd25q256_default_init,
};
-static const struct flash_info gigadevice_parts[] = {
+static const struct flash_info gigadevice_nor_parts[] = {
{ "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
@@ -61,6 +61,6 @@ static const struct flash_info gigadevice_parts[] = {
const struct spi_nor_manufacturer spi_nor_gigadevice = {
.name = "gigadevice",
- .parts = gigadevice_parts,
- .nparts = ARRAY_SIZE(gigadevice_parts),
+ .parts = gigadevice_nor_parts,
+ .nparts = ARRAY_SIZE(gigadevice_nor_parts),
};
diff --git a/drivers/mtd/spi-nor/intel.c b/drivers/mtd/spi-nor/intel.c
index d64e114e9fb4..9179f2d09cba 100644
--- a/drivers/mtd/spi-nor/intel.c
+++ b/drivers/mtd/spi-nor/intel.c
@@ -8,7 +8,7 @@
#include "core.h"
-static const struct flash_info intel_parts[] = {
+static const struct flash_info intel_nor_parts[] = {
/* Intel/Numonyx -- xxxs33b */
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
@@ -20,6 +20,6 @@ static const struct flash_info intel_parts[] = {
const struct spi_nor_manufacturer spi_nor_intel = {
.name = "intel",
- .parts = intel_parts,
- .nparts = ARRAY_SIZE(intel_parts),
+ .parts = intel_nor_parts,
+ .nparts = ARRAY_SIZE(intel_nor_parts),
};
diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c
index 23629b919ade..c012bc2486e1 100644
--- a/drivers/mtd/spi-nor/issi.c
+++ b/drivers/mtd/spi-nor/issi.c
@@ -29,7 +29,7 @@ static const struct spi_nor_fixups is25lp256_fixups = {
.post_bfpt = is25lp256_post_bfpt_fixups,
};
-static const struct flash_info issi_parts[] = {
+static const struct flash_info issi_nor_parts[] = {
/* ISSI */
{ "is25cd512", INFO(0x7f9d20, 0, 32 * 1024, 2)
NO_SFDP_FLAGS(SECT_4K) },
@@ -69,18 +69,18 @@ static const struct flash_info issi_parts[] = {
NO_SFDP_FLAGS(SECT_4K) },
};
-static void issi_default_init(struct spi_nor *nor)
+static void issi_nor_default_init(struct spi_nor *nor)
{
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
}
static const struct spi_nor_fixups issi_fixups = {
- .default_init = issi_default_init,
+ .default_init = issi_nor_default_init,
};
const struct spi_nor_manufacturer spi_nor_issi = {
.name = "issi",
- .parts = issi_parts,
- .nparts = ARRAY_SIZE(issi_parts),
+ .parts = issi_nor_parts,
+ .nparts = ARRAY_SIZE(issi_nor_parts),
.fixups = &issi_fixups,
};
diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c
index 97dba1ae7fb1..d81a4cb2812b 100644
--- a/drivers/mtd/spi-nor/macronix.c
+++ b/drivers/mtd/spi-nor/macronix.c
@@ -32,7 +32,7 @@ static const struct spi_nor_fixups mx25l25635_fixups = {
.post_bfpt = mx25l25635_post_bfpt_fixups,
};
-static const struct flash_info macronix_parts[] = {
+static const struct flash_info macronix_nor_parts[] = {
/* Macronix */
{ "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1)
NO_SFDP_FLAGS(SECT_4K) },
@@ -102,19 +102,19 @@ static const struct flash_info macronix_parts[] = {
FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
};
-static void macronix_default_init(struct spi_nor *nor)
+static void macronix_nor_default_init(struct spi_nor *nor)
{
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode;
}
-static const struct spi_nor_fixups macronix_fixups = {
- .default_init = macronix_default_init,
+static const struct spi_nor_fixups macronix_nor_fixups = {
+ .default_init = macronix_nor_default_init,
};
const struct spi_nor_manufacturer spi_nor_macronix = {
.name = "macronix",
- .parts = macronix_parts,
- .nparts = ARRAY_SIZE(macronix_parts),
- .fixups = &macronix_fixups,
+ .parts = macronix_nor_parts,
+ .nparts = ARRAY_SIZE(macronix_nor_parts),
+ .fixups = &macronix_nor_fixups,
};
diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c
index bb95b1aabf74..8a20475ce77a 100644
--- a/drivers/mtd/spi-nor/micron-st.c
+++ b/drivers/mtd/spi-nor/micron-st.c
@@ -8,6 +8,11 @@
#include "core.h"
+/* flash_info mfr_flag. Used to read proprietary FSR register. */
+#define USE_FSR BIT(0)
+
+#define SPINOR_OP_RDFSR 0x70 /* Read flag status register */
+#define SPINOR_OP_CLFSR 0x50 /* Clear flag status register */
#define SPINOR_OP_MT_DTR_RD 0xfd /* Fast Read opcode in DTR mode */
#define SPINOR_OP_MT_RD_ANY_REG 0x85 /* Read volatile register */
#define SPINOR_OP_MT_WR_ANY_REG 0x81 /* Write volatile register */
@@ -17,7 +22,13 @@
#define SPINOR_MT_OCT_DTR 0xe7 /* Enable Octal DTR. */
#define SPINOR_MT_EXSPI 0xff /* Enable Extended SPI (default) */
-static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor, bool enable)
+/* Flag Status Register bits */
+#define FSR_READY BIT(7) /* Device status, 0 = Busy, 1 = Ready */
+#define FSR_E_ERR BIT(5) /* Erase operation status */
+#define FSR_P_ERR BIT(4) /* Program operation status */
+#define FSR_PT_ERR BIT(1) /* Protection error bit */
+
+static int micron_st_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
{
struct spi_mem_op op;
u8 *buf = nor->bouncebuf;
@@ -102,7 +113,7 @@ static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor, bool enable)
static void mt35xu512aba_default_init(struct spi_nor *nor)
{
- nor->params->octal_dtr_enable = spi_nor_micron_octal_dtr_enable;
+ nor->params->octal_dtr_enable = micron_st_nor_octal_dtr_enable;
}
static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
@@ -130,20 +141,22 @@ static const struct spi_nor_fixups mt35xu512aba_fixups = {
.post_sfdp = mt35xu512aba_post_sfdp_fixup,
};
-static const struct flash_info micron_parts[] = {
+static const struct flash_info micron_nor_parts[] = {
{ "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512)
- FLAGS(USE_FSR)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_OCTAL_READ |
SPI_NOR_OCTAL_DTR_READ | SPI_NOR_OCTAL_DTR_PP)
FIXUP_FLAGS(SPI_NOR_4B_OPCODES | SPI_NOR_IO_MODE_EN_VOLATILE)
- .fixups = &mt35xu512aba_fixups},
+ MFR_FLAGS(USE_FSR)
+ .fixups = &mt35xu512aba_fixups
+ },
{ "mt35xu02g", INFO(0x2c5b1c, 0, 128 * 1024, 2048)
- FLAGS(USE_FSR)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_OCTAL_READ)
- FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
+ FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
+ MFR_FLAGS(USE_FSR)
+ },
};
-static const struct flash_info st_parts[] = {
+static const struct flash_info st_nor_parts[] = {
{ "n25q016a", INFO(0x20bb15, 0, 64 * 1024, 32)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64)
@@ -156,57 +169,79 @@ static const struct flash_info st_parts[] = {
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
- SPI_NOR_BP3_SR_BIT6 | USE_FSR)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
+ SPI_NOR_BP3_SR_BIT6)
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_FSR)
+ },
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
- SPI_NOR_BP3_SR_BIT6 | USE_FSR)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
+ SPI_NOR_BP3_SR_BIT6)
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_FSR)
+ },
{ "mt25ql256a", INFO6(0x20ba19, 0x104400, 64 * 1024, 512)
- FLAGS(USE_FSR)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
+ FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
+ MFR_FLAGS(USE_FSR)
+ },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512)
- FLAGS(USE_FSR)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
+ SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_FSR)
+ },
{ "mt25qu256a", INFO6(0x20bb19, 0x104400, 64 * 1024, 512)
- FLAGS(USE_FSR)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
+ FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
+ MFR_FLAGS(USE_FSR)
+ },
{ "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512)
- FLAGS(USE_FSR)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_FSR)
+ },
{ "mt25ql512a", INFO6(0x20ba20, 0x104400, 64 * 1024, 1024)
- FLAGS(USE_FSR)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
+ FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
+ MFR_FLAGS(USE_FSR)
+ },
{ "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
- SPI_NOR_BP3_SR_BIT6 | USE_FSR)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
+ SPI_NOR_BP3_SR_BIT6)
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_FSR)
+ },
{ "mt25qu512a", INFO6(0x20bb20, 0x104400, 64 * 1024, 1024)
- FLAGS(USE_FSR)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
+ FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
+ MFR_FLAGS(USE_FSR)
+ },
{ "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
- SPI_NOR_BP3_SR_BIT6 | USE_FSR)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
+ SPI_NOR_BP3_SR_BIT6)
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_FSR)
+ },
{ "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
- SPI_NOR_BP3_SR_BIT6 | NO_CHIP_ERASE | USE_FSR)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
+ SPI_NOR_BP3_SR_BIT6 | NO_CHIP_ERASE)
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_FSR)
+ },
{ "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048)
- FLAGS(NO_CHIP_ERASE | USE_FSR)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
+ FLAGS(NO_CHIP_ERASE)
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_FSR)
+ },
{ "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096)
- FLAGS(NO_CHIP_ERASE | USE_FSR)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
+ FLAGS(NO_CHIP_ERASE)
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_FSR)
+ },
{ "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096)
- FLAGS(NO_CHIP_ERASE | USE_FSR)
+ FLAGS(NO_CHIP_ERASE)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
+ SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_FSR)
+ },
{ "m25p05", INFO(0x202010, 0, 32 * 1024, 2) },
{ "m25p10", INFO(0x202011, 0, 32 * 1024, 4) },
@@ -250,15 +285,15 @@ static const struct flash_info st_parts[] = {
};
/**
- * st_micron_set_4byte_addr_mode() - Set 4-byte address mode for ST and Micron
- * flashes.
+ * micron_st_nor_set_4byte_addr_mode() - Set 4-byte address mode for ST and
+ * Micron flashes.
* @nor: pointer to 'struct spi_nor'.
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte
* address mode.
*
* Return: 0 on success, -errno otherwise.
*/
-static int st_micron_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
+static int micron_st_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
{
int ret;
@@ -273,28 +308,154 @@ static int st_micron_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
return spi_nor_write_disable(nor);
}
-static void micron_st_default_init(struct spi_nor *nor)
+/**
+ * micron_st_nor_read_fsr() - Read the Flag Status Register.
+ * @nor: pointer to 'struct spi_nor'
+ * @fsr: pointer to a DMA-able buffer where the value of the
+ * Flag Status Register will be written. Should be at least 2
+ * bytes.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int micron_st_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
+{
+ int ret;
+
+ if (nor->spimem) {
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_IN(1, fsr, 0));
+
+ if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
+ op.addr.nbytes = nor->params->rdsr_addr_nbytes;
+ op.dummy.nbytes = nor->params->rdsr_dummy;
+ /*
+ * We don't want to read only one byte in DTR mode. So,
+ * read 2 and then discard the second byte.
+ */
+ op.data.nbytes = 2;
+ }
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ } else {
+ ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr,
+ 1);
+ }
+
+ if (ret)
+ dev_dbg(nor->dev, "error %d reading FSR\n", ret);
+
+ return ret;
+}
+
+/**
+ * micron_st_nor_clear_fsr() - Clear the Flag Status Register.
+ * @nor: pointer to 'struct spi_nor'.
+ */
+static void micron_st_nor_clear_fsr(struct spi_nor *nor)
+{
+ int ret;
+
+ if (nor->spimem) {
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 0),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_NO_DATA);
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ } else {
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR,
+ NULL, 0);
+ }
+
+ if (ret)
+ dev_dbg(nor->dev, "error %d clearing FSR\n", ret);
+}
+
+/**
+ * micron_st_nor_ready() - Query the Status Register as well as the Flag Status
+ * Register to see if the flash is ready for new commands. If there are any
+ * errors in the FSR clear them.
+ * @nor: pointer to 'struct spi_nor'.
+ *
+ * Return: 1 if ready, 0 if not ready, -errno on errors.
+ */
+static int micron_st_nor_ready(struct spi_nor *nor)
+{
+ int sr_ready, ret;
+
+ sr_ready = spi_nor_sr_ready(nor);
+ if (sr_ready < 0)
+ return sr_ready;
+
+ ret = micron_st_nor_read_fsr(nor, nor->bouncebuf);
+ if (ret)
+ return ret;
+
+ if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) {
+ if (nor->bouncebuf[0] & FSR_E_ERR)
+ dev_err(nor->dev, "Erase operation failed.\n");
+ else
+ dev_err(nor->dev, "Program operation failed.\n");
+
+ if (nor->bouncebuf[0] & FSR_PT_ERR)
+ dev_err(nor->dev,
+ "Attempted to modify a protected sector.\n");
+
+ micron_st_nor_clear_fsr(nor);
+
+ /*
+ * WEL bit remains set to one when an erase or page program
+ * error occurs. Issue a Write Disable command to protect
+ * against inadvertent writes that can possibly corrupt the
+ * contents of the memory.
+ */
+ ret = spi_nor_write_disable(nor);
+ if (ret)
+ return ret;
+
+ return -EIO;
+ }
+
+ return sr_ready && !!(nor->bouncebuf[0] & FSR_READY);
+}
+
+static void micron_st_nor_default_init(struct spi_nor *nor)
{
nor->flags |= SNOR_F_HAS_LOCK;
nor->flags &= ~SNOR_F_HAS_16BIT_SR;
nor->params->quad_enable = NULL;
- nor->params->set_4byte_addr_mode = st_micron_set_4byte_addr_mode;
+ nor->params->set_4byte_addr_mode = micron_st_nor_set_4byte_addr_mode;
+}
+
+static void micron_st_nor_late_init(struct spi_nor *nor)
+{
+ if (nor->info->mfr_flags & USE_FSR)
+ nor->params->ready = micron_st_nor_ready;
}
-static const struct spi_nor_fixups micron_st_fixups = {
- .default_init = micron_st_default_init,
+static const struct spi_nor_fixups micron_st_nor_fixups = {
+ .default_init = micron_st_nor_default_init,
+ .late_init = micron_st_nor_late_init,
};
const struct spi_nor_manufacturer spi_nor_micron = {
.name = "micron",
- .parts = micron_parts,
- .nparts = ARRAY_SIZE(micron_parts),
- .fixups = &micron_st_fixups,
+ .parts = micron_nor_parts,
+ .nparts = ARRAY_SIZE(micron_nor_parts),
+ .fixups = &micron_st_nor_fixups,
};
const struct spi_nor_manufacturer spi_nor_st = {
.name = "st",
- .parts = st_parts,
- .nparts = ARRAY_SIZE(st_parts),
- .fixups = &micron_st_fixups,
+ .parts = st_nor_parts,
+ .nparts = ARRAY_SIZE(st_nor_parts),
+ .fixups = &micron_st_nor_fixups,
};
diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
index 534196b1d3e7..f24e546e04a5 100644
--- a/drivers/mtd/spi-nor/spansion.c
+++ b/drivers/mtd/spi-nor/spansion.c
@@ -8,6 +8,10 @@
#include "core.h"
+/* flash_info mfr_flag. Used to clear sticky prorietary SR bits. */
+#define USE_CLSR BIT(0)
+
+#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
#define SPINOR_REG_CYPRESS_CFR2V 0x00800003
@@ -20,7 +24,7 @@
#define SPINOR_OP_CYPRESS_RD_FAST 0xee
/**
- * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
+ * cypress_nor_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
* @nor: pointer to a 'struct spi_nor'
* @enable: whether to enable or disable Octal DTR
*
@@ -29,7 +33,7 @@
*
* Return: 0 on success, -errno otherwise.
*/
-static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor, bool enable)
+static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
{
struct spi_mem_op op;
u8 *buf = nor->bouncebuf;
@@ -116,7 +120,7 @@ static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor, bool enable)
static void s28hs512t_default_init(struct spi_nor *nor)
{
- nor->params->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable;
+ nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable;
nor->params->writesize = 16;
}
@@ -183,9 +187,9 @@ static const struct spi_nor_fixups s28hs512t_fixups = {
};
static int
-s25fs_s_post_bfpt_fixups(struct spi_nor *nor,
- const struct sfdp_parameter_header *bfpt_header,
- const struct sfdp_bfpt *bfpt)
+s25fs_s_nor_post_bfpt_fixups(struct spi_nor *nor,
+ const struct sfdp_parameter_header *bfpt_header,
+ const struct sfdp_bfpt *bfpt)
{
/*
* The S25FS-S chip family reports 512-byte pages in BFPT but
@@ -198,11 +202,11 @@ s25fs_s_post_bfpt_fixups(struct spi_nor *nor,
return 0;
}
-static const struct spi_nor_fixups s25fs_s_fixups = {
- .post_bfpt = s25fs_s_post_bfpt_fixups,
+static const struct spi_nor_fixups s25fs_s_nor_fixups = {
+ .post_bfpt = s25fs_s_nor_post_bfpt_fixups,
};
-static const struct flash_info spansion_parts[] = {
+static const struct flash_info spansion_nor_parts[] = {
/* Spansion/Cypress -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
*/
@@ -211,43 +215,53 @@ static const struct flash_info spansion_parts[] = {
{ "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128)
NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl128s0", INFO6(0x012018, 0x4d0080, 256 * 1024, 64)
- FLAGS(USE_CLSR)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_CLSR)
+ },
{ "s25fl128s1", INFO6(0x012018, 0x4d0180, 64 * 1024, 256)
- FLAGS(USE_CLSR)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_CLSR)
+ },
{ "s25fl256s0", INFO6(0x010219, 0x4d0080, 256 * 1024, 128)
- FLAGS(USE_CLSR)
NO_SFDP_FLAGS(SPI_NOR_SKIP_SFDP | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
+ SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_CLSR)
+ },
{ "s25fl256s1", INFO6(0x010219, 0x4d0180, 64 * 1024, 512)
- FLAGS(USE_CLSR)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_CLSR)
+ },
{ "s25fl512s", INFO6(0x010220, 0x4d0080, 256 * 1024, 256)
- FLAGS(SPI_NOR_HAS_LOCK | USE_CLSR)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ FLAGS(SPI_NOR_HAS_LOCK)
+ NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_CLSR)
+ },
{ "s25fs128s1", INFO6(0x012018, 0x4d0181, 64 * 1024, 256)
- FLAGS(USE_CLSR)
NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- .fixups = &s25fs_s_fixups, },
+ MFR_FLAGS(USE_CLSR)
+ .fixups = &s25fs_s_nor_fixups, },
{ "s25fs256s0", INFO6(0x010219, 0x4d0081, 256 * 1024, 128)
- FLAGS(USE_CLSR)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_CLSR)
+ },
{ "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512)
- FLAGS(USE_CLSR)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_CLSR)
+ },
{ "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256)
- FLAGS(USE_CLSR)
NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- .fixups = &s25fs_s_fixups, },
+ MFR_FLAGS(USE_CLSR)
+ .fixups = &s25fs_s_nor_fixups, },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64)
- FLAGS(USE_CLSR)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_CLSR)
+ },
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256)
- FLAGS(USE_CLSR)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
+ MFR_FLAGS(USE_CLSR)
+ },
{ "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8) },
{ "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16) },
{ "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32) },
@@ -294,24 +308,92 @@ static const struct flash_info spansion_parts[] = {
},
};
-static void spansion_late_init(struct spi_nor *nor)
+/**
+ * spansion_nor_clear_sr() - Clear the Status Register.
+ * @nor: pointer to 'struct spi_nor'.
+ */
+static void spansion_nor_clear_sr(struct spi_nor *nor)
{
- if (nor->params->size <= SZ_16M)
- return;
+ int ret;
+
+ if (nor->spimem) {
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_NO_DATA);
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ } else {
+ ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR,
+ NULL, 0);
+ }
+
+ if (ret)
+ dev_dbg(nor->dev, "error %d clearing SR\n", ret);
+}
+
+/**
+ * spansion_nor_sr_ready_and_clear() - Query the Status Register to see if the
+ * flash is ready for new commands and clear it if there are any errors.
+ * @nor: pointer to 'struct spi_nor'.
+ *
+ * Return: 1 if ready, 0 if not ready, -errno on errors.
+ */
+static int spansion_nor_sr_ready_and_clear(struct spi_nor *nor)
+{
+ int ret;
+
+ ret = spi_nor_read_sr(nor, nor->bouncebuf);
+ if (ret)
+ return ret;
+
+ if (nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) {
+ if (nor->bouncebuf[0] & SR_E_ERR)
+ dev_err(nor->dev, "Erase Error occurred\n");
+ else
+ dev_err(nor->dev, "Programming Error occurred\n");
+
+ spansion_nor_clear_sr(nor);
+
+ /*
+ * WEL bit remains set to one when an erase or page program
+ * error occurs. Issue a Write Disable command to protect
+ * against inadvertent writes that can possibly corrupt the
+ * contents of the memory.
+ */
+ ret = spi_nor_write_disable(nor);
+ if (ret)
+ return ret;
+
+ return -EIO;
+ }
+
+ return !(nor->bouncebuf[0] & SR_WIP);
+}
+
+static void spansion_nor_late_init(struct spi_nor *nor)
+{
+ if (nor->params->size > SZ_16M) {
+ nor->flags |= SNOR_F_4B_OPCODES;
+ /* No small sector erase for 4-byte command set */
+ nor->erase_opcode = SPINOR_OP_SE;
+ nor->mtd.erasesize = nor->info->sector_size;
+ }
- nor->flags |= SNOR_F_4B_OPCODES;
- /* No small sector erase for 4-byte command set */
- nor->erase_opcode = SPINOR_OP_SE;
- nor->mtd.erasesize = nor->info->sector_size;
+ if (nor->info->mfr_flags & USE_CLSR)
+ nor->params->ready = spansion_nor_sr_ready_and_clear;
}
-static const struct spi_nor_fixups spansion_fixups = {
- .late_init = spansion_late_init,
+static const struct spi_nor_fixups spansion_nor_fixups = {
+ .late_init = spansion_nor_late_init,
};
const struct spi_nor_manufacturer spi_nor_spansion = {
.name = "spansion",
- .parts = spansion_parts,
- .nparts = ARRAY_SIZE(spansion_parts),
- .fixups = &spansion_fixups,
+ .parts = spansion_nor_parts,
+ .nparts = ARRAY_SIZE(spansion_nor_parts),
+ .fixups = &spansion_nor_fixups,
};
diff --git a/drivers/mtd/spi-nor/sst.c b/drivers/mtd/spi-nor/sst.c
index 30183e9189b9..63bcc97bf978 100644
--- a/drivers/mtd/spi-nor/sst.c
+++ b/drivers/mtd/spi-nor/sst.c
@@ -13,12 +13,12 @@
#define SST26VF_CR_BPNV BIT(3)
-static int sst26vf_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int sst26vf_nor_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
return -EOPNOTSUPP;
}
-static int sst26vf_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int sst26vf_nor_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
int ret;
@@ -38,27 +38,27 @@ static int sst26vf_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
return spi_nor_global_block_unlock(nor);
}
-static int sst26vf_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int sst26vf_nor_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
return -EOPNOTSUPP;
}
-static const struct spi_nor_locking_ops sst26vf_locking_ops = {
- .lock = sst26vf_lock,
- .unlock = sst26vf_unlock,
- .is_locked = sst26vf_is_locked,
+static const struct spi_nor_locking_ops sst26vf_nor_locking_ops = {
+ .lock = sst26vf_nor_lock,
+ .unlock = sst26vf_nor_unlock,
+ .is_locked = sst26vf_nor_is_locked,
};
-static void sst26vf_late_init(struct spi_nor *nor)
+static void sst26vf_nor_late_init(struct spi_nor *nor)
{
- nor->params->locking_ops = &sst26vf_locking_ops;
+ nor->params->locking_ops = &sst26vf_nor_locking_ops;
}
-static const struct spi_nor_fixups sst26vf_fixups = {
- .late_init = sst26vf_late_init,
+static const struct spi_nor_fixups sst26vf_nor_fixups = {
+ .late_init = sst26vf_nor_late_init,
};
-static const struct flash_info sst_parts[] = {
+static const struct flash_info sst_nor_parts[] = {
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
@@ -114,11 +114,11 @@ static const struct flash_info sst_parts[] = {
{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- .fixups = &sst26vf_fixups },
+ .fixups = &sst26vf_nor_fixups },
};
-static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
+static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
size_t actual = 0;
@@ -203,19 +203,19 @@ out:
return ret;
}
-static void sst_late_init(struct spi_nor *nor)
+static void sst_nor_late_init(struct spi_nor *nor)
{
if (nor->info->mfr_flags & SST_WRITE)
- nor->mtd._write = sst_write;
+ nor->mtd._write = sst_nor_write;
}
-static const struct spi_nor_fixups sst_fixups = {
- .late_init = sst_late_init,
+static const struct spi_nor_fixups sst_nor_fixups = {
+ .late_init = sst_nor_late_init,
};
const struct spi_nor_manufacturer spi_nor_sst = {
.name = "sst",
- .parts = sst_parts,
- .nparts = ARRAY_SIZE(sst_parts),
- .fixups = &sst_fixups,
+ .parts = sst_nor_parts,
+ .nparts = ARRAY_SIZE(sst_nor_parts),
+ .fixups = &sst_nor_fixups,
};
diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c
index 675f32c136b3..fe80dffc2e70 100644
--- a/drivers/mtd/spi-nor/winbond.c
+++ b/drivers/mtd/spi-nor/winbond.c
@@ -32,7 +32,7 @@ static const struct spi_nor_fixups w25q256_fixups = {
.post_bfpt = w25q256_post_bfpt_fixups,
};
-static const struct flash_info winbond_parts[] = {
+static const struct flash_info winbond_nor_parts[] = {
/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
{ "w25x05", INFO(0xef3010, 0, 64 * 1024, 1)
NO_SFDP_FLAGS(SECT_4K) },
@@ -130,14 +130,15 @@ static const struct flash_info winbond_parts[] = {
};
/**
- * winbond_set_4byte_addr_mode() - Set 4-byte address mode for Winbond flashes.
+ * winbond_nor_set_4byte_addr_mode() - Set 4-byte address mode for Winbond
+ * flashes.
* @nor: pointer to 'struct spi_nor'.
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte
* address mode.
*
* Return: 0 on success, -errno otherwise.
*/
-static int winbond_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
+static int winbond_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
{
int ret;
@@ -161,7 +162,7 @@ static int winbond_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
return spi_nor_write_disable(nor);
}
-static const struct spi_nor_otp_ops winbond_otp_ops = {
+static const struct spi_nor_otp_ops winbond_nor_otp_ops = {
.read = spi_nor_otp_read_secr,
.write = spi_nor_otp_write_secr,
.erase = spi_nor_otp_erase_secr,
@@ -169,25 +170,25 @@ static const struct spi_nor_otp_ops winbond_otp_ops = {
.is_locked = spi_nor_otp_is_locked_sr2,
};
-static void winbond_default_init(struct spi_nor *nor)
+static void winbond_nor_default_init(struct spi_nor *nor)
{
- nor->params->set_4byte_addr_mode = winbond_set_4byte_addr_mode;
+ nor->params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode;
}
-static void winbond_late_init(struct spi_nor *nor)
+static void winbond_nor_late_init(struct spi_nor *nor)
{
if (nor->params->otp.org->n_regions)
- nor->params->otp.ops = &winbond_otp_ops;
+ nor->params->otp.ops = &winbond_nor_otp_ops;
}
-static const struct spi_nor_fixups winbond_fixups = {
- .default_init = winbond_default_init,
- .late_init = winbond_late_init,
+static const struct spi_nor_fixups winbond_nor_fixups = {
+ .default_init = winbond_nor_default_init,
+ .late_init = winbond_nor_late_init,
};
const struct spi_nor_manufacturer spi_nor_winbond = {
.name = "winbond",
- .parts = winbond_parts,
- .nparts = ARRAY_SIZE(winbond_parts),
- .fixups = &winbond_fixups,
+ .parts = winbond_nor_parts,
+ .nparts = ARRAY_SIZE(winbond_nor_parts),
+ .fixups = &winbond_nor_fixups,
};
diff --git a/drivers/mtd/spi-nor/xilinx.c b/drivers/mtd/spi-nor/xilinx.c
index 580562bc1e45..9459ac2609dc 100644
--- a/drivers/mtd/spi-nor/xilinx.c
+++ b/drivers/mtd/spi-nor/xilinx.c
@@ -8,7 +8,28 @@
#include "core.h"
-static const struct flash_info xilinx_parts[] = {
+#define XILINX_OP_SE 0x50 /* Sector erase */
+#define XILINX_OP_PP 0x82 /* Page program */
+#define XILINX_OP_RDSR 0xd7 /* Read status register */
+
+#define XSR_PAGESIZE BIT(0) /* Page size in Po2 or Linear */
+#define XSR_RDY BIT(7) /* Ready */
+
+#define S3AN_INFO(_jedec_id, _n_sectors, _page_size) \
+ .id = { \
+ ((_jedec_id) >> 16) & 0xff, \
+ ((_jedec_id) >> 8) & 0xff, \
+ (_jedec_id) & 0xff \
+ }, \
+ .id_len = 3, \
+ .sector_size = (8 * (_page_size)), \
+ .n_sectors = (_n_sectors), \
+ .page_size = (_page_size), \
+ .addr_width = 3, \
+ .flags = SPI_NOR_NO_FR
+
+/* Xilinx S3AN share MFR with Atmel SPI NOR */
+static const struct flash_info xilinx_nor_parts[] = {
/* Xilinx S3AN Internal Flash */
{ "3S50AN", S3AN_INFO(0x1f2200, 64, 264) },
{ "3S200AN", S3AN_INFO(0x1f2400, 256, 264) },
@@ -26,7 +47,7 @@ static const struct flash_info xilinx_parts[] = {
* Addr can safely be unsigned int, the biggest S3AN device is smaller than
* 4 MiB.
*/
-static u32 s3an_convert_addr(struct spi_nor *nor, u32 addr)
+static u32 s3an_nor_convert_addr(struct spi_nor *nor, u32 addr)
{
u32 page_size = nor->params->page_size;
u32 offset, page;
@@ -38,18 +59,69 @@ static u32 s3an_convert_addr(struct spi_nor *nor, u32 addr)
return page | offset;
}
+/**
+ * xilinx_nor_read_sr() - Read the Status Register on S3AN flashes.
+ * @nor: pointer to 'struct spi_nor'.
+ * @sr: pointer to a DMA-able buffer where the value of the
+ * Status Register will be written.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int xilinx_nor_read_sr(struct spi_nor *nor, u8 *sr)
+{
+ int ret;
+
+ if (nor->spimem) {
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(XILINX_OP_RDSR, 0),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_IN(1, sr, 0));
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ } else {
+ ret = spi_nor_controller_ops_read_reg(nor, XILINX_OP_RDSR, sr,
+ 1);
+ }
+
+ if (ret)
+ dev_dbg(nor->dev, "error %d reading SR\n", ret);
+
+ return ret;
+}
+
+/**
+ * xilinx_nor_sr_ready() - Query the Status Register of the S3AN flash to see
+ * if the flash is ready for new commands.
+ * @nor: pointer to 'struct spi_nor'.
+ *
+ * Return: 1 if ready, 0 if not ready, -errno on errors.
+ */
+static int xilinx_nor_sr_ready(struct spi_nor *nor)
+{
+ int ret;
+
+ ret = xilinx_nor_read_sr(nor, nor->bouncebuf);
+ if (ret)
+ return ret;
+
+ return !!(nor->bouncebuf[0] & XSR_RDY);
+}
+
static int xilinx_nor_setup(struct spi_nor *nor,
const struct spi_nor_hwcaps *hwcaps)
{
u32 page_size;
int ret;
- ret = spi_nor_xread_sr(nor, nor->bouncebuf);
+ ret = xilinx_nor_read_sr(nor, nor->bouncebuf);
if (ret)
return ret;
- nor->erase_opcode = SPINOR_OP_XSE;
- nor->program_opcode = SPINOR_OP_XPP;
+ nor->erase_opcode = XILINX_OP_SE;
+ nor->program_opcode = XILINX_OP_PP;
nor->read_opcode = SPINOR_OP_READ;
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
@@ -73,25 +145,26 @@ static int xilinx_nor_setup(struct spi_nor *nor,
nor->mtd.erasesize = 8 * page_size;
} else {
/* Flash in Default addressing mode */
- nor->params->convert_addr = s3an_convert_addr;
+ nor->params->convert_addr = s3an_nor_convert_addr;
nor->mtd.erasesize = nor->info->sector_size;
}
return 0;
}
-static void xilinx_late_init(struct spi_nor *nor)
+static void xilinx_nor_late_init(struct spi_nor *nor)
{
nor->params->setup = xilinx_nor_setup;
+ nor->params->ready = xilinx_nor_sr_ready;
}
-static const struct spi_nor_fixups xilinx_fixups = {
- .late_init = xilinx_late_init,
+static const struct spi_nor_fixups xilinx_nor_fixups = {
+ .late_init = xilinx_nor_late_init,
};
const struct spi_nor_manufacturer spi_nor_xilinx = {
.name = "xilinx",
- .parts = xilinx_parts,
- .nparts = ARRAY_SIZE(xilinx_parts),
- .fixups = &xilinx_fixups,
+ .parts = xilinx_nor_parts,
+ .nparts = ARRAY_SIZE(xilinx_nor_parts),
+ .fixups = &xilinx_nor_fixups,
};
diff --git a/drivers/mtd/spi-nor/xmc.c b/drivers/mtd/spi-nor/xmc.c
index 2992af03cb0a..051411e86339 100644
--- a/drivers/mtd/spi-nor/xmc.c
+++ b/drivers/mtd/spi-nor/xmc.c
@@ -8,7 +8,7 @@
#include "core.h"
-static const struct flash_info xmc_parts[] = {
+static const struct flash_info xmc_nor_parts[] = {
/* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */
{ "XM25QH64A", INFO(0x207017, 0, 64 * 1024, 128)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
@@ -20,6 +20,6 @@ static const struct flash_info xmc_parts[] = {
const struct spi_nor_manufacturer spi_nor_xmc = {
.name = "xmc",
- .parts = xmc_parts,
- .nparts = ARRAY_SIZE(xmc_parts),
+ .parts = xmc_nor_parts,
+ .nparts = ARRAY_SIZE(xmc_nor_parts),
};