From: Venkatesh Yadav Abbarapu Date: Tue, 2 Jan 2024 12:53:03 +0000 (+0530) Subject: mtd: spi-nor: scale up timeout for full-chip erase X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=948616894c6d3316a5ac8f2a891783e3e7ff3516;p=u-boot.git 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 --- diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index aea611fef5..8f7a77e716 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; }