}
/**
- * spi_nor_erase_chip() - Erase the entire flash memory.
+ * spi_nor_erase_die() - Erase the entire die.
* @nor: pointer to 'struct spi_nor'.
+ * @addr: address of the die.
+ * @die_size: size of the die.
*
* Return: 0 on success, -errno otherwise.
*/
-static int spi_nor_erase_chip(struct spi_nor *nor)
+static int spi_nor_erase_die(struct spi_nor *nor, loff_t addr, size_t die_size)
{
+ bool multi_die = nor->mtd.size != die_size;
int ret;
- dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
+ dev_dbg(nor->dev, " %lldKiB\n", (long long)(die_size >> 10));
if (nor->spimem) {
- struct spi_mem_op op = SPI_NOR_CHIP_ERASE_OP;
+ struct spi_mem_op op =
+ SPI_NOR_DIE_ERASE_OP(nor->params->die_erase_opcode,
+ nor->addr_nbytes, addr, multi_die);
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
+ if (multi_die)
+ return -EOPNOTSUPP;
+
ret = spi_nor_controller_ops_write_reg(nor,
SPINOR_OP_CHIP_ERASE,
NULL, 0);
return ret;
}
+static int spi_nor_erase_dice(struct spi_nor *nor, loff_t addr,
+ size_t len, size_t die_size)
+{
+ unsigned long timeout;
+ int ret;
+
+ /*
+ * Scale the timeout linearly with the size of the flash, with
+ * a minimum calibrated to an old 2MB flash. We could try to
+ * pull these from CFI/SFDP, but these values should be good
+ * enough for now.
+ */
+ timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
+ CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
+ (unsigned long)(nor->mtd.size / SZ_2M));
+
+ do {
+ ret = spi_nor_lock_device(nor);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_write_enable(nor);
+ if (ret) {
+ spi_nor_unlock_device(nor);
+ return ret;
+ }
+
+ ret = spi_nor_erase_die(nor, addr, die_size);
+
+ spi_nor_unlock_device(nor);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
+ if (ret)
+ return ret;
+
+ addr += die_size;
+ len -= die_size;
+
+ } while (len);
+
+ return 0;
+}
+
/*
* Erase an address range on the nor chip. The address range may extend
* one or more erase sectors. Return an error if there is a problem erasing.
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 multi_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,
addr = instr->addr;
len = instr->len;
+ if (n_dice) {
+ die_size = div_u64(mtd->size, n_dice);
+ if (!(len & (die_size - 1)) && !(addr & (die_size - 1)))
+ multi_die_erase = true;
+ } else {
+ die_size = mtd->size;
+ }
+
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)) {
- unsigned long timeout;
-
- ret = spi_nor_lock_device(nor);
- if (ret)
- goto erase_err;
-
- ret = spi_nor_write_enable(nor);
- if (ret) {
- spi_nor_unlock_device(nor);
- goto erase_err;
- }
-
- ret = spi_nor_erase_chip(nor);
- spi_nor_unlock_device(nor);
- if (ret)
- goto erase_err;
-
- /*
- * Scale the timeout linearly with the size of the flash, with
- * a minimum calibrated to an old 2MB flash. We could try to
- * pull these from CFI/SFDP, but these values should be good
- * enough for now.
- */
- timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
- CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
- (unsigned long)(mtd->size / SZ_2M));
- ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
+ /* chip (die) erase? */
+ if ((len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) ||
+ multi_die_erase) {
+ ret = spi_nor_erase_dice(nor, addr, len, die_size);
if (ret)
goto erase_err;
return ret;
}
+ if (!nor->params->die_erase_opcode)
+ nor->params->die_erase_opcode = SPINOR_OP_CHIP_ERASE;
+
/* Default method kept for backward compatibility. */
if (!params->set_4byte_addr_mode)
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr;
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA)
-#define SPI_NOR_CHIP_ERASE_OP \
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CHIP_ERASE, 0), \
- SPI_MEM_OP_NO_ADDR, \
+#define SPI_NOR_DIE_ERASE_OP(opcode, addr_nbytes, addr, dice) \
+ SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0), \
+ SPI_MEM_OP_ADDR(dice ? addr_nbytes : 0, addr, 0), \
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA)
* command in octal DTR mode.
* @n_banks: number of banks.
* @n_dice: number of dice in the flash memory.
+ * @die_erase_opcode: die erase opcode. Defaults to SPINOR_OP_CHIP_ERASE.
* @vreg_offset: volatile register offset for each die.
* @hwcaps: describes the read and page program hardware
* capabilities.
u8 rdsr_addr_nbytes;
u8 n_banks;
u8 n_dice;
+ u8 die_erase_opcode;
u32 *vreg_offset;
struct spi_nor_hwcaps hwcaps;