[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)),
);