mtd: spi-nor: micron-st: enable die erase for multi die flashes
authorTudor Ambarus <tudor.ambarus@linaro.org>
Sat, 25 Nov 2023 12:35:27 +0000 (14:35 +0200)
committerTudor Ambarus <tudor.ambarus@linaro.org>
Wed, 6 Dec 2023 09:25:07 +0000 (11:25 +0200)
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>
drivers/mtd/spi-nor/core.c
drivers/mtd/spi-nor/micron-st.c

index 479494cf00c92b9382f3662eebab3849565fc0c2..52e5b569ddfd6d219cef44c33d686eb341e68f5c 100644 (file)
@@ -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;
 }
index 8920547c12bfd6b7eaad4f8cec9b9294deec8b20..b63f1e9b97d00290a02240518a2e3962c69d4677 100644 (file)
@@ -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,
        }
 };