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>
This commit is contained in:
Tudor Ambarus 2023-11-25 14:35:27 +02:00
parent 461d0babb5
commit 53919a968b
No known key found for this signature in database
GPG Key ID: 4B554F47A58D14E9
2 changed files with 47 additions and 19 deletions

View 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;
}

View 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,
}
};