[PATCH 10/27] mtd: nand: mrvl_nfc: keep the ready latch across a STATUS command

Sascha Hauer s.hauer at pengutronix.de
Sun Aug 16 10:56:30 PDT 2026


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 <s.hauer at pengutronix.de>
---
 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




More information about the barebox mailing list