Skip to content

Commit 9641423

Browse files
committed
mtd: spi-nor: add erase die (chip) capability
JESD216 mentions die erase, but does not provide an opcode for it. Check BFPT dword 11, bits 30:24, "Chip Erase, Typical time", it says: "Typical time to erase one chip (die). User must poll device busy to determine if the operation has completed. For a device consisting of multiple dies, that are individually accessed, the time is for each die to which a chip erase command is applied." So when a flash consists of a single die, this is the erase time for the full chip (die) erase, and when it consists of multiple dies, it's the die erase time. Chip and die are the same thing. Add support for die erase. 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. Tested-by: Fabio Estevam <festevam@denx.de> Link: https://lore.kernel.org/r/20231125123529.55686-2-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
1 parent 9b3eae3 commit 9641423

File tree

3 files changed

+81
-37
lines changed

3 files changed

+81
-37
lines changed

drivers/mtd/spi-nor/core.c

Lines changed: 75 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,24 +1060,32 @@ static int spi_nor_read_sr2(struct spi_nor *nor, u8 *sr2)
10601060
}
10611061

10621062
/**
1063-
* spi_nor_erase_chip() - Erase the entire flash memory.
1063+
* spi_nor_erase_die() - Erase the entire die.
10641064
* @nor: pointer to 'struct spi_nor'.
1065+
* @addr: address of the die.
1066+
* @die_size: size of the die.
10651067
*
10661068
* Return: 0 on success, -errno otherwise.
10671069
*/
1068-
static int spi_nor_erase_chip(struct spi_nor *nor)
1070+
static int spi_nor_erase_die(struct spi_nor *nor, loff_t addr, size_t die_size)
10691071
{
1072+
bool multi_die = nor->mtd.size != die_size;
10701073
int ret;
10711074

1072-
dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
1075+
dev_dbg(nor->dev, " %lldKiB\n", (long long)(die_size >> 10));
10731076

10741077
if (nor->spimem) {
1075-
struct spi_mem_op op = SPI_NOR_CHIP_ERASE_OP;
1078+
struct spi_mem_op op =
1079+
SPI_NOR_DIE_ERASE_OP(nor->params->die_erase_opcode,
1080+
nor->addr_nbytes, addr, multi_die);
10761081

10771082
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
10781083

10791084
ret = spi_mem_exec_op(nor->spimem, &op);
10801085
} else {
1086+
if (multi_die)
1087+
return -EOPNOTSUPP;
1088+
10811089
ret = spi_nor_controller_ops_write_reg(nor,
10821090
SPINOR_OP_CHIP_ERASE,
10831091
NULL, 0);
@@ -1792,14 +1800,62 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len)
17921800
return ret;
17931801
}
17941802

1803+
static int spi_nor_erase_dice(struct spi_nor *nor, loff_t addr,
1804+
size_t len, size_t die_size)
1805+
{
1806+
unsigned long timeout;
1807+
int ret;
1808+
1809+
/*
1810+
* Scale the timeout linearly with the size of the flash, with
1811+
* a minimum calibrated to an old 2MB flash. We could try to
1812+
* pull these from CFI/SFDP, but these values should be good
1813+
* enough for now.
1814+
*/
1815+
timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
1816+
CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
1817+
(unsigned long)(nor->mtd.size / SZ_2M));
1818+
1819+
do {
1820+
ret = spi_nor_lock_device(nor);
1821+
if (ret)
1822+
return ret;
1823+
1824+
ret = spi_nor_write_enable(nor);
1825+
if (ret) {
1826+
spi_nor_unlock_device(nor);
1827+
return ret;
1828+
}
1829+
1830+
ret = spi_nor_erase_die(nor, addr, die_size);
1831+
1832+
spi_nor_unlock_device(nor);
1833+
if (ret)
1834+
return ret;
1835+
1836+
ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
1837+
if (ret)
1838+
return ret;
1839+
1840+
addr += die_size;
1841+
len -= die_size;
1842+
1843+
} while (len);
1844+
1845+
return 0;
1846+
}
1847+
17951848
/*
17961849
* Erase an address range on the nor chip. The address range may extend
17971850
* one or more erase sectors. Return an error if there is a problem erasing.
17981851
*/
17991852
static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
18001853
{
18011854
struct spi_nor *nor = mtd_to_spi_nor(mtd);
1855+
u8 n_dice = nor->params->n_dice;
1856+
bool multi_die_erase = false;
18021857
u32 addr, len, rem;
1858+
size_t die_size;
18031859
int ret;
18041860

18051861
dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
@@ -1814,39 +1870,22 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
18141870
addr = instr->addr;
18151871
len = instr->len;
18161872

1873+
if (n_dice) {
1874+
die_size = div_u64(mtd->size, n_dice);
1875+
if (!(len & (die_size - 1)) && !(addr & (die_size - 1)))
1876+
multi_die_erase = true;
1877+
} else {
1878+
die_size = mtd->size;
1879+
}
1880+
18171881
ret = spi_nor_prep_and_lock_pe(nor, instr->addr, instr->len);
18181882
if (ret)
18191883
return ret;
18201884

1821-
/* whole-chip erase? */
1822-
if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
1823-
unsigned long timeout;
1824-
1825-
ret = spi_nor_lock_device(nor);
1826-
if (ret)
1827-
goto erase_err;
1828-
1829-
ret = spi_nor_write_enable(nor);
1830-
if (ret) {
1831-
spi_nor_unlock_device(nor);
1832-
goto erase_err;
1833-
}
1834-
1835-
ret = spi_nor_erase_chip(nor);
1836-
spi_nor_unlock_device(nor);
1837-
if (ret)
1838-
goto erase_err;
1839-
1840-
/*
1841-
* Scale the timeout linearly with the size of the flash, with
1842-
* a minimum calibrated to an old 2MB flash. We could try to
1843-
* pull these from CFI/SFDP, but these values should be good
1844-
* enough for now.
1845-
*/
1846-
timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
1847-
CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
1848-
(unsigned long)(mtd->size / SZ_2M));
1849-
ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
1885+
/* chip (die) erase? */
1886+
if ((len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) ||
1887+
multi_die_erase) {
1888+
ret = spi_nor_erase_dice(nor, addr, len, die_size);
18501889
if (ret)
18511890
goto erase_err;
18521891

@@ -2902,6 +2941,9 @@ static int spi_nor_late_init_params(struct spi_nor *nor)
29022941
return ret;
29032942
}
29042943

2944+
if (!nor->params->die_erase_opcode)
2945+
nor->params->die_erase_opcode = SPINOR_OP_CHIP_ERASE;
2946+
29052947
/* Default method kept for backward compatibility. */
29062948
if (!params->set_4byte_addr_mode)
29072949
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr;

drivers/mtd/spi-nor/core.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@
8585
SPI_MEM_OP_NO_DUMMY, \
8686
SPI_MEM_OP_NO_DATA)
8787

88-
#define SPI_NOR_CHIP_ERASE_OP \
89-
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CHIP_ERASE, 0), \
90-
SPI_MEM_OP_NO_ADDR, \
88+
#define SPI_NOR_DIE_ERASE_OP(opcode, addr_nbytes, addr, dice) \
89+
SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0), \
90+
SPI_MEM_OP_ADDR(dice ? addr_nbytes : 0, addr, 0), \
9191
SPI_MEM_OP_NO_DUMMY, \
9292
SPI_MEM_OP_NO_DATA)
9393

@@ -362,6 +362,7 @@ struct spi_nor_otp {
362362
* command in octal DTR mode.
363363
* @n_banks: number of banks.
364364
* @n_dice: number of dice in the flash memory.
365+
* @die_erase_opcode: die erase opcode. Defaults to SPINOR_OP_CHIP_ERASE.
365366
* @vreg_offset: volatile register offset for each die.
366367
* @hwcaps: describes the read and page program hardware
367368
* capabilities.
@@ -399,6 +400,7 @@ struct spi_nor_flash_parameter {
399400
u8 rdsr_addr_nbytes;
400401
u8 n_banks;
401402
u8 n_dice;
403+
u8 die_erase_opcode;
402404
u32 *vreg_offset;
403405

404406
struct spi_nor_hwcaps hwcaps;

drivers/mtd/spi-nor/debugfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ static int spi_nor_params_show(struct seq_file *s, void *data)
138138

139139
if (!(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
140140
string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));
141-
seq_printf(s, " %02x (%s)\n", SPINOR_OP_CHIP_ERASE, buf);
141+
seq_printf(s, " %02x (%s)\n", nor->params->die_erase_opcode, buf);
142142
}
143143

144144
seq_puts(s, "\nsector map\n");

0 commit comments

Comments
 (0)