* [PATCH 00/13] spi: airoha: driver fixes & improvements
@ 2025-08-14 23:11 Mikhail Kshevetskiy
2025-08-14 23:11 ` [PATCH 01/13] spi: airoha: remove unnecessary restriction length Mikhail Kshevetskiy
` (12 more replies)
0 siblings, 13 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:11 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
This patch series greatly improve airoha snfi driver and fix a
number of serious bug.
Fixed bugs:
* fix reading/writing of flashes with more than one plane per lun
* fix inability to read/write oob area
* fill the buffer with 0xff before writing
* fix error paths
Improvements:
* add support of dual/quad wires spi modes in exec_op()
* support of dualio/quadio flash reading commands
* remove dirty hack that reads flash page settings from SNFI registers
during driver startup
Unfortunately I am unable to test the driver with linux at the moment,
so only the following testing was done:
* Driver compiles without error.
* All changes were tested with corresponding u-boot driver. U-Boot
SpiNAND driver was modified as well to matck linux-6.17-rc1.
Mikhail Kshevetskiy (13):
spi: airoha: remove unnecessary restriction length
spi: airoha: add support of dual/quad wires spi modes
spi: airoha: remove unnecessary switch to non-dma mode
spi: airoha: unify dirmap read/write code
spi: airoha: switch back to non-dma mode in the case of error
spi: airoha: fix reading/writing of flashes with more than one plane
per lun
spi: airoha: support of dualio/quadio flash reading commands
spi: airoha: allow reading/writing of oob area
spi: airoha: buffer must be 0xff-ed before writing
spi: airoha: avoid setting of page/oob sizes in REG_SPI_NFI_PAGEFMT
spi: airoha: reduce the number of modification of REG_SPI_NFI_CNFG and
REG_SPI_NFI_SECCUS_SIZE registers
spi: airoha: set custom sector size equal to flash page size
spi: airoha: avoid reading flash page settings from SNFI registers
during driver startup
drivers/spi/spi-airoha-snfi.c | 502 +++++++++++++++++-----------------
1 file changed, 252 insertions(+), 250 deletions(-)
--
2.50.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 01/13] spi: airoha: remove unnecessary restriction length
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
@ 2025-08-14 23:11 ` Mikhail Kshevetskiy
2025-08-14 23:11 ` [PATCH 02/13] spi: airoha: add support of dual/quad wires spi modes Mikhail Kshevetskiy
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:11 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
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 <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index dbe640986825..09dbbca8bd2b 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -579,13 +579,6 @@ static int airoha_snand_adjust_op_size(struct spi_mem *mem,
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;
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 02/13] spi: airoha: add support of dual/quad wires spi modes
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
2025-08-14 23:11 ` [PATCH 01/13] spi: airoha: remove unnecessary restriction length Mikhail Kshevetskiy
@ 2025-08-14 23:11 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 03/13] spi: airoha: remove unnecessary switch to non-dma mode Mikhail Kshevetskiy
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:11 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
This patch adds support of dual and quad wires spi modes. It will
speed up flash operations on the hardware with corresponding hardware
support.
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 111 +++++++++++++++++++++++++---------
1 file changed, 81 insertions(+), 30 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index 09dbbca8bd2b..70855975c2f3 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -192,6 +192,14 @@
#define SPI_NAND_OP_RESET 0xff
#define SPI_NAND_OP_DIE_SELECT 0xc2
+/* SNAND FIFO commands */
+#define SNAND_FIFO_TX_BUSWIDTH_SINGLE 0x08
+#define SNAND_FIFO_TX_BUSWIDTH_DUAL 0x09
+#define SNAND_FIFO_TX_BUSWIDTH_QUAD 0x0a
+#define SNAND_FIFO_RX_BUSWIDTH_SINGLE 0x0c
+#define SNAND_FIFO_RX_BUSWIDTH_DUAL 0x0e
+#define SNAND_FIFO_RX_BUSWIDTH_QUAD 0x0f
+
#define SPI_NAND_CACHE_SIZE (SZ_4K + SZ_256)
#define SPI_MAX_TRANSFER_SIZE 511
@@ -387,10 +395,25 @@ static int airoha_snand_set_mode(struct airoha_snand_ctrl *as_ctrl,
return regmap_write(as_ctrl->regmap_ctrl, REG_SPI_CTRL_DUMMY, 0);
}
-static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl, u8 cmd,
- const u8 *data, int len)
+static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl,
+ const u8 *data, int len, int buswidth)
{
int i, data_len;
+ u8 cmd;
+
+ switch (buswidth) {
+ case 1:
+ cmd = SNAND_FIFO_TX_BUSWIDTH_SINGLE;
+ break;
+ case 2:
+ cmd = SNAND_FIFO_TX_BUSWIDTH_DUAL;
+ break;
+ case 4:
+ cmd = SNAND_FIFO_TX_BUSWIDTH_QUAD;
+ break;
+ default:
+ return -EINVAL;
+ }
for (i = 0; i < len; i += data_len) {
int err;
@@ -409,16 +432,31 @@ static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl, u8 cmd,
return 0;
}
-static int airoha_snand_read_data(struct airoha_snand_ctrl *as_ctrl, u8 *data,
- int len)
+static int airoha_snand_read_data(struct airoha_snand_ctrl *as_ctrl,
+ u8 *data, int len, int buswidth)
{
int i, data_len;
+ u8 cmd;
+
+ switch (buswidth) {
+ case 1:
+ cmd = SNAND_FIFO_RX_BUSWIDTH_SINGLE;
+ break;
+ case 2:
+ cmd = SNAND_FIFO_RX_BUSWIDTH_DUAL;
+ break;
+ case 4:
+ cmd = SNAND_FIFO_RX_BUSWIDTH_QUAD;
+ break;
+ default:
+ return -EINVAL;
+ }
for (i = 0; i < len; i += data_len) {
int err;
data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
- err = airoha_snand_set_fifo_op(as_ctrl, 0xc, data_len);
+ err = airoha_snand_set_fifo_op(as_ctrl, cmd, data_len);
if (err)
return err;
@@ -596,9 +634,7 @@ static bool airoha_snand_supports_op(struct spi_mem *mem,
if (airoha_snand_is_page_ops(op))
return true;
- return (!op->addr.nbytes || op->addr.buswidth == 1) &&
- (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
- (!op->data.nbytes || op->data.buswidth == 1);
+ return true;
}
static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc)
@@ -891,12 +927,27 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
static int airoha_snand_exec_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- u8 data[8], cmd, opcode = op->cmd.opcode;
struct airoha_snand_ctrl *as_ctrl;
- int i, err;
+ char buf[20], *data;
+ int i, err, op_len, addr_len, dummy_len;
as_ctrl = spi_controller_get_devdata(mem->spi->controller);
+ op_len = op->cmd.nbytes;
+ addr_len = op->addr.nbytes;
+ dummy_len = op->dummy.nbytes;
+
+ if (op_len + dummy_len + addr_len > sizeof(buf))
+ return -EIO;
+
+ data = buf;
+ for (i = 0; i < op_len; i++)
+ *data++ = op->cmd.opcode >> (8 * (op_len - i - 1));
+ for (i = 0; i < addr_len; i++)
+ *data++ = op->addr.val >> (8 * (addr_len - i - 1));
+ for (i = 0; i < dummy_len; i++)
+ *data++ = 0xff;
+
/* switch to manual mode */
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
if (err < 0)
@@ -907,40 +958,40 @@ static int airoha_snand_exec_op(struct spi_mem *mem,
return err;
/* opcode */
- err = airoha_snand_write_data(as_ctrl, 0x8, &opcode, sizeof(opcode));
+ data = buf;
+ err = airoha_snand_write_data(as_ctrl, data, op_len,
+ op->cmd.buswidth);
if (err)
return err;
/* addr part */
- cmd = opcode == SPI_NAND_OP_GET_FEATURE ? 0x11 : 0x8;
- put_unaligned_be64(op->addr.val, data);
-
- for (i = ARRAY_SIZE(data) - op->addr.nbytes;
- i < ARRAY_SIZE(data); i++) {
- err = airoha_snand_write_data(as_ctrl, cmd, &data[i],
- sizeof(data[0]));
+ data += op_len;
+ if (addr_len) {
+ err = airoha_snand_write_data(as_ctrl, data, addr_len,
+ op->addr.buswidth);
if (err)
return err;
}
/* dummy */
- data[0] = 0xff;
- for (i = 0; i < op->dummy.nbytes; i++) {
- err = airoha_snand_write_data(as_ctrl, 0x8, &data[0],
- sizeof(data[0]));
+ data += addr_len;
+ if (dummy_len) {
+ err = airoha_snand_write_data(as_ctrl, data, dummy_len,
+ op->dummy.buswidth);
if (err)
return err;
}
/* data */
- if (op->data.dir == SPI_MEM_DATA_IN) {
- err = airoha_snand_read_data(as_ctrl, op->data.buf.in,
- op->data.nbytes);
- if (err)
- return err;
- } else {
- err = airoha_snand_write_data(as_ctrl, 0x8, op->data.buf.out,
- op->data.nbytes);
+ if (op->data.nbytes) {
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ err = airoha_snand_read_data(as_ctrl, op->data.buf.in,
+ op->data.nbytes,
+ op->data.buswidth);
+ else
+ err = airoha_snand_write_data(as_ctrl, op->data.buf.out,
+ op->data.nbytes,
+ op->data.buswidth);
if (err)
return err;
}
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 03/13] spi: airoha: remove unnecessary switch to non-dma mode
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
2025-08-14 23:11 ` [PATCH 01/13] spi: airoha: remove unnecessary restriction length Mikhail Kshevetskiy
2025-08-14 23:11 ` [PATCH 02/13] spi: airoha: add support of dual/quad wires spi modes Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 04/13] spi: airoha: unify dirmap read/write code Mikhail Kshevetskiy
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
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 <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index 70855975c2f3..049dbb406779 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -804,9 +804,6 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
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,
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 04/13] spi: airoha: unify dirmap read/write code
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
` (2 preceding siblings ...)
2025-08-14 23:12 ` [PATCH 03/13] spi: airoha: remove unnecessary switch to non-dma mode Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 05/13] spi: airoha: switch back to non-dma mode in the case of error Mikhail Kshevetskiy
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
Makes dirmap writing looks similar to dirmap reading. Just a minor
refactoring, no behavior change is expected.
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 43 +++++++++++++++++++++--------------
1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index 049dbb406779..eb39401b3fb3 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -664,6 +664,8 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
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;
@@ -676,7 +678,6 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
break;
}
- as_ctrl = spi_controller_get_devdata(spi->controller);
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA);
if (err < 0)
return err;
@@ -795,36 +796,45 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
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;
+ return err;
- 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)
+ return err;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
dma_addr);
@@ -840,8 +850,7 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
goto error_dma_unmap;
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;
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 05/13] spi: airoha: switch back to non-dma mode in the case of error
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
` (3 preceding siblings ...)
2025-08-14 23:12 ` [PATCH 04/13] spi: airoha: unify dirmap read/write code Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 06/13] spi: airoha: fix reading/writing of flashes with more than one plane per lun Mikhail Kshevetskiy
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
Current dirmap code does not switch back to non-dma mode in the case of
error. This is wrong.
This patch fixes dirmap read/write error path.
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index eb39401b3fb3..8e217ef00dd2 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -684,13 +684,13 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
err = airoha_snand_nfi_config(as_ctrl);
if (err)
- return err;
+ goto error_dma_mode_off;
dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE,
DMA_FROM_DEVICE);
err = dma_mapping_error(as_ctrl->dev, dma_addr);
if (err)
- return err;
+ goto error_dma_mode_off;
/* set dma addr */
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
@@ -790,6 +790,8 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
error_dma_unmap:
dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
DMA_FROM_DEVICE);
+error_dma_mode_off:
+ airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
return err;
}
@@ -828,13 +830,13 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
err = airoha_snand_nfi_config(as_ctrl);
if (err)
- return err;
+ goto error_dma_mode_off;
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;
+ goto error_dma_mode_off;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
dma_addr);
@@ -927,6 +929,8 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
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;
}
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 06/13] spi: airoha: fix reading/writing of flashes with more than one plane per lun
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
` (4 preceding siblings ...)
2025-08-14 23:12 ` [PATCH 05/13] spi: airoha: switch back to non-dma mode in the case of error Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 07/13] spi: airoha: support of dualio/quadio flash reading commands Mikhail Kshevetskiy
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
Reading UBI on the flash with more than one plane per lun will lead to
the following error:
ubi0: default fastmap WL pool size: 50
ubi0: attaching mtd2
ubi0 error: ubi_add_to_av: two LEBs with same sequence number 403
eraseblock attaching information dump:
ec 1
pnum 538
lnum 0
scrub 0
sqnum 403
Volume identifier header dump:
magic 55424921
version 1
vol_type 1
copy_flag 0
compat 0
vol_id 1
lnum 0
data_size 0
used_ebs 0
data_pad 0
sqnum 403
hdr_crc c8418a31
Volume identifier header hexdump:
00000000: 55 42 49 21 01 01 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 UBI!............................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 93 00 00 00 00 00 00 00 00 00 00 00 00 c8 41 8a 31 .............................A.1
ubi0 error: ubi_attach_mtd_dev: failed to attach mtd2, error -22
UBI error: cannot attach mtd2
UBI error: cannot initialize UBI, error -22
UBI init error 22
looking to spi_mem_no_dirmap_read() code we'll see:
static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
struct spi_mem_op op = desc->info.op_tmpl;
int ret;
// --- see here ---
op.addr.val = desc->info.offset + offs;
//-----------------
op.data.buf.in = buf;
op.data.nbytes = len;
ret = spi_mem_adjust_op_size(desc->mem, &op);
if (ret)
return ret;
ret = spi_mem_exec_op(desc->mem, &op);
if (ret)
return ret;
return op.data.nbytes;
}
The similar happens for spi_mem_no_dirmap_write(). Thus spi read address should
take in the account the desc->info.offset.
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index 8e217ef00dd2..89bc09d3faf7 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -719,8 +719,9 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
if (err)
goto error_dma_unmap;
- /* set read addr */
- err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3, 0x0);
+ /* set read addr: zero page offset + descriptor read offset */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3,
+ desc->info.offset);
if (err)
goto error_dma_unmap;
@@ -861,7 +862,9 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
if (err)
goto error_dma_unmap;
- err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, 0x0);
+ /* set write addr: zero page offset + descriptor write offset */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2,
+ desc->info.offset);
if (err)
goto error_dma_unmap;
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 07/13] spi: airoha: support of dualio/quadio flash reading commands
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
` (5 preceding siblings ...)
2025-08-14 23:12 ` [PATCH 06/13] spi: airoha: fix reading/writing of flashes with more than one plane per lun Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 08/13] spi: airoha: allow reading/writing of oob area Mikhail Kshevetskiy
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
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 <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index 89bc09d3faf7..38f2397d1bc4 100644
--- 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
@@ -656,26 +660,38 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc)
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);
@@ -709,7 +725,7 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
/* 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;
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 08/13] spi: airoha: allow reading/writing of oob area
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
` (6 preceding siblings ...)
2025-08-14 23:12 ` [PATCH 07/13] spi: airoha: support of dualio/quadio flash reading commands Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 09/13] spi: airoha: buffer must be 0xff-ed before writing Mikhail Kshevetskiy
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
Current code does not support reading/writing of oob area. Thus raw
reading/writing and bad block support is broken.
This patch fix custom sector size, so oob area will be included to
reading/writing operations.
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index 38f2397d1bc4..bf29de9dad7a 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -568,7 +568,9 @@ static int airoha_snand_nfi_config(struct airoha_snand_ctrl *as_ctrl)
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.spare_size);
return regmap_update_bits(as_ctrl->regmap_nfi,
REG_SPI_NFI_SECCUS_SIZE,
SPI_NFI_CUS_SEC_SIZE, val);
@@ -714,8 +716,9 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
if (err)
goto error_dma_unmap;
- /* set cust sec size */
- val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num;
+ /* number of bytes to read via dma (whole flash page + oob) */
+ val = (as_ctrl->nfi_cfg.sec_size + as_ctrl->nfi_cfg.spare_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,
@@ -860,8 +863,10 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
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);
+ /* number of bytes to write via dma (whole flash page + oob) */
+ val = (as_ctrl->nfi_cfg.sec_size + as_ctrl->nfi_cfg.spare_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);
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 09/13] spi: airoha: buffer must be 0xff-ed before writing
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
` (7 preceding siblings ...)
2025-08-14 23:12 ` [PATCH 08/13] spi: airoha: allow reading/writing of oob area Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 10/13] spi: airoha: avoid setting of page/oob sizes in REG_SPI_NFI_PAGEFMT Mikhail Kshevetskiy
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
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 <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index bf29de9dad7a..7cef38c6f823 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -842,6 +842,9 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
return -EOPNOTSUPP;
}
+ memset(txrx_buf, 0xff,
+ (as_ctrl->nfi_cfg.sec_size + as_ctrl->nfi_cfg.spare_size) *
+ as_ctrl->nfi_cfg.sec_num);
memcpy(txrx_buf + offs, buf, len);
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA);
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 10/13] spi: airoha: avoid setting of page/oob sizes in REG_SPI_NFI_PAGEFMT
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
` (8 preceding siblings ...)
2025-08-14 23:12 ` [PATCH 09/13] spi: airoha: buffer must be 0xff-ed before writing Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 11/13] spi: airoha: reduce the number of modification of REG_SPI_NFI_CNFG and REG_SPI_NFI_SECCUS_SIZE registers Mikhail Kshevetskiy
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
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 <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 38 -----------------------------------
1 file changed, 38 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index 7cef38c6f823..e21d7c8c2e3c 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -516,44 +516,6 @@ static int airoha_snand_nfi_config(struct airoha_snand_ctrl *as_ctrl)
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,
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 11/13] spi: airoha: reduce the number of modification of REG_SPI_NFI_CNFG and REG_SPI_NFI_SECCUS_SIZE registers
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
` (9 preceding siblings ...)
2025-08-14 23:12 ` [PATCH 10/13] spi: airoha: avoid setting of page/oob sizes in REG_SPI_NFI_PAGEFMT Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 12/13] spi: airoha: set custom sector size equal to flash page size Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 13/13] spi: airoha: avoid reading flash page settings from SNFI registers during driver startup Mikhail Kshevetskiy
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
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 <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 113 +++++++++++++++++++++++++---------
1 file changed, 83 insertions(+), 30 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index e21d7c8c2e3c..bda85866d1ae 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -662,7 +662,47 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
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
+ * - Use AHB bus for DMA transfer
+ */
+ 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));
+
+ /* 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 + as_ctrl->nfi_cfg.spare_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;
@@ -706,18 +746,6 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
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;
@@ -813,7 +841,48 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
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 + as_ctrl->nfi_cfg.spare_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;
@@ -854,22 +923,6 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
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;
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 12/13] spi: airoha: set custom sector size equal to flash page size
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
` (10 preceding siblings ...)
2025-08-14 23:12 ` [PATCH 11/13] spi: airoha: reduce the number of modification of REG_SPI_NFI_CNFG and REG_SPI_NFI_SECCUS_SIZE registers Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 13/13] spi: airoha: avoid reading flash page settings from SNFI registers during driver startup Mikhail Kshevetskiy
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
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 <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 38 +++++++++++++++++------------------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index bda85866d1ae..a96c87f01f52 100644
--- a/drivers/spi/spi-airoha-snfi.c
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -629,10 +629,14 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
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 + as_ctrl->nfi_cfg.spare_size);
+
/*
* DUALIO and QUADIO opcodes are not supported by the spi controller,
* replace them with supported opcodes.
@@ -690,18 +694,17 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
FIELD_PREP(SPI_NFI_OPMODE, 6));
/* 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 + as_ctrl->nfi_cfg.spare_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;
@@ -719,12 +722,10 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
goto error_dma_unmap;
/* number of bytes to read via dma (whole flash page + oob) */
- val = (as_ctrl->nfi_cfg.sec_size + as_ctrl->nfi_cfg.spare_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;
@@ -813,10 +814,14 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
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 + as_ctrl->nfi_cfg.spare_size);
+
opcode = desc->info.op_tmpl.cmd.opcode;
switch (opcode) {
case SPI_NAND_OP_PROGRAM_LOAD_SINGLE:
@@ -832,9 +837,7 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
return -EOPNOTSUPP;
}
- memset(txrx_buf, 0xff,
- (as_ctrl->nfi_cfg.sec_size + as_ctrl->nfi_cfg.spare_size) *
- as_ctrl->nfi_cfg.sec_num);
+ memset(txrx_buf, 0xff, bytes);
memcpy(txrx_buf + offs, buf, len);
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA);
@@ -870,18 +873,17 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
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 + as_ctrl->nfi_cfg.spare_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;
@@ -898,12 +900,10 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
goto error_dma_unmap;
/* number of bytes to write via dma (whole flash page + oob) */
- val = (as_ctrl->nfi_cfg.sec_size + as_ctrl->nfi_cfg.spare_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;
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 13/13] spi: airoha: avoid reading flash page settings from SNFI registers during driver startup
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
` (11 preceding siblings ...)
2025-08-14 23:12 ` [PATCH 12/13] spi: airoha: set custom sector size equal to flash page size Mikhail Kshevetskiy
@ 2025-08-14 23:12 ` Mikhail Kshevetskiy
12 siblings, 0 replies; 14+ messages in thread
From: Mikhail Kshevetskiy @ 2025-08-14 23:12 UTC (permalink / raw)
To: Lorenzo Bianconi, Ray Liu, Mark Brown, linux-arm-kernel,
linux-spi, linux-kernel
Cc: Mikhail Kshevetskiy
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 <mikhail.kshevetskiy@iopsys.eu>
---
drivers/spi/spi-airoha-snfi.c | 136 ++++++----------------------------
1 file changed, 21 insertions(+), 115 deletions(-)
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
index a96c87f01f52..3bafceaf749c 100644
--- 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,
@@ -488,56 +481,6 @@ static int airoha_snand_nfi_init(struct airoha_snand_ctrl *as_ctrl)
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, 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)
- 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.spare_size);
- 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)
@@ -570,26 +513,6 @@ static bool airoha_snand_is_page_ops(const struct spi_mem_op *op)
}
}
-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)
{
@@ -634,8 +557,8 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
as_ctrl = spi_controller_get_devdata(spi->controller);
- bytes = as_ctrl->nfi_cfg.sec_num *
- (as_ctrl->nfi_cfg.sec_size + as_ctrl->nfi_cfg.spare_size);
+ /* minimum oob size is 64 */
+ bytes = round_up(offs + len, 64);
/*
* DUALIO and QUADIO opcodes are not supported by the spi controller,
@@ -721,7 +644,14 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
if (err)
goto error_dma_unmap;
- /* number of bytes to read via dma (whole flash page + oob) */
+ /*
+ * 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
+ */
err = regmap_update_bits(as_ctrl->regmap_nfi,
REG_SPI_NFI_SNF_MISC_CTL2,
SPI_NFI_READ_DATA_BYTE_NUM,
@@ -819,8 +749,8 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
as_ctrl = spi_controller_get_devdata(spi->controller);
- bytes = as_ctrl->nfi_cfg.sec_num *
- (as_ctrl->nfi_cfg.sec_size + as_ctrl->nfi_cfg.spare_size);
+ /* minimum oob size is 64 */
+ bytes = round_up(offs + len, 64);
opcode = desc->info.op_tmpl.cmd.opcode;
switch (opcode) {
@@ -899,7 +829,14 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
if (err)
goto error_dma_unmap;
- /* number of bytes to write via dma (whole flash page + oob) */
+ /*
+ * 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
+ */
err = regmap_update_bits(as_ctrl->regmap_nfi,
REG_SPI_NFI_SNF_MISC_CTL2,
SPI_NFI_PROG_LOAD_BYTE_NUM,
@@ -1052,7 +989,6 @@ static int airoha_snand_exec_op(struct spi_mem *mem,
}
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,
@@ -1077,36 +1013,6 @@ static int airoha_snand_setup(struct spi_device *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,
@@ -1180,7 +1086,7 @@ static int airoha_snand_probe(struct platform_device *pdev)
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;
--
2.50.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2025-08-14 23:12 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-14 23:11 [PATCH 00/13] spi: airoha: driver fixes & improvements Mikhail Kshevetskiy
2025-08-14 23:11 ` [PATCH 01/13] spi: airoha: remove unnecessary restriction length Mikhail Kshevetskiy
2025-08-14 23:11 ` [PATCH 02/13] spi: airoha: add support of dual/quad wires spi modes Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 03/13] spi: airoha: remove unnecessary switch to non-dma mode Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 04/13] spi: airoha: unify dirmap read/write code Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 05/13] spi: airoha: switch back to non-dma mode in the case of error Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 06/13] spi: airoha: fix reading/writing of flashes with more than one plane per lun Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 07/13] spi: airoha: support of dualio/quadio flash reading commands Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 08/13] spi: airoha: allow reading/writing of oob area Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 09/13] spi: airoha: buffer must be 0xff-ed before writing Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 10/13] spi: airoha: avoid setting of page/oob sizes in REG_SPI_NFI_PAGEFMT Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 11/13] spi: airoha: reduce the number of modification of REG_SPI_NFI_CNFG and REG_SPI_NFI_SECCUS_SIZE registers Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 12/13] spi: airoha: set custom sector size equal to flash page size Mikhail Kshevetskiy
2025-08-14 23:12 ` [PATCH 13/13] spi: airoha: avoid reading flash page settings from SNFI registers during driver startup Mikhail Kshevetskiy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).