From: Ahmed Naseef Date: Wed, 31 Dec 2025 09:58:22 +0000 (+0400) Subject: econet: spi: sync spi-airoha-snfi patches from airoha target X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0b035903fb177b868fd28c89ba2d5ab527a7ee6c;p=thirdparty%2Fopenwrt.git econet: spi: sync spi-airoha-snfi patches from airoha target Copy upstream v6.19 spi-airoha-snfi driver patches from target/linux/airoha/patches-6.12 for the EN7528 subtarget. Signed-off-by: Ahmed Naseef Link: https://github.com/openwrt/openwrt/pull/21326 Signed-off-by: Hauke Mehrtens --- diff --git a/target/linux/econet/patches-6.12/029-05-v6.19-spi-airoha-remove-unnecessary-restriction-length.patch b/target/linux/econet/patches-6.12/029-05-v6.19-spi-airoha-remove-unnecessary-restriction-length.patch new file mode 100644 index 00000000000..c99c25921c7 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-05-v6.19-spi-airoha-remove-unnecessary-restriction-length.patch @@ -0,0 +1,33 @@ +From 661856ca131c8bf6724905966e02149805660abe Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:16:53 +0300 +Subject: [PATCH 05/14] spi: airoha: remove unnecessary restriction length + +The "length < 160" restriction is not needed because airoha_snand_write_data() +and airoha_snand_read_data() will properly handle data transfers above +SPI_MAX_TRANSFER_SIZE. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-3-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 7 ------- + 1 file changed, 7 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -619,13 +619,6 @@ static int airoha_snand_adjust_op_size(s + + if (op->data.nbytes > max_len) + op->data.nbytes = max_len; +- } else { +- max_len = 1 + op->addr.nbytes + op->dummy.nbytes; +- if (max_len >= 160) +- return -EOPNOTSUPP; +- +- if (op->data.nbytes > 160 - max_len) +- op->data.nbytes = 160 - max_len; + } + + return 0; diff --git a/target/linux/econet/patches-6.12/029-06-v6.19-spi-airoha-remove-unnecessary-switch-to-non-dma-mode.patch b/target/linux/econet/patches-6.12/029-06-v6.19-spi-airoha-remove-unnecessary-switch-to-non-dma-mode.patch new file mode 100644 index 00000000000..afe496c968f --- /dev/null +++ b/target/linux/econet/patches-6.12/029-06-v6.19-spi-airoha-remove-unnecessary-switch-to-non-dma-mode.patch @@ -0,0 +1,30 @@ +From 7350f8dc15bfbb7abf1ce4babea6fcace1c574c5 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:16:55 +0300 +Subject: [PATCH 06/14] spi: airoha: remove unnecessary switch to non-dma mode + +The code switches to dma at the start of dirmap operation and returns +to non-dma at the end of dirmap operation, so an additional switch to +non-dma at the start of dirmap write is not required. + +Signed-off-by: Mikhail Kshevetskiy +Acked-by: Lorenzo Bianconi +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-5-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -815,9 +815,6 @@ static ssize_t airoha_snand_dirmap_write + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); +- err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); +- if (err < 0) +- return err; + + memcpy(txrx_buf + offs, buf, len); + dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, diff --git a/target/linux/econet/patches-6.12/029-07-v6.19-spi-airoha-unify-dirmap-read-write-code.patch b/target/linux/econet/patches-6.12/029-07-v6.19-spi-airoha-unify-dirmap-read-write-code.patch new file mode 100644 index 00000000000..c85c6861fc2 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-07-v6.19-spi-airoha-unify-dirmap-read-write-code.patch @@ -0,0 +1,137 @@ +From 233a22687411ea053a4b169c07324ee6aa33bf38 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:16:58 +0300 +Subject: [PATCH 07/14] spi: airoha: unify dirmap read/write code + +Makes dirmap writing looks similar to dirmap reading. Just a minor +refactoring, no behavior change is expected. + +Signed-off-by: Mikhail Kshevetskiy +Link: https://patch.msgid.link/20251012121707.2296160-8-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 50 ++++++++++++++++++++++------------- + 1 file changed, 32 insertions(+), 18 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -672,6 +672,8 @@ static ssize_t airoha_snand_dirmap_read( + u32 val, rd_mode; + int err; + ++ as_ctrl = spi_controller_get_devdata(spi->controller); ++ + switch (op->cmd.opcode) { + case SPI_NAND_OP_READ_FROM_CACHE_DUAL: + rd_mode = 1; +@@ -684,7 +686,6 @@ static ssize_t airoha_snand_dirmap_read( + break; + } + +- as_ctrl = spi_controller_get_devdata(spi->controller); + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); + if (err < 0) + return err; +@@ -748,7 +749,7 @@ static ssize_t airoha_snand_dirmap_read( + if (err) + goto error_dma_unmap; + +- /* trigger dma start read */ ++ /* trigger dma reading */ + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_RD_TRIG); + if (err) +@@ -806,37 +807,47 @@ error_dma_mode_off: + static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, const void *buf) + { +- struct spi_mem_op *op = &desc->info.op_tmpl; + struct spi_device *spi = desc->mem->spi; + u8 *txrx_buf = spi_get_ctldata(spi); + struct airoha_snand_ctrl *as_ctrl; + dma_addr_t dma_addr; +- u32 wr_mode, val; ++ u32 wr_mode, val, opcode; + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); + ++ opcode = desc->info.op_tmpl.cmd.opcode; ++ switch (opcode) { ++ case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: ++ case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE: ++ wr_mode = 0; ++ break; ++ case SPI_NAND_OP_PROGRAM_LOAD_QUAD: ++ case SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD: ++ wr_mode = 2; ++ break; ++ default: ++ /* unknown opcode */ ++ return -EOPNOTSUPP; ++ } ++ + memcpy(txrx_buf + offs, buf, len); +- dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, +- DMA_TO_DEVICE); +- err = dma_mapping_error(as_ctrl->dev, dma_addr); +- if (err) +- return err; + + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); + if (err < 0) +- goto error_dma_unmap; ++ return err; + + err = airoha_snand_nfi_config(as_ctrl); + if (err) +- goto error_dma_unmap; ++ goto error_dma_mode_off; + +- if (op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_QUAD || +- op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD) +- wr_mode = BIT(1); +- else +- wr_mode = 0; ++ dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, ++ DMA_TO_DEVICE); ++ err = dma_mapping_error(as_ctrl->dev, dma_addr); ++ if (err) ++ goto error_dma_mode_off; + ++ /* set dma addr */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, + dma_addr); + if (err) +@@ -850,12 +861,13 @@ static ssize_t airoha_snand_dirmap_write + if (err) + goto error_dma_unmap; + ++ /* set write command */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1, +- FIELD_PREP(SPI_NFI_PG_LOAD_CMD, +- op->cmd.opcode)); ++ FIELD_PREP(SPI_NFI_PG_LOAD_CMD, opcode)); + if (err) + goto error_dma_unmap; + ++ /* set write mode */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, + FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode)); + if (err) +@@ -887,6 +899,7 @@ static ssize_t airoha_snand_dirmap_write + if (err) + goto error_dma_unmap; + ++ /* trigger dma writing */ + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_WR_TRIG); + if (err) +@@ -931,6 +944,7 @@ static ssize_t airoha_snand_dirmap_write + error_dma_unmap: + dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); ++error_dma_mode_off: + airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); + return err; + } diff --git a/target/linux/econet/patches-6.12/029-08-v6.19-spi-airoha-support-of-dualio-quadio-flash-reading-co.patch b/target/linux/econet/patches-6.12/029-08-v6.19-spi-airoha-support-of-dualio-quadio-flash-reading-co.patch new file mode 100644 index 00000000000..7e3fcb47647 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-08-v6.19-spi-airoha-support-of-dualio-quadio-flash-reading-co.patch @@ -0,0 +1,94 @@ +From 80b09137aeab27e59004383058f8cc696a9ee048 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:16:59 +0300 +Subject: [PATCH 08/14] spi: airoha: support of dualio/quadio flash reading + commands + +Airoha snfi spi controller supports acceleration of DUAL/QUAD +operations, but does not supports DUAL_IO/QUAD_IO operations. +Luckily DUAL/QUAD operations do the same as DUAL_IO/QUAD_IO ones, +so we can issue corresponding DUAL/QUAD operation instead of +DUAL_IO/QUAD_IO one. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-9-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 28 ++++++++++++++++++++++------ + 1 file changed, 22 insertions(+), 6 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -147,6 +147,8 @@ + #define SPI_NFI_CUS_SEC_SIZE_EN BIT(16) + + #define REG_SPI_NFI_RD_CTL2 0x0510 ++#define SPI_NFI_DATA_READ_CMD GENMASK(7, 0) ++ + #define REG_SPI_NFI_RD_CTL3 0x0514 + + #define REG_SPI_NFI_PG_CTL1 0x0524 +@@ -179,7 +181,9 @@ + #define SPI_NAND_OP_READ_FROM_CACHE_SINGLE 0x03 + #define SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST 0x0b + #define SPI_NAND_OP_READ_FROM_CACHE_DUAL 0x3b ++#define SPI_NAND_OP_READ_FROM_CACHE_DUALIO 0xbb + #define SPI_NAND_OP_READ_FROM_CACHE_QUAD 0x6b ++#define SPI_NAND_OP_READ_FROM_CACHE_QUADIO 0xeb + #define SPI_NAND_OP_WRITE_ENABLE 0x06 + #define SPI_NAND_OP_WRITE_DISABLE 0x04 + #define SPI_NAND_OP_PROGRAM_LOAD_SINGLE 0x02 +@@ -664,26 +668,38 @@ static int airoha_snand_dirmap_create(st + static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, void *buf) + { +- struct spi_mem_op *op = &desc->info.op_tmpl; + struct spi_device *spi = desc->mem->spi; + struct airoha_snand_ctrl *as_ctrl; + u8 *txrx_buf = spi_get_ctldata(spi); + dma_addr_t dma_addr; +- u32 val, rd_mode; ++ u32 val, rd_mode, opcode; + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); + +- switch (op->cmd.opcode) { ++ /* ++ * DUALIO and QUADIO opcodes are not supported by the spi controller, ++ * replace them with supported opcodes. ++ */ ++ opcode = desc->info.op_tmpl.cmd.opcode; ++ switch (opcode) { ++ case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: ++ case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST: ++ rd_mode = 0; ++ break; + case SPI_NAND_OP_READ_FROM_CACHE_DUAL: ++ case SPI_NAND_OP_READ_FROM_CACHE_DUALIO: ++ opcode = SPI_NAND_OP_READ_FROM_CACHE_DUAL; + rd_mode = 1; + break; + case SPI_NAND_OP_READ_FROM_CACHE_QUAD: ++ case SPI_NAND_OP_READ_FROM_CACHE_QUADIO: ++ opcode = SPI_NAND_OP_READ_FROM_CACHE_QUAD; + rd_mode = 2; + break; + default: +- rd_mode = 0; +- break; ++ /* unknown opcode */ ++ return -EOPNOTSUPP; + } + + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); +@@ -717,7 +733,7 @@ static ssize_t airoha_snand_dirmap_read( + + /* set read command */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2, +- op->cmd.opcode); ++ FIELD_PREP(SPI_NFI_DATA_READ_CMD, opcode)); + if (err) + goto error_dma_unmap; + diff --git a/target/linux/econet/patches-6.12/029-09-v6.19-spi-airoha-avoid-setting-of-page-oob-sizes-in-REG_SP.patch b/target/linux/econet/patches-6.12/029-09-v6.19-spi-airoha-avoid-setting-of-page-oob-sizes-in-REG_SP.patch new file mode 100644 index 00000000000..f8902f7e575 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-09-v6.19-spi-airoha-avoid-setting-of-page-oob-sizes-in-REG_SP.patch @@ -0,0 +1,64 @@ +From 70eec454f2d6cdfab547c262781acd38328e11a1 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:17:00 +0300 +Subject: [PATCH 09/14] spi: airoha: avoid setting of page/oob sizes in + REG_SPI_NFI_PAGEFMT + +spi-airoha-snfi uses custom sector size in REG_SPI_NFI_SECCUS_SIZE +register, so setting of page/oob sizes in REG_SPI_NFI_PAGEFMT is not +required. + +Signed-off-by: Mikhail Kshevetskiy +Link: https://patch.msgid.link/20251012121707.2296160-10-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 38 ----------------------------------- + 1 file changed, 38 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -518,44 +518,6 @@ static int airoha_snand_nfi_config(struc + if (err) + return err; + +- /* page format */ +- switch (as_ctrl->nfi_cfg.spare_size) { +- case 26: +- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x1); +- break; +- case 27: +- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x2); +- break; +- case 28: +- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x3); +- break; +- default: +- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x0); +- break; +- } +- +- err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT, +- SPI_NFI_SPARE_SIZE, val); +- if (err) +- return err; +- +- switch (as_ctrl->nfi_cfg.page_size) { +- case 2048: +- val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x1); +- break; +- case 4096: +- val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x2); +- break; +- default: +- val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x0); +- break; +- } +- +- err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT, +- SPI_NFI_PAGE_SIZE, val); +- if (err) +- return err; +- + /* sec num */ + val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, diff --git a/target/linux/econet/patches-6.12/029-10-v6.19-spi-airoha-reduce-the-number-of-modification-of-REG_.patch b/target/linux/econet/patches-6.12/029-10-v6.19-spi-airoha-reduce-the-number-of-modification-of-REG_.patch new file mode 100644 index 00000000000..40e2f6ea218 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-10-v6.19-spi-airoha-reduce-the-number-of-modification-of-REG_.patch @@ -0,0 +1,199 @@ +From d1ff30df1d9a4eb4c067795abb5e2a66910fd108 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:17:01 +0300 +Subject: [PATCH 10/14] spi: airoha: reduce the number of modification of + REG_SPI_NFI_CNFG and REG_SPI_NFI_SECCUS_SIZE registers + +This just reduce the number of modification of REG_SPI_NFI_CNFG and +REG_SPI_NFI_SECCUS_SIZE registers during dirmap operation. + +This patch is a necessary step to avoid reading flash page settings +from SNFI registers during driver startup. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-11-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 135 +++++++++++++++++++++++++--------- + 1 file changed, 102 insertions(+), 33 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -668,7 +668,48 @@ static ssize_t airoha_snand_dirmap_read( + if (err < 0) + return err; + +- err = airoha_snand_nfi_config(as_ctrl); ++ /* NFI reset */ ++ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, ++ SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* NFI configure: ++ * - No AutoFDM (custom sector size (SECCUS) register will be used) ++ * - No SoC's hardware ECC (flash internal ECC will be used) ++ * - Use burst mode (faster, but requires 16 byte alignment for addresses) ++ * - Setup for reading (SPI_NFI_READ_MODE) ++ * - Setup reading command: FIELD_PREP(SPI_NFI_OPMODE, 6) ++ * - Use DMA instead of PIO for data reading ++ */ ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, ++ SPI_NFI_DMA_MODE | ++ SPI_NFI_READ_MODE | ++ SPI_NFI_DMA_BURST_EN | ++ SPI_NFI_HW_ECC_EN | ++ SPI_NFI_AUTO_FDM_EN | ++ SPI_NFI_OPMODE, ++ SPI_NFI_DMA_MODE | ++ SPI_NFI_READ_MODE | ++ SPI_NFI_DMA_BURST_EN | ++ FIELD_PREP(SPI_NFI_OPMODE, 6)); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* Set number of sector will be read */ ++ val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, ++ SPI_NFI_SEC_NUM, val); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* Set custom sector size */ ++ val = as_ctrl->nfi_cfg.sec_size; ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, ++ SPI_NFI_CUS_SEC_SIZE | ++ SPI_NFI_CUS_SEC_SIZE_EN, ++ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, val) | ++ SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; + +@@ -684,7 +725,14 @@ static ssize_t airoha_snand_dirmap_read( + if (err) + goto error_dma_unmap; + +- /* set cust sec size */ ++ /* ++ * Setup transfer length ++ * --------------------- ++ * The following rule MUST be met: ++ * transfer_length = ++ * = NFI_SNF_MISC_CTL2.read_data_byte_number = ++ * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size ++ */ + val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; + val = FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, val); + err = regmap_update_bits(as_ctrl->regmap_nfi, +@@ -711,18 +759,6 @@ static ssize_t airoha_snand_dirmap_read( + if (err) + goto error_dma_unmap; + +- /* set nfi read */ +- err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_OPMODE, +- FIELD_PREP(SPI_NFI_OPMODE, 6)); +- if (err) +- goto error_dma_unmap; +- +- err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_READ_MODE | SPI_NFI_DMA_MODE); +- if (err) +- goto error_dma_unmap; +- + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x0); + if (err) + goto error_dma_unmap; +@@ -815,7 +851,48 @@ static ssize_t airoha_snand_dirmap_write + if (err < 0) + return err; + +- err = airoha_snand_nfi_config(as_ctrl); ++ /* NFI reset */ ++ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, ++ SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* ++ * NFI configure: ++ * - No AutoFDM (custom sector size (SECCUS) register will be used) ++ * - No SoC's hardware ECC (flash internal ECC will be used) ++ * - Use burst mode (faster, but requires 16 byte alignment for addresses) ++ * - Setup for writing (SPI_NFI_READ_MODE bit is cleared) ++ * - Setup writing command: FIELD_PREP(SPI_NFI_OPMODE, 3) ++ * - Use DMA instead of PIO for data writing ++ */ ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, ++ SPI_NFI_DMA_MODE | ++ SPI_NFI_READ_MODE | ++ SPI_NFI_DMA_BURST_EN | ++ SPI_NFI_HW_ECC_EN | ++ SPI_NFI_AUTO_FDM_EN | ++ SPI_NFI_OPMODE, ++ SPI_NFI_DMA_MODE | ++ SPI_NFI_DMA_BURST_EN | ++ FIELD_PREP(SPI_NFI_OPMODE, 3)); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* Set number of sector will be written */ ++ val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, ++ SPI_NFI_SEC_NUM, val); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* Set custom sector size */ ++ val = as_ctrl->nfi_cfg.sec_size; ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, ++ SPI_NFI_CUS_SEC_SIZE | ++ SPI_NFI_CUS_SEC_SIZE_EN, ++ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, val) | ++ SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; + +@@ -831,8 +908,16 @@ static ssize_t airoha_snand_dirmap_write + if (err) + goto error_dma_unmap; + +- val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, +- as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); ++ /* ++ * Setup transfer length ++ * --------------------- ++ * The following rule MUST be met: ++ * transfer_length = ++ * = NFI_SNF_MISC_CTL2.write_data_byte_number = ++ * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size ++ */ ++ val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; ++ val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, val); + err = regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, + SPI_NFI_PROG_LOAD_BYTE_NUM, val); +@@ -857,22 +942,6 @@ static ssize_t airoha_snand_dirmap_write + if (err) + goto error_dma_unmap; + +- err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_READ_MODE); +- if (err) +- goto error_dma_unmap; +- +- err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_OPMODE, +- FIELD_PREP(SPI_NFI_OPMODE, 3)); +- if (err) +- goto error_dma_unmap; +- +- err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_DMA_MODE); +- if (err) +- goto error_dma_unmap; +- + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x80); + if (err) + goto error_dma_unmap; diff --git a/target/linux/econet/patches-6.12/029-11-v6.19-spi-airoha-set-custom-sector-size-equal-to-flash-pag.patch b/target/linux/econet/patches-6.12/029-11-v6.19-spi-airoha-set-custom-sector-size-equal-to-flash-pag.patch new file mode 100644 index 00000000000..514212835ce --- /dev/null +++ b/target/linux/econet/patches-6.12/029-11-v6.19-spi-airoha-set-custom-sector-size-equal-to-flash-pag.patch @@ -0,0 +1,142 @@ +From fb81b5cecb8553e3ca2b45288cf340d43c9c2991 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:17:02 +0300 +Subject: [PATCH 11/14] spi: airoha: set custom sector size equal to flash page + size + +Set custom sector size equal to flash page size including oob. Thus we +will always read a single sector. The maximum custom sector size is +8187, so all possible flash sector sizes are supported. + +This patch is a necessary step to avoid reading flash page settings +from SNFI registers during driver startup. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-12-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 35 +++++++++++++++++++---------------- + 1 file changed, 19 insertions(+), 16 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -519,7 +519,7 @@ static int airoha_snand_nfi_config(struc + return err; + + /* sec num */ +- val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); ++ val = FIELD_PREP(SPI_NFI_SEC_NUM, 1); + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_SEC_NUM, val); + if (err) +@@ -532,7 +532,8 @@ static int airoha_snand_nfi_config(struc + return err; + + /* set cust sec size */ +- val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, as_ctrl->nfi_cfg.sec_size); ++ val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, ++ as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); + return regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE, val); +@@ -635,10 +636,13 @@ static ssize_t airoha_snand_dirmap_read( + u8 *txrx_buf = spi_get_ctldata(spi); + dma_addr_t dma_addr; + u32 val, rd_mode, opcode; ++ size_t bytes; + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); + ++ bytes = as_ctrl->nfi_cfg.sec_num * as_ctrl->nfi_cfg.sec_size; ++ + /* + * DUALIO and QUADIO opcodes are not supported by the spi controller, + * replace them with supported opcodes. +@@ -697,18 +701,17 @@ static ssize_t airoha_snand_dirmap_read( + goto error_dma_mode_off; + + /* Set number of sector will be read */ +- val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, +- SPI_NFI_SEC_NUM, val); ++ SPI_NFI_SEC_NUM, ++ FIELD_PREP(SPI_NFI_SEC_NUM, 1)); + if (err) + goto error_dma_mode_off; + + /* Set custom sector size */ +- val = as_ctrl->nfi_cfg.sec_size; + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE | + SPI_NFI_CUS_SEC_SIZE_EN, +- FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, val) | ++ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) | + SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; +@@ -733,11 +736,10 @@ static ssize_t airoha_snand_dirmap_read( + * = NFI_SNF_MISC_CTL2.read_data_byte_number = + * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size + */ +- val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; +- val = FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, val); + err = regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, +- SPI_NFI_READ_DATA_BYTE_NUM, val); ++ SPI_NFI_READ_DATA_BYTE_NUM, ++ FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, bytes)); + if (err) + goto error_dma_unmap; + +@@ -826,10 +828,13 @@ static ssize_t airoha_snand_dirmap_write + struct airoha_snand_ctrl *as_ctrl; + dma_addr_t dma_addr; + u32 wr_mode, val, opcode; ++ size_t bytes; + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); + ++ bytes = as_ctrl->nfi_cfg.sec_num * as_ctrl->nfi_cfg.sec_size; ++ + opcode = desc->info.op_tmpl.cmd.opcode; + switch (opcode) { + case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: +@@ -880,18 +885,17 @@ static ssize_t airoha_snand_dirmap_write + goto error_dma_mode_off; + + /* Set number of sector will be written */ +- val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, +- SPI_NFI_SEC_NUM, val); ++ SPI_NFI_SEC_NUM, ++ FIELD_PREP(SPI_NFI_SEC_NUM, 1)); + if (err) + goto error_dma_mode_off; + + /* Set custom sector size */ +- val = as_ctrl->nfi_cfg.sec_size; + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE | + SPI_NFI_CUS_SEC_SIZE_EN, +- FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, val) | ++ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) | + SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; +@@ -916,11 +920,10 @@ static ssize_t airoha_snand_dirmap_write + * = NFI_SNF_MISC_CTL2.write_data_byte_number = + * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size + */ +- val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; +- val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, val); + err = regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, +- SPI_NFI_PROG_LOAD_BYTE_NUM, val); ++ SPI_NFI_PROG_LOAD_BYTE_NUM, ++ FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, bytes)); + if (err) + goto error_dma_unmap; + diff --git a/target/linux/econet/patches-6.12/029-12-v6.19-spi-airoha-avoid-reading-flash-page-settings-from-SN.patch b/target/linux/econet/patches-6.12/029-12-v6.19-spi-airoha-avoid-reading-flash-page-settings-from-SN.patch new file mode 100644 index 00000000000..c785ae8d563 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-12-v6.19-spi-airoha-avoid-reading-flash-page-settings-from-SN.patch @@ -0,0 +1,206 @@ +From 902c0ea18a97b1a6eeee5799cb1fd9a79ef9208e Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:17:03 +0300 +Subject: [PATCH 12/14] spi: airoha: avoid reading flash page settings from + SNFI registers during driver startup + +The spinand driver do 3 type of dirmap requests: + * read/write whole flash page without oob + (offs = 0, len = page_size) + * read/write whole flash page including oob + (offs = 0, len = page_size + oob_size) + * read/write oob area only + (offs = page_size, len = oob_size) + +The trick is: + * read/write a single "sector" + * set a custom sector size equal to offs + len. It's a bit safer to + rounded up "sector size" value 64. + * set the transfer length equal to custom sector size + +And it works! + +Thus we can remove a dirty hack that reads flash page settings from +SNFI registers during driver startup. Also airoha_snand_adjust_op_size() +function becomes unnecessary. + +Signed-off-by: Mikhail Kshevetskiy +Link: https://patch.msgid.link/20251012121707.2296160-13-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 115 ++-------------------------------- + 1 file changed, 5 insertions(+), 110 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -223,13 +223,6 @@ struct airoha_snand_ctrl { + struct regmap *regmap_ctrl; + struct regmap *regmap_nfi; + struct clk *spi_clk; +- +- struct { +- size_t page_size; +- size_t sec_size; +- u8 sec_num; +- u8 spare_size; +- } nfi_cfg; + }; + + static int airoha_snand_set_fifo_op(struct airoha_snand_ctrl *as_ctrl, +@@ -490,55 +483,6 @@ static int airoha_snand_nfi_init(struct + SPI_NFI_ALL_IRQ_EN, SPI_NFI_AHB_DONE_EN); + } + +-static int airoha_snand_nfi_config(struct airoha_snand_ctrl *as_ctrl) +-{ +- int err; +- u32 val; +- +- err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, +- SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); +- if (err) +- return err; +- +- /* auto FDM */ +- err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_AUTO_FDM_EN); +- if (err) +- return err; +- +- /* HW ECC */ +- err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_HW_ECC_EN); +- if (err) +- return err; +- +- /* DMA Burst */ +- err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_DMA_BURST_EN); +- if (err) +- return err; +- +- /* sec num */ +- val = FIELD_PREP(SPI_NFI_SEC_NUM, 1); +- err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, +- SPI_NFI_SEC_NUM, val); +- if (err) +- return err; +- +- /* enable cust sec size */ +- err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, +- SPI_NFI_CUS_SEC_SIZE_EN); +- if (err) +- return err; +- +- /* set cust sec size */ +- val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, +- as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); +- return regmap_update_bits(as_ctrl->regmap_nfi, +- REG_SPI_NFI_SECCUS_SIZE, +- SPI_NFI_CUS_SEC_SIZE, val); +-} +- + static bool airoha_snand_is_page_ops(const struct spi_mem_op *op) + { + if (op->addr.nbytes != 2) +@@ -571,26 +515,6 @@ static bool airoha_snand_is_page_ops(con + } + } + +-static int airoha_snand_adjust_op_size(struct spi_mem *mem, +- struct spi_mem_op *op) +-{ +- size_t max_len; +- +- if (airoha_snand_is_page_ops(op)) { +- struct airoha_snand_ctrl *as_ctrl; +- +- as_ctrl = spi_controller_get_devdata(mem->spi->controller); +- max_len = as_ctrl->nfi_cfg.sec_size; +- max_len += as_ctrl->nfi_cfg.spare_size; +- max_len *= as_ctrl->nfi_cfg.sec_num; +- +- if (op->data.nbytes > max_len) +- op->data.nbytes = max_len; +- } +- +- return 0; +-} +- + static bool airoha_snand_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) + { +@@ -641,7 +565,8 @@ static ssize_t airoha_snand_dirmap_read( + + as_ctrl = spi_controller_get_devdata(spi->controller); + +- bytes = as_ctrl->nfi_cfg.sec_num * as_ctrl->nfi_cfg.sec_size; ++ /* minimum oob size is 64 */ ++ bytes = round_up(offs + len, 64); + + /* + * DUALIO and QUADIO opcodes are not supported by the spi controller, +@@ -833,7 +758,8 @@ static ssize_t airoha_snand_dirmap_write + + as_ctrl = spi_controller_get_devdata(spi->controller); + +- bytes = as_ctrl->nfi_cfg.sec_num * as_ctrl->nfi_cfg.sec_size; ++ /* minimum oob size is 64 */ ++ bytes = round_up(offs + len, 64); + + opcode = desc->info.op_tmpl.cmd.opcode; + switch (opcode) { +@@ -1076,7 +1002,6 @@ static int airoha_snand_exec_op(struct s + } + + static const struct spi_controller_mem_ops airoha_snand_mem_ops = { +- .adjust_op_size = airoha_snand_adjust_op_size, + .supports_op = airoha_snand_supports_op, + .exec_op = airoha_snand_exec_op, + .dirmap_create = airoha_snand_dirmap_create, +@@ -1101,36 +1026,6 @@ static int airoha_snand_setup(struct spi + return 0; + } + +-static int airoha_snand_nfi_setup(struct airoha_snand_ctrl *as_ctrl) +-{ +- u32 val, sec_size, sec_num; +- int err; +- +- err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, &val); +- if (err) +- return err; +- +- sec_num = FIELD_GET(SPI_NFI_SEC_NUM, val); +- +- err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, &val); +- if (err) +- return err; +- +- sec_size = FIELD_GET(SPI_NFI_CUS_SEC_SIZE, val); +- +- /* init default value */ +- as_ctrl->nfi_cfg.sec_size = sec_size; +- as_ctrl->nfi_cfg.sec_num = sec_num; +- as_ctrl->nfi_cfg.page_size = round_down(sec_size * sec_num, 1024); +- as_ctrl->nfi_cfg.spare_size = 16; +- +- err = airoha_snand_nfi_init(as_ctrl); +- if (err) +- return err; +- +- return airoha_snand_nfi_config(as_ctrl); +-} +- + static const struct regmap_config spi_ctrl_regmap_config = { + .name = "ctrl", + .reg_bits = 32, +@@ -1204,7 +1099,7 @@ static int airoha_snand_probe(struct pla + ctrl->setup = airoha_snand_setup; + device_set_node(&ctrl->dev, dev_fwnode(dev)); + +- err = airoha_snand_nfi_setup(as_ctrl); ++ err = airoha_snand_nfi_init(as_ctrl); + if (err) + return err; + diff --git a/target/linux/econet/patches-6.12/029-13-v6.19-spi-airoha-buffer-must-be-0xff-ed-before-writing.patch b/target/linux/econet/patches-6.12/029-13-v6.19-spi-airoha-buffer-must-be-0xff-ed-before-writing.patch new file mode 100644 index 00000000000..669f9b2dd43 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-13-v6.19-spi-airoha-buffer-must-be-0xff-ed-before-writing.patch @@ -0,0 +1,32 @@ +From 0743acf746a81e0460a56fd5ff847d97fa7eb370 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:17:04 +0300 +Subject: [PATCH 13/14] spi: airoha: buffer must be 0xff-ed before writing + +During writing, the entire flash page (including OOB) will be updated +with the values from the temporary buffer, so we need to fill the +untouched areas of the buffer with 0xff value to prevent accidental +data overwriting. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-14-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -776,7 +776,11 @@ static ssize_t airoha_snand_dirmap_write + return -EOPNOTSUPP; + } + ++ if (offs > 0) ++ memset(txrx_buf, 0xff, offs); + memcpy(txrx_buf + offs, buf, len); ++ if (bytes > offs + len) ++ memset(txrx_buf + offs + len, 0xff, bytes - offs - len); + + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); + if (err < 0)