[openwrt/openwrt] generic: 6.12: backport upstream v6.16 brcmnand patches
LEDE Commits
lede-commits at lists.infradead.org
Tue May 27 02:30:08 PDT 2025
noltari pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/53c723246a153801264b3284c4488ced3fe57abd
commit 53c723246a153801264b3284c4488ced3fe57abd
Author: Álvaro Fernández Rojas <noltari at gmail.com>
AuthorDate: Fri May 23 08:15:42 2025 +0200
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 <noltari at gmail.com>
---
...rawnand-brcmnand-remove-unused-parameters.patch | 88 ++++++
...cmnand-fix-NAND-timeout-when-accessing-eM.patch | 30 +++
...nd-brcmnand-legacy-exec_op-implementation.patch | 299 +++++++++++++++++++++
3 files changed, 417 insertions(+)
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 0000000000..3bc6038711
--- /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?= <noltari at gmail.com>
+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 <noltari at gmail.com>
+Reviewed-by: Florian Fainelli <florian.fainelli at broadcom.com>
+Reviewed-by: William Zhang <william.zhang at broadcom.com>
+Signed-off-by: Miquel Raynal <miquel.raynal at bootlin.com>
+---
+ 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 0000000000..d3dbde8b9e
--- /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 <dregan at broadcom.com>
+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 <dregan at broadcom.com>
+Reviewed-by: William Zhang <william.zhang at broadcom.com>
+Reviewed-by: Florian Fainelli <florian.fainelli at broadcom.com>
+Signed-off-by: Miquel Raynal <miquel.raynal at bootlin.com>
+---
+ 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 0000000000..6c75c2bbf2
--- /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?= <noltari at gmail.com>
+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 <noltari at gmail.com>
+Reviewed-by: David Regan <dregan at broadcom.com>
+Reviewed-by: Florian Fainelli <florian.fainelli at broadcom.com>
+Reviewed-by: William Zhang <william.zhang at broadcom.com>
+Signed-off-by: Miquel Raynal <miquel.raynal at bootlin.com>
+---
+ 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.
More information about the lede-commits
mailing list