[PATCH 2/6] mtd: spi-nor: add erase die (chip) capability
Tudor Ambarus
tudor.ambarus at linaro.org
Wed Nov 1 02:48:15 PDT 2023
On 01.11.2023 11:43, Tudor Ambarus wrote:
> JESD216 defines a chip as a die, one and the other are the same thing.
> JESD216 clarifies that the chip erase time defined in BFPT dword(11)
> applies separately to each die for multi-die devices in which the dice
> are individually accessed. Based on this, update the
> spi_nor_erase_chip() method to support multi-die devices.
>
> For now, benefit of the die erase when addr and len are aligned with die
> size. This could be improved however for the uniform and non-uniform
> erases cases to use the die erase when possible. For example if one
> requests that an erase of a 2 die device starting from the last 64KB of
> the first die to the end of the flash size, we could use just 2
> commands, a 64KB erase and a die erase. This improvement is left as an
> exercise for the reader, as I don't have multi die flashes at hand.
>
> Signed-off-by: Tudor Ambarus <tudor.ambarus at linaro.org>
> ---
> drivers/mtd/spi-nor/core.c | 22 +++++++++++++++++++---
> drivers/mtd/spi-nor/core.h | 6 ++++--
> drivers/mtd/spi-nor/debugfs.c | 2 +-
> 3 files changed, 24 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
> index 25a64c65717d..360fce7ffe82 100644
> --- a/drivers/mtd/spi-nor/core.c
> +++ b/drivers/mtd/spi-nor/core.c
> @@ -1067,17 +1067,21 @@ static int spi_nor_read_sr2(struct spi_nor *nor, u8 *sr2)
> */
> static int spi_nor_erase_chip(struct spi_nor *nor)
> {
> + u8 opcode = nor->params->chip_erase_opcode;
> int ret;
>
> dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
>
> if (nor->spimem) {
> - struct spi_mem_op op = SPI_NOR_CHIP_ERASE_OP;
> + struct spi_mem_op op = SPI_NOR_CHIP_ERASE_OP(opcode);
>
> spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
>
> ret = spi_mem_exec_op(nor->spimem, &op);
> } else {
> + if (opcode != SPINOR_OP_CHIP_ERASE)
> + return -EOPNOTSUPP;
> +
> ret = spi_nor_controller_ops_write_reg(nor,
> SPINOR_OP_CHIP_ERASE,
> NULL, 0);
> @@ -1799,7 +1803,10 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len)
> static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
> {
> struct spi_nor *nor = mtd_to_spi_nor(mtd);
> + u8 n_dice = nor->params->n_dice;
> + bool die_erase = false;
> u32 addr, len, rem;
> + size_t die_size;
> int ret;
>
> dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
> @@ -1814,12 +1821,18 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
> addr = instr->addr;
> len = instr->len;
>
> + if (n_dice) {
> + die_size = div_u64(mtd->size, n_dice);
> + if (len == die_size && (addr & (die_size - 1)))
> + die_erase = true;
> + }
> +
> ret = spi_nor_prep_and_lock_pe(nor, instr->addr, instr->len);
> if (ret)
> return ret;
>
> - /* whole-chip erase? */
> - if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
> + /* chip (die) erase? */
> + if ((len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) || die_erase) {
> unsigned long timeout;
>
> ret = spi_nor_lock_device(nor);
> @@ -2902,6 +2915,9 @@ static int spi_nor_late_init_params(struct spi_nor *nor)
> return ret;
> }
>
> + if (nor->params->chip_erase_opcode)
oops, here I wanted to check for null, when null, set the default.
Takahiro and Fabio, would you please update when/if testing?
if (!nor->params->chip_erase_opcode)
Thanks!
More information about the linux-mtd
mailing list