]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
generic: 6.12: backport upstream v6.16 brcmnand patches 18931/head
authorÁlvaro Fernández Rojas <noltari@gmail.com>
Fri, 23 May 2025 06:15:42 +0000 (08:15 +0200)
committerÁlvaro Fernández Rojas <noltari@gmail.com>
Tue, 27 May 2025 09:29:46 +0000 (11:29 +0200)
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@gmail.com>
target/linux/generic/backport-6.12/420-01-v6.16-mtd-rawnand-brcmnand-remove-unused-parameters.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/420-02-v6.16-mtd-nand-brcmnand-fix-NAND-timeout-when-accessing-eM.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/420-03-v6.16-mtd-rawnand-brcmnand-legacy-exec_op-implementation.patch [new file with mode: 0644]

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 (file)
index 0000000..3bc6038
--- /dev/null
@@ -0,0 +1,88 @@
+From 56fce75470041b5b0d92ae10637416e1a4cceb1b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@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@gmail.com>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Reviewed-by: William Zhang <william.zhang@broadcom.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@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 (file)
index 0000000..d3dbde8
--- /dev/null
@@ -0,0 +1,30 @@
+From 528b541b71cf03e263272b051b70696f92258e9d Mon Sep 17 00:00:00 2001
+From: David Regan <dregan@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@broadcom.com>
+Reviewed-by: William Zhang <william.zhang@broadcom.com>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@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 (file)
index 0000000..6c75c2b
--- /dev/null
@@ -0,0 +1,299 @@
+From 3bfb22cecfe6b6f0d8ee56ef4b533cf68599c5d9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@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@gmail.com>
+Reviewed-by: David Regan <dregan@broadcom.com>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Reviewed-by: William Zhang <william.zhang@broadcom.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@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.