[PATCH] mtd: rawnand: pl35x: Fix BBT write operations by adding pure data out pattern

From: Rafal Vonau
Date: Tue Jul 01 2025 - 06:07:35 EST


The PL35x NAND controller driver was failing to write Bad Block Tables
due to missing support for pure data out operations. When the NAND subsystem
attempted to write BBT data using just DATA_OUT commands without preceding
address cycles or commands, the operation parser failed to match any pattern.

This patch:

Adds a dedicated execution function for pure data out operations

Includes a new pattern in the op parser for DATA_OUT only operation

The fix maintains proper separation of concerns where:

Command sequences are handled by nand_prog_page_begin_op/end_op

Data writing is handled by the controller's data out operation

BBT writes now complete successfully

Tested on Xilinx Zynq with Micron MT29F2G08ABBEAH4 NAND flash.

Signed-off-by: Rafal Vonau <rafal.vonau@xxxxxxxxx>
diff --git a/linux/drivers/mtd/nand/raw/pl35x-nand-controller.c b/linux/drivers/mtd/nand/raw/pl35x-nand-controller.c
index 1d3f0261a7..a2e8ba9dc4 100644
--- a/linux/drivers/mtd/nand/raw/pl35x-nand-controller.c
+++ b/linux/drivers/mtd/nand/raw/pl35x-nand-controller.c
@@ -755,6 +755,33 @@ static int pl35x_nand_exec_op(struct nand_chip *chip,
return 0;
}

+
+static int pl35x_nand_exec_data_out_op(struct nand_chip *chip,
+ const struct nand_subop *subop)
+{
+ struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
+ const struct nand_op_instr *instr;
+ unsigned int len, offset;
+
+ if (subop->ninstrs != 1 || subop->instrs[0].type != NAND_OP_DATA_OUT_INSTR) {
+ dev_err(nfc->dev, "Invalid data out operation\n");
+ return -EINVAL;
+ }
+
+ instr = &subop->instrs[0];
+ offset = nand_subop_get_data_start_off(subop, 0);
+ len = nand_subop_get_data_len(subop, 0);
+
+ dev_dbg(nfc->dev, "Executing data out op: len=%u, offset=%u\n", len, offset);
+
+ pl35x_nand_write_data_op(chip, instr->ctx.data.buf.out + offset,
+ len, instr->ctx.data.force_8bit,
+ 0, PL35X_SMC_DATA_PHASE_CLEAR_CS);
+
+ return 0;
+}
+
+
static const struct nand_op_parser pl35x_nandc_op_parser = NAND_OP_PARSER(
NAND_OP_PARSER_PATTERN(pl35x_nand_exec_op,
NAND_OP_PARSER_PAT_CMD_ELEM(true),
@@ -774,6 +801,9 @@ static const struct nand_op_parser pl35x_nandc_op_parser = NAND_OP_PARSER(
NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 2112),
NAND_OP_PARSER_PAT_CMD_ELEM(true),
NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
+ /* Pure data out operation (for BBT writes) */
+ NAND_OP_PARSER_PATTERN(pl35x_nand_exec_data_out_op,
+ NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 2112)),
);