summaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorTudor Ambarus <tudor.ambarus@linaro.org>2023-11-25 13:35:27 +0100
committerTudor Ambarus <tudor.ambarus@linaro.org>2023-12-06 10:25:07 +0100
commit53919a968b43648822f2d35b6cafacd3950238cc (patch)
tree9e5d91da194fb15932c55cc1e26c002eb3b6c611 /drivers/mtd
parentmtd: spi-nor: spansion: enable die erase for multi die flashes (diff)
downloadlinux-53919a968b43648822f2d35b6cafacd3950238cc.tar.xz
linux-53919a968b43648822f2d35b6cafacd3950238cc.zip
mtd: spi-nor: micron-st: enable die erase for multi die flashes
Enable die erase for multi die flashes, it will speed the erase time. Unfortunately, Micron does not provide a 4-byte opcode equivalent for the die erase. The SFDP 4BAIT table fails to consider the die erase too, the standard can be improved. Thus we're forced to enter in the 4 byte address mode in order to benefit of the die erase. Tested on n25q00. This flash defines the 4BAIT SFDP table, thus it will use the 4BAIT opcodes for reads, page programs or erases, with the exception that it will use the die erase command in the 4 byte address mode. Link: https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/nor-flash/serial-nor/n25q/n25q_1gb_3v_65nm.pdf?rev=b6eba74759984f749f8c039bc5bc47b7 Link: https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/nor-flash/serial-nor/mt25q/die-rev-b/mt25q_qlkt_l_02g_cbb_0.pdf?rev=43f7f66fc8da4d7d901b35fa51284c8f Link: https://lore.kernel.org/r/20231125123529.55686-4-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/spi-nor/core.c32
-rw-r--r--drivers/mtd/spi-nor/micron-st.c34
2 files changed, 47 insertions, 19 deletions
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 479494cf00c9..52e5b569ddfd 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -2935,6 +2935,9 @@ static int spi_nor_late_init_params(struct spi_nor *nor)
return ret;
}
+ /* Needed by some flashes late_init hooks. */
+ spi_nor_init_flags(nor);
+
if (nor->info->fixups && nor->info->fixups->late_init) {
ret = nor->info->fixups->late_init(nor);
if (ret)
@@ -2948,7 +2951,6 @@ static int spi_nor_late_init_params(struct spi_nor *nor)
if (!params->set_4byte_addr_mode)
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr;
- spi_nor_init_flags(nor);
spi_nor_init_fixup_flags(nor);
/*
@@ -3186,6 +3188,18 @@ int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
struct spi_nor_flash_parameter *params = nor->params;
int ret;
+ if (enable) {
+ /*
+ * If the RESET# pin isn't hooked up properly, or the system
+ * otherwise doesn't perform a reset command in the boot
+ * sequence, it's impossible to 100% protect against unexpected
+ * reboots (e.g., crashes). Warn the user (or hopefully, system
+ * designer) that this is bad.
+ */
+ WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
+ "enabling reset hack; may not recover from unexpected reboots\n");
+ }
+
ret = params->set_4byte_addr_mode(nor, enable);
if (ret && ret != -ENOTSUPP)
return ret;
@@ -3234,20 +3248,8 @@ static int spi_nor_init(struct spi_nor *nor)
if (nor->addr_nbytes == 4 &&
nor->read_proto != SNOR_PROTO_8_8_8_DTR &&
- !(nor->flags & SNOR_F_4B_OPCODES)) {
- /*
- * If the RESET# pin isn't hooked up properly, or the system
- * otherwise doesn't perform a reset command in the boot
- * sequence, it's impossible to 100% protect against unexpected
- * reboots (e.g., crashes). Warn the user (or hopefully, system
- * designer) that this is bad.
- */
- WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
- "enabling reset hack; may not recover from unexpected reboots\n");
- err = spi_nor_set_4byte_addr_mode(nor, true);
- if (err)
- return err;
- }
+ !(nor->flags & SNOR_F_4B_OPCODES))
+ return spi_nor_set_4byte_addr_mode(nor, true);
return 0;
}
diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c
index 8920547c12bf..b63f1e9b97d0 100644
--- a/drivers/mtd/spi-nor/micron-st.c
+++ b/drivers/mtd/spi-nor/micron-st.c
@@ -11,6 +11,7 @@
/* flash_info mfr_flag. Used to read proprietary FSR register. */
#define USE_FSR BIT(0)
+#define SPINOR_OP_MT_DIE_ERASE 0xc4 /* Chip (die) erase opcode */
#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 */
@@ -192,6 +193,30 @@ static struct spi_nor_fixups mt25qu512a_fixups = {
.post_bfpt = mt25qu512a_post_bfpt_fixup,
};
+static int st_nor_four_die_late_init(struct spi_nor *nor)
+{
+ struct spi_nor_flash_parameter *params = nor->params;
+
+ params->die_erase_opcode = SPINOR_OP_MT_DIE_ERASE;
+ params->n_dice = 4;
+
+ /*
+ * Unfortunately the die erase opcode does not have a 4-byte opcode
+ * correspondent for these flashes. The SFDP 4BAIT table fails to
+ * consider the die erase too. We're forced to enter in the 4 byte
+ * address mode in order to benefit of the die erase.
+ */
+ return spi_nor_set_4byte_addr_mode(nor, true);
+}
+
+static struct spi_nor_fixups n25q00_fixups = {
+ .late_init = st_nor_four_die_late_init,
+};
+
+static struct spi_nor_fixups mt25q02_fixups = {
+ .late_init = st_nor_four_die_late_init,
+};
+
static const struct flash_info st_nor_parts[] = {
{
.name = "m25p05-nonjedec",
@@ -366,16 +391,17 @@ static const struct flash_info st_nor_parts[] = {
.name = "n25q00",
.size = SZ_128M,
.flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
- SPI_NOR_BP3_SR_BIT6 | NO_CHIP_ERASE,
+ SPI_NOR_BP3_SR_BIT6,
.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
.mfr_flags = USE_FSR,
+ .fixups = &n25q00_fixups,
}, {
.id = SNOR_ID(0x20, 0xba, 0x22),
.name = "mt25ql02g",
.size = SZ_256M,
- .flags = NO_CHIP_ERASE,
.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
.mfr_flags = USE_FSR,
+ .fixups = &mt25q02_fixups,
}, {
.id = SNOR_ID(0x20, 0xbb, 0x15),
.name = "n25q016a",
@@ -433,16 +459,16 @@ static const struct flash_info st_nor_parts[] = {
.id = SNOR_ID(0x20, 0xbb, 0x21),
.name = "n25q00a",
.size = SZ_128M,
- .flags = NO_CHIP_ERASE,
.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
.mfr_flags = USE_FSR,
+ .fixups = &n25q00_fixups,
}, {
.id = SNOR_ID(0x20, 0xbb, 0x22),
.name = "mt25qu02g",
.size = SZ_256M,
- .flags = NO_CHIP_ERASE,
.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
.mfr_flags = USE_FSR,
+ .fixups = &mt25q02_fixups,
}
};