From: Álvaro Fernández Rojas Date: Fri, 23 May 2025 06:15:42 +0000 (+0200) Subject: generic: 6.12: backport upstream v6.16 brcmnand patches X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F18931%2Fhead;p=thirdparty%2Fopenwrt.git generic: 6.12: backport upstream v6.16 brcmnand patches This is needed to restore compatibility with legacy brcmnand controllers. 3bfb22cecfe6 mtd: rawnand: brcmnand: legacy exec_op implementation 528b541b71cf mtd: nand: brcmnand: fix NAND timeout when accessing eMMC 56fce7547004 mtd: rawnand: brcmnand: remove unused parameters Signed-off-by: Álvaro Fernández Rojas --- diff --git a/target/linux/generic/backport-6.12/420-01-v6.16-mtd-rawnand-brcmnand-remove-unused-parameters.patch b/target/linux/generic/backport-6.12/420-01-v6.16-mtd-rawnand-brcmnand-remove-unused-parameters.patch new file mode 100644 index 00000000000..3bc6038711f --- /dev/null +++ b/target/linux/generic/backport-6.12/420-01-v6.16-mtd-rawnand-brcmnand-remove-unused-parameters.patch @@ -0,0 +1,88 @@ +From 56fce75470041b5b0d92ae10637416e1a4cceb1b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Wed, 14 May 2025 08:14:54 +0200 +Subject: [PATCH] mtd: rawnand: brcmnand: remove unused parameters +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +last_cmd and last_byte are now unused brcmnand_host members. +last_addr is only written and never read so we can remove it too. + +Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: Florian Fainelli +Reviewed-by: William Zhang +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/raw/brcmnand/brcmnand.c | 24 ++++++------------------ + 1 file changed, 6 insertions(+), 18 deletions(-) + +--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c ++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +@@ -310,9 +310,6 @@ struct brcmnand_host { + struct platform_device *pdev; + int cs; + +- unsigned int last_cmd; +- unsigned int last_byte; +- u64 last_addr; + struct brcmnand_cfg hwcfg; + struct brcmnand_controller *ctrl; + }; +@@ -2233,14 +2230,11 @@ static int brcmnand_read_page(struct nan + int oob_required, int page) + { + struct mtd_info *mtd = nand_to_mtd(chip); +- struct brcmnand_host *host = nand_get_controller_data(chip); + u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL; + u64 addr = (u64)page << chip->page_shift; + +- host->last_addr = addr; +- +- return brcmnand_read(mtd, chip, host->last_addr, +- mtd->writesize >> FC_SHIFT, (u32 *)buf, oob); ++ return brcmnand_read(mtd, chip, addr, mtd->writesize >> FC_SHIFT, ++ (u32 *)buf, oob); + } + + static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf, +@@ -2252,11 +2246,9 @@ static int brcmnand_read_page_raw(struct + int ret; + u64 addr = (u64)page << chip->page_shift; + +- host->last_addr = addr; +- + brcmnand_set_ecc_enabled(host, 0); +- ret = brcmnand_read(mtd, chip, host->last_addr, +- mtd->writesize >> FC_SHIFT, (u32 *)buf, oob); ++ ret = brcmnand_read(mtd, chip, addr, mtd->writesize >> FC_SHIFT, ++ (u32 *)buf, oob); + brcmnand_set_ecc_enabled(host, 1); + return ret; + } +@@ -2363,13 +2355,10 @@ static int brcmnand_write_page(struct na + int oob_required, int page) + { + struct mtd_info *mtd = nand_to_mtd(chip); +- struct brcmnand_host *host = nand_get_controller_data(chip); + void *oob = oob_required ? chip->oob_poi : NULL; + u64 addr = (u64)page << chip->page_shift; + +- host->last_addr = addr; +- +- return brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob); ++ return brcmnand_write(mtd, chip, addr, (const u32 *)buf, oob); + } + + static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, +@@ -2381,9 +2370,8 @@ static int brcmnand_write_page_raw(struc + u64 addr = (u64)page << chip->page_shift; + int ret = 0; + +- host->last_addr = addr; + brcmnand_set_ecc_enabled(host, 0); +- ret = brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob); ++ ret = brcmnand_write(mtd, chip, addr, (const u32 *)buf, oob); + brcmnand_set_ecc_enabled(host, 1); + + return ret; diff --git a/target/linux/generic/backport-6.12/420-02-v6.16-mtd-nand-brcmnand-fix-NAND-timeout-when-accessing-eM.patch b/target/linux/generic/backport-6.12/420-02-v6.16-mtd-nand-brcmnand-fix-NAND-timeout-when-accessing-eM.patch new file mode 100644 index 00000000000..d3dbde8b9e6 --- /dev/null +++ b/target/linux/generic/backport-6.12/420-02-v6.16-mtd-nand-brcmnand-fix-NAND-timeout-when-accessing-eM.patch @@ -0,0 +1,30 @@ +From 528b541b71cf03e263272b051b70696f92258e9d Mon Sep 17 00:00:00 2001 +From: David Regan +Date: Thu, 22 May 2025 10:25:17 -0700 +Subject: [PATCH] mtd: nand: brcmnand: fix NAND timeout when accessing eMMC + +When booting a board to NAND and accessing NAND while eMMC +transactions are occurring the NAND will sometimes timeout. This +is due to both NAND and eMMC controller sharing the same data bus +on BCMBCA chips. Fix is to extend NAND timeout to allow eMMC +transactions time to complete. + +Signed-off-by: David Regan +Reviewed-by: William Zhang +Reviewed-by: Florian Fainelli +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/raw/brcmnand/brcmnand.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c ++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +@@ -101,7 +101,7 @@ struct brcm_nand_dma_desc { + #define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024) + + #define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY) +-#define NAND_POLL_STATUS_TIMEOUT_MS 100 ++#define NAND_POLL_STATUS_TIMEOUT_MS 500 + + #define EDU_CMD_WRITE 0x00 + #define EDU_CMD_READ 0x01 diff --git a/target/linux/generic/backport-6.12/420-03-v6.16-mtd-rawnand-brcmnand-legacy-exec_op-implementation.patch b/target/linux/generic/backport-6.12/420-03-v6.16-mtd-rawnand-brcmnand-legacy-exec_op-implementation.patch new file mode 100644 index 00000000000..6c75c2bbf2a --- /dev/null +++ b/target/linux/generic/backport-6.12/420-03-v6.16-mtd-rawnand-brcmnand-legacy-exec_op-implementation.patch @@ -0,0 +1,299 @@ +From 3bfb22cecfe6b6f0d8ee56ef4b533cf68599c5d9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Wed, 21 May 2025 10:03:25 +0200 +Subject: [PATCH] mtd: rawnand: brcmnand: legacy exec_op implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 3c8260ce7663 ("mtd: rawnand: brcmnand: exec_op implementation") +removed legacy interface functions, breaking < v5.0 controllers support. +In order to fix older controllers we need to add an alternative exec_op +implementation which doesn't rely on low level registers. + +Fixes: 3c8260ce7663 ("mtd: rawnand: brcmnand: exec_op implementation") +Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: David Regan +Reviewed-by: Florian Fainelli +Reviewed-by: William Zhang +Signed-off-by: Miquel Raynal +--- + drivers/mtd/nand/raw/brcmnand/brcmnand.c | 222 ++++++++++++++++++++++- + 1 file changed, 215 insertions(+), 7 deletions(-) + +--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c ++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +@@ -65,6 +65,7 @@ module_param(wp_on, int, 0444); + #define CMD_PARAMETER_READ 0x0e + #define CMD_PARAMETER_CHANGE_COL 0x0f + #define CMD_LOW_LEVEL_OP 0x10 ++#define CMD_NOT_SUPPORTED 0xff + + struct brcm_nand_dma_desc { + u32 next_desc; +@@ -199,6 +200,30 @@ static const u16 flash_dma_regs_v4[] = { + [FLASH_DMA_CURRENT_DESC_EXT] = 0x34, + }; + ++/* Native command conversion for legacy controllers (< v5.0) */ ++static const u8 native_cmd_conv[] = { ++ [NAND_CMD_READ0] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READ1] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_RNDOUT] = CMD_PARAMETER_CHANGE_COL, ++ [NAND_CMD_PAGEPROG] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READOOB] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_ERASE1] = CMD_BLOCK_ERASE, ++ [NAND_CMD_STATUS] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_SEQIN] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_RNDIN] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READID] = CMD_DEVICE_ID_READ, ++ [NAND_CMD_ERASE2] = CMD_NULL, ++ [NAND_CMD_PARAM] = CMD_PARAMETER_READ, ++ [NAND_CMD_GET_FEATURES] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_SET_FEATURES] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_RESET] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READSTART] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READCACHESEQ] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_READCACHEEND] = CMD_NOT_SUPPORTED, ++ [NAND_CMD_RNDOUTSTART] = CMD_NULL, ++ [NAND_CMD_CACHEDPROG] = CMD_NOT_SUPPORTED, ++}; ++ + /* Controller feature flags */ + enum { + BRCMNAND_HAS_1K_SECTORS = BIT(0), +@@ -237,6 +262,12 @@ struct brcmnand_controller { + /* List of NAND hosts (one for each chip-select) */ + struct list_head host_list; + ++ /* Functions to be called from exec_op */ ++ int (*check_instr)(struct nand_chip *chip, ++ const struct nand_operation *op); ++ int (*exec_instr)(struct nand_chip *chip, ++ const struct nand_operation *op); ++ + /* EDU info, per-transaction */ + const u16 *edu_offsets; + void __iomem *edu_base; +@@ -2478,18 +2509,190 @@ static int brcmnand_op_is_reset(const st + return 0; + } + ++static int brcmnand_check_instructions(struct nand_chip *chip, ++ const struct nand_operation *op) ++{ ++ return 0; ++} ++ ++static int brcmnand_exec_instructions(struct nand_chip *chip, ++ const struct nand_operation *op) ++{ ++ struct brcmnand_host *host = nand_get_controller_data(chip); ++ unsigned int i; ++ int ret = 0; ++ ++ for (i = 0; i < op->ninstrs; i++) { ++ ret = brcmnand_exec_instr(host, i, op); ++ if (ret) ++ break; ++ } ++ ++ return ret; ++} ++ ++static int brcmnand_check_instructions_legacy(struct nand_chip *chip, ++ const struct nand_operation *op) ++{ ++ const struct nand_op_instr *instr; ++ unsigned int i; ++ u8 cmd; ++ ++ for (i = 0; i < op->ninstrs; i++) { ++ instr = &op->instrs[i]; ++ ++ switch (instr->type) { ++ case NAND_OP_CMD_INSTR: ++ cmd = native_cmd_conv[instr->ctx.cmd.opcode]; ++ if (cmd == CMD_NOT_SUPPORTED) ++ return -EOPNOTSUPP; ++ break; ++ case NAND_OP_ADDR_INSTR: ++ case NAND_OP_DATA_IN_INSTR: ++ case NAND_OP_WAITRDY_INSTR: ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ return 0; ++} ++ ++static int brcmnand_exec_instructions_legacy(struct nand_chip *chip, ++ const struct nand_operation *op) ++{ ++ struct mtd_info *mtd = nand_to_mtd(chip); ++ struct brcmnand_host *host = nand_get_controller_data(chip); ++ struct brcmnand_controller *ctrl = host->ctrl; ++ const struct nand_op_instr *instr; ++ unsigned int i, j; ++ u8 cmd = CMD_NULL, last_cmd = CMD_NULL; ++ int ret = 0; ++ u64 last_addr; ++ ++ for (i = 0; i < op->ninstrs; i++) { ++ instr = &op->instrs[i]; ++ ++ if (instr->type == NAND_OP_CMD_INSTR) { ++ cmd = native_cmd_conv[instr->ctx.cmd.opcode]; ++ if (cmd == CMD_NOT_SUPPORTED) { ++ dev_err(ctrl->dev, "unsupported cmd=%d\n", ++ instr->ctx.cmd.opcode); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ } else if (instr->type == NAND_OP_ADDR_INSTR) { ++ u64 addr = 0; ++ ++ if (cmd == CMD_NULL) ++ continue; ++ ++ if (instr->ctx.addr.naddrs > 8) { ++ dev_err(ctrl->dev, "unsupported naddrs=%u\n", ++ instr->ctx.addr.naddrs); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ for (j = 0; j < instr->ctx.addr.naddrs; j++) ++ addr |= (instr->ctx.addr.addrs[j]) << (j << 3); ++ ++ if (cmd == CMD_BLOCK_ERASE) ++ addr <<= chip->page_shift; ++ else if (cmd == CMD_PARAMETER_CHANGE_COL) ++ addr &= ~((u64)(FC_BYTES - 1)); ++ ++ brcmnand_set_cmd_addr(mtd, addr); ++ brcmnand_send_cmd(host, cmd); ++ last_addr = addr; ++ last_cmd = cmd; ++ cmd = CMD_NULL; ++ brcmnand_waitfunc(chip); ++ ++ if (last_cmd == CMD_PARAMETER_READ || ++ last_cmd == CMD_PARAMETER_CHANGE_COL) { ++ /* Copy flash cache word-wise */ ++ u32 *flash_cache = (u32 *)ctrl->flash_cache; ++ ++ brcmnand_soc_data_bus_prepare(ctrl->soc, true); ++ ++ /* ++ * Must cache the FLASH_CACHE now, since changes in ++ * SECTOR_SIZE_1K may invalidate it ++ */ ++ for (j = 0; j < FC_WORDS; j++) ++ /* ++ * Flash cache is big endian for parameter pages, at ++ * least on STB SoCs ++ */ ++ flash_cache[j] = be32_to_cpu(brcmnand_read_fc(ctrl, j)); ++ ++ brcmnand_soc_data_bus_unprepare(ctrl->soc, true); ++ } ++ } else if (instr->type == NAND_OP_DATA_IN_INSTR) { ++ u8 *in = instr->ctx.data.buf.in; ++ ++ if (last_cmd == CMD_DEVICE_ID_READ) { ++ u32 val; ++ ++ if (instr->ctx.data.len > 8) { ++ dev_err(ctrl->dev, "unsupported len=%u\n", ++ instr->ctx.data.len); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ for (j = 0; j < instr->ctx.data.len; j++) { ++ if (j == 0) ++ val = brcmnand_read_reg(ctrl, BRCMNAND_ID); ++ else if (j == 4) ++ val = brcmnand_read_reg(ctrl, BRCMNAND_ID_EXT); ++ ++ in[j] = (val >> (24 - ((j % 4) << 3))) & 0xff; ++ } ++ } else if (last_cmd == CMD_PARAMETER_READ || ++ last_cmd == CMD_PARAMETER_CHANGE_COL) { ++ u64 addr; ++ u32 offs; ++ ++ for (j = 0; j < instr->ctx.data.len; j++) { ++ addr = last_addr + j; ++ offs = addr & (FC_BYTES - 1); ++ ++ if (j > 0 && offs == 0) ++ nand_change_read_column_op(chip, addr, NULL, 0, ++ false); ++ ++ in[j] = ctrl->flash_cache[offs]; ++ } ++ } ++ } else if (instr->type == NAND_OP_WAITRDY_INSTR) { ++ ret = bcmnand_ctrl_poll_status(host, NAND_CTRL_RDY, NAND_CTRL_RDY, 0); ++ if (ret) ++ break; ++ } else { ++ dev_err(ctrl->dev, "unsupported instruction type: %d\n", instr->type); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ + static int brcmnand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) + { + struct brcmnand_host *host = nand_get_controller_data(chip); ++ struct brcmnand_controller *ctrl = host->ctrl; + struct mtd_info *mtd = nand_to_mtd(chip); + u8 *status; +- unsigned int i; + int ret = 0; + + if (check_only) +- return 0; ++ return ctrl->check_instr(chip, op); + + if (brcmnand_op_is_status(op)) { + status = op->instrs[1].ctx.data.buf.in; +@@ -2513,11 +2716,7 @@ static int brcmnand_exec_op(struct nand_ + if (op->deassert_wp) + brcmnand_wp(mtd, 0); + +- for (i = 0; i < op->ninstrs; i++) { +- ret = brcmnand_exec_instr(host, i, op); +- if (ret) +- break; +- } ++ ret = ctrl->exec_instr(chip, op); + + if (op->deassert_wp) + brcmnand_wp(mtd, 1); +@@ -3130,6 +3329,15 @@ int brcmnand_probe(struct platform_devic + if (ret) + goto err; + ++ /* Only v5.0+ controllers have low level ops support */ ++ if (ctrl->nand_version >= 0x0500) { ++ ctrl->check_instr = brcmnand_check_instructions; ++ ctrl->exec_instr = brcmnand_exec_instructions; ++ } else { ++ ctrl->check_instr = brcmnand_check_instructions_legacy; ++ ctrl->exec_instr = brcmnand_exec_instructions_legacy; ++ } ++ + /* + * Most chips have this cache at a fixed offset within 'nand' block. + * Some must specify this region separately.