[PATCH 10/27] mtd: nand: mrvl_nfc: keep the ready latch across a STATUS command
Sascha Hauer <[email protected]>
| Newsgroups | org.infradead.lists.barebox |
|---|---|
| Message-ID | <[email protected]> |
Every block erase and every page program took 400ms, so writing a bootloader image to NAND took minutes. That 400ms is nand_wait()'s timeout, hit in full every single time. NDSR's per-chipselect ready bits latch the flash's busy-to-ready transition rather than reporting its current level, and nand_wait() polls them through mrvl_nand_ready() to find out when an erase or a program has finished. It issues a STATUS command before it starts polling, though, and every command clears NDSR on its way through mrvl_nand_start() - so the transition it was about to wait for was gone before it ever looked. It never saw a ready chip, ran its timeout out, and only then fell through to read the status byte. That last read is correct, which is why this showed up as NAND writes being unusably slow rather than as an error. Keep the ready bits across a STATUS command, and go on clearing them for the commands that make the flash busy in the first place, so what nand_wait() observes is that command's own completion. Measured on a Raumfeld speaker (PXA303, 128KiB erase blocks): a block erase goes from 400ms to under a millisecond and a 128KiB write from 25.6s to 28ms. Reads were never affected. Assisted-by: Claude Opus 5 Signed-off-by: Sascha Hauer <[email protected]> --- drivers/mtd/nand/raw/nand_mrvl_nfc.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_mrvl_nfc.c b/drivers/mtd/nand/raw/nand_mrvl_nfc.c index ebb1fd81fb..b1532dbf1b 100644 --- a/drivers/mtd/nand/raw/nand_mrvl_nfc.c +++ b/drivers/mtd/nand/raw/nand_mrvl_nfc.c @@ -472,8 +472,9 @@ static unsigned int mrvl_datasize(struct mrvl_nand_host *host) * We enable all the interrupt at the same time, and * let mrvl_nand_irq to handle all logic. */ -static void mrvl_nand_start(struct mrvl_nand_host *host) +static void mrvl_nand_start(struct mrvl_nand_host *host, unsigned command) { + uint32_t ndsr_clear = NDSR_MASK; uint32_t ndcr; if (host->hwflags & HWFLAGS_ECC_BCH) { @@ -503,9 +504,27 @@ static void mrvl_nand_start(struct mrvl_nand_host *host) ndcr &= ~NDCR_ND_RUN; ndcr |= NDCR_INT_MASK; + /* + * NDSR's per-chipselect ready bits latch the flash's busy-to-ready + * transition, they do not report its current level. nand_wait() polls + * them through mrvl_nand_ready() to find out when an erase or a page + * program has finished - but it issues a STATUS command first, and + * clearing the latch here would wipe the very transition it is about + * to wait for. It would then never see a ready chip and spend its + * full 400ms timeout on every block erase and every page program + * before falling through to read the status byte, which is why this + * only ever showed up as NAND writes being unusably slow rather than + * as an error. + * + * So leave the latch alone for STATUS, and keep clearing it for the + * commands that make the flash busy in the first place. + */ + if (command == NAND_CMD_STATUS) + ndsr_clear &= ~(NDSR_RDY | NDSR_FLASH_RDY); + /* clear status bits and run */ nand_writel(host, NDCR, ndcr); - nand_writel(host, NDSR, NDSR_MASK); + nand_writel(host, NDSR, ndsr_clear); nand_writel(host, NDCR, ndcr | NDCR_ND_RUN); if (wait_on_timeout(host->chip.legacy.chip_delay * USECOND, @@ -817,7 +836,7 @@ static void mrvl_nand_cmdfunc(struct nand_chip *chip, unsigned command, prepare_start_command(host, command); if (prepare_set_command(host, command, 0, column, page_addr)) { - mrvl_nand_start(host); + mrvl_nand_start(host, command); mrvl_data_stage(host); mrvl_nand_wait_cmd_done(host, command); } -- 2.47.3