diff options
| author | Venkatesh Yadav Abbarapu <[email protected]> | 2024-01-02 18:23:03 +0530 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2024-09-19 16:42:31 -0600 |
| commit | 948616894c6d3316a5ac8f2a891783e3e7ff3516 (patch) | |
| tree | 0572db69576f28928bb52da3dca7197eb1f94133 | |
| parent | 146be6f0362e16b112e72bdbb5c2d359dc65c890 (diff) | |
mtd: spi-nor: scale up timeout for full-chip erase
This patch fixes timeout issues seen on large NOR flash.
For full-chip erase, where we use the SPINOR_OP_CHIP_ERASE (0xc7)
opcode. Use a different timeout for full-chip erase than for other
commands.
[Ported from Linux kernel commit
09b6a377687b ("mtd: spi-nor: scale up timeout for
full-chip erase") ]
Signed-off-by: Venkatesh Yadav Abbarapu <[email protected]>
| -rw-r--r-- | drivers/mtd/spi/spi-nor-core.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index aea611fef52..8f7a77e7169 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -44,6 +44,12 @@ #define DEFAULT_READY_WAIT_JIFFIES (40UL * HZ) +/* + * For full-chip erase, calibrated to a 2MB flash (M25P16); should be scaled up + * for larger flash + */ +#define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ) + #define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) struct sfdp_parameter_header { @@ -855,6 +861,20 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor) DEFAULT_READY_WAIT_JIFFIES); } +static int spi_nor_erase_chip_wait_till_ready(struct spi_nor *nor, unsigned long size) +{ + /* + * 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. + */ + unsigned long timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES, + CHIP_ERASE_2MB_READY_WAIT_JIFFIES * + (unsigned long)(size / SZ_2M)); + return spi_nor_wait_till_ready_with_timeout(nor, timeout); +} + #ifdef CONFIG_SPI_FLASH_BAR /* * This "clean_bar" is necessary in a situation when one was accessing @@ -989,7 +1009,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) { struct spi_nor *nor = mtd_to_spi_nor(mtd); bool addr_known = false; - u32 addr, len, rem; + u32 addr, len, rem, max_size; int ret, err; dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, @@ -1003,6 +1023,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) addr = instr->addr; len = instr->len; + max_size = instr->len; instr->state = MTD_ERASING; addr_known = true; @@ -1035,7 +1056,13 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) addr += ret; len -= ret; - ret = spi_nor_wait_till_ready(nor); + if (max_size == mtd->size && + !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) { + ret = spi_nor_erase_chip_wait_till_ready(nor, mtd->size); + } else { + ret = spi_nor_wait_till_ready(nor); + } + if (ret) goto erase_err; } |
