* [PATCH 1/4] spi: spi-mem: Add a no_cs_assertion capability
2026-03-26 16:47 [PATCH 0/4] spi: spi-mem/mtd: spinand: Prevent SPI NAND continuous reads on am65/am62 Miquel Raynal
@ 2026-03-26 16:47 ` Miquel Raynal
2026-03-26 16:47 ` [PATCH 2/4] mtd: spinand: Make sure continuous read is always disabled during probe Miquel Raynal
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Miquel Raynal @ 2026-03-26 16:47 UTC (permalink / raw)
To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
Cc: Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd,
Michael Walle, Takahiro Kuwano, Pratyush Yadav, Steam Lin,
Santhosh Kumar K, Miquel Raynal
Some controllers are 'smart', and that's a problem.
For instance, the Cadence quadspi controller is capable of deasserting
the CS automatically whenever a too long period of time without any data
to transfer elapses.
This 'feature' combined with a loaded interconnect with arbitration, a
"long" transfer may be split into smaller DMA transfers. In this case
the controller may allow itself to deassert the CS between chunks.
Deasserting the CS stops any ongoing continuous read. Reasserting it
later to continue the reading will only result in the host getting
garbage.
In this case, the host controller driver has no control over the CS
state, so we cannot reliably enable continuous reads. Flag this
limitation through a spi-mem controller capability.
The inversion in the flag name (starting with 'no_') is voluntary, in
order to avoid the need to set this flag in all controller drivers. Only
the broken controllers shall set this bit, the default being that the
controller masters its CS fully.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
I am open to suggestions regarding the naming of this flag.
---
include/linux/spi/spi-mem.h | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index bd2a73d46980..de153719a08e 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -373,7 +373,10 @@ struct spi_controller_mem_ops {
* @swap16: Supports swapping bytes on a 16 bit boundary when configured in
* Octal DTR
* @per_op_freq: Supports per operation frequency switching
- * @secondary_op_tmpl: Supports leveraging a secondary memory operation template
+ * @no_cs_assertion: The controller may automatically deassert the CS if there
+ * is a pause in the transfer (eg. internal bus contention or
+ * DMA arbitration on an interconnect). Features such as NAND
+ * continuous reads shall not be leveraged.
*/
struct spi_controller_mem_caps {
bool dtr;
@@ -381,6 +384,7 @@ struct spi_controller_mem_caps {
bool swap16;
bool per_op_freq;
bool secondary_op_tmpl;
+ bool no_cs_assertion;
};
#define spi_mem_controller_is_capable(ctlr, cap) \
--
2.51.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/4] mtd: spinand: Make sure continuous read is always disabled during probe
2026-03-26 16:47 [PATCH 0/4] spi: spi-mem/mtd: spinand: Prevent SPI NAND continuous reads on am65/am62 Miquel Raynal
2026-03-26 16:47 ` [PATCH 1/4] spi: spi-mem: Add a no_cs_assertion capability Miquel Raynal
@ 2026-03-26 16:47 ` Miquel Raynal
2026-03-26 16:47 ` [PATCH 3/4] mtd: spinand: Prevent continuous reads on some controllers Miquel Raynal
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Miquel Raynal @ 2026-03-26 16:47 UTC (permalink / raw)
To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
Cc: Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd,
Michael Walle, Takahiro Kuwano, Pratyush Yadav, Steam Lin,
Santhosh Kumar K, Miquel Raynal
Recent changes made sure whenever we were using continuous reads, we
would first start by disabling the feature to ensure a well proven and
stable probe sequence. For development purposes, it might also matter to
make sure we always disable continuous reads at first, in case the ECC
configuration would change. Doing this "automatically" will become even
more relevant when we add extra controller flags to prevent continuous
reads at all.
Ensure we disable continuous reads if the feature is available on the
chip, regardless of whether it will be used or not.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/spi/core.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 45c3afb9cceb..dbe2c463fe01 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -953,11 +953,7 @@ static void spinand_cont_read_init(struct spinand_device *spinand)
enum nand_ecc_engine_type engine_type = nand->ecc.ctx.conf.engine_type;
/* OOBs cannot be retrieved so external/on-host ECC engine won't work */
- if (spinand->set_cont_read &&
- (engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE ||
- engine_type == NAND_ECC_ENGINE_TYPE_NONE)) {
- spinand->cont_read_possible = true;
-
+ if (spinand->set_cont_read) {
/*
* Ensure continuous read is disabled on probe.
* Some devices retain this state across soft reset,
@@ -965,6 +961,10 @@ static void spinand_cont_read_init(struct spinand_device *spinand)
* in false positive returns from spinand_isbad().
*/
spinand_cont_read_enable(spinand, false);
+
+ if (engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE ||
+ engine_type == NAND_ECC_ENGINE_TYPE_NONE)
+ spinand->cont_read_possible = true;
}
}
--
2.51.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/4] mtd: spinand: Prevent continuous reads on some controllers
2026-03-26 16:47 [PATCH 0/4] spi: spi-mem/mtd: spinand: Prevent SPI NAND continuous reads on am65/am62 Miquel Raynal
2026-03-26 16:47 ` [PATCH 1/4] spi: spi-mem: Add a no_cs_assertion capability Miquel Raynal
2026-03-26 16:47 ` [PATCH 2/4] mtd: spinand: Make sure continuous read is always disabled during probe Miquel Raynal
@ 2026-03-26 16:47 ` Miquel Raynal
2026-03-26 16:47 ` [PATCH 4/4] spi: cadence-qspi: Prevent SPI NAND continuous reads Miquel Raynal
2026-04-27 13:28 ` [PATCH 0/4] spi: spi-mem/mtd: spinand: Prevent SPI NAND continuous reads on am65/am62 Miquel Raynal
4 siblings, 0 replies; 6+ messages in thread
From: Miquel Raynal @ 2026-03-26 16:47 UTC (permalink / raw)
To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
Cc: Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd,
Michael Walle, Takahiro Kuwano, Pratyush Yadav, Steam Lin,
Santhosh Kumar K, Miquel Raynal
Some controllers do not have full control over the CS line state and may
deassert it under certain conditions in the middle of a (long)
transfer.
Continuous reads are stopped with a CS deassert, hence both features
cannot live together.
Whenever a controller flags that it cannot maintain the CS state
reliably, disable continuous reads entirely.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
SPI NOR reads are not affected, hence only a solution in SPI NAND is
needed.
---
drivers/mtd/nand/spi/core.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index dbe2c463fe01..82f4dd441541 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -951,6 +951,7 @@ static void spinand_cont_read_init(struct spinand_device *spinand)
{
struct nand_device *nand = spinand_to_nand(spinand);
enum nand_ecc_engine_type engine_type = nand->ecc.ctx.conf.engine_type;
+ struct spi_controller *ctlr = spinand->spimem->spi->controller;
/* OOBs cannot be retrieved so external/on-host ECC engine won't work */
if (spinand->set_cont_read) {
@@ -962,8 +963,9 @@ static void spinand_cont_read_init(struct spinand_device *spinand)
*/
spinand_cont_read_enable(spinand, false);
- if (engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE ||
- engine_type == NAND_ECC_ENGINE_TYPE_NONE)
+ if ((engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE ||
+ engine_type == NAND_ECC_ENGINE_TYPE_NONE) &&
+ !spi_mem_controller_is_capable(ctlr, no_cs_assertion))
spinand->cont_read_possible = true;
}
}
--
2.51.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 4/4] spi: cadence-qspi: Prevent SPI NAND continuous reads
2026-03-26 16:47 [PATCH 0/4] spi: spi-mem/mtd: spinand: Prevent SPI NAND continuous reads on am65/am62 Miquel Raynal
` (2 preceding siblings ...)
2026-03-26 16:47 ` [PATCH 3/4] mtd: spinand: Prevent continuous reads on some controllers Miquel Raynal
@ 2026-03-26 16:47 ` Miquel Raynal
2026-04-27 13:28 ` [PATCH 0/4] spi: spi-mem/mtd: spinand: Prevent SPI NAND continuous reads on am65/am62 Miquel Raynal
4 siblings, 0 replies; 6+ messages in thread
From: Miquel Raynal @ 2026-03-26 16:47 UTC (permalink / raw)
To: Mark Brown, Richard Weinberger, Vignesh Raghavendra
Cc: Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd,
Michael Walle, Takahiro Kuwano, Pratyush Yadav, Steam Lin,
Santhosh Kumar K, Miquel Raynal
TI AM62Ax errata i2351, entitled "OSPI: Direct Access Controller (DAC)
does not support Continuous Read mode with NAND Flash", explains that
the CS can be deasserted almost at any time during a transfer (basically
there is an interconnect arbitration every 1023 byte). This is an
expected internal behaviour of the controller, but this leads to
spurious CS deasserts. These are totally forbidden during SPI NAND
continuous read transfers, because they indicate an end of transfer and
the continuous read is then stopped on the flash side.
I initially tried to query the flash type and geometry to decide whether
to apply a spi message size limit (there is a spi helper for that) but
we cannot reliably get up to the MTD structure to discriminate if it is
a NOR or a NAND we are playing with (it is not relevant to limit SPI NOR
transfers, they are not affected). If we actually take this path, what
limitation shall we enforce? The errata mentions 1023B, this is super
low, less than a typical page size (about 2k or 4k, for most of them),
so this is not usable. On my side, I only observed this problem on a
2-page read in octal DTR mode with more than 12 dummy cycles. The
writesize summed with the oobsize could be a relevant boundary, but it
is still quite arbitrary. Hence, I opted for implementing a controller
capability flag, which then is used to decide whether the SPI NAND
continuous read feature can be enabled.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
I do not know if all flavours of this controller have the same
limitation, or whether it is integration specific. As I only found
mention of this errata for the AM62 processor, I opted for limiting the
flag to a single compatible.
---
drivers/spi/spi-cadence-quadspi.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index 649ff55333f0..9f9b3013aa5d 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -1740,6 +1740,12 @@ static const struct spi_controller_mem_caps cqspi_mem_caps = {
.per_op_freq = true,
};
+static const struct spi_controller_mem_caps cqspi_am654_mem_caps = {
+ .dtr = true,
+ .per_op_freq = true,
+ .no_cs_assertion = true,
+};
+
static int cqspi_setup_flash(struct cqspi_st *cqspi)
{
struct platform_device *pdev = cqspi->pdev;
@@ -1797,6 +1803,8 @@ static int cqspi_probe(struct platform_device *pdev)
host->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL;
host->mem_ops = &cqspi_mem_ops;
host->mem_caps = &cqspi_mem_caps;
+ if (of_device_is_compatible(pdev->dev.of_node, "ti,am654-ospi"))
+ host->mem_caps = &cqspi_am654_mem_caps;
cqspi = spi_controller_get_devdata(host);
if (of_device_is_compatible(pdev->dev.of_node, "starfive,jh7110-qspi"))
--
2.51.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 0/4] spi: spi-mem/mtd: spinand: Prevent SPI NAND continuous reads on am65/am62
2026-03-26 16:47 [PATCH 0/4] spi: spi-mem/mtd: spinand: Prevent SPI NAND continuous reads on am65/am62 Miquel Raynal
` (3 preceding siblings ...)
2026-03-26 16:47 ` [PATCH 4/4] spi: cadence-qspi: Prevent SPI NAND continuous reads Miquel Raynal
@ 2026-04-27 13:28 ` Miquel Raynal
4 siblings, 0 replies; 6+ messages in thread
From: Miquel Raynal @ 2026-04-27 13:28 UTC (permalink / raw)
To: Mark Brown
Cc: Richard Weinberger, Vignesh Raghavendra, Thomas Petazzoni,
linux-spi, linux-kernel, linux-mtd, Michael Walle,
Takahiro Kuwano, Pratyush Yadav, Steam Lin, Santhosh Kumar K
Hi Mark,
> Mark, as agreed for the continuous read series, I will offer to you an
> immutable tag with the spi-mem patches, if you agree I can include the
> spi-mem patch from this series as well (once the discussion on the
> approach/naming settled).
As discussed, I am preparing an immutable branch with the spi-mem
patches of the "Winbond SPI NAND continuous read" series.
This series is related but I wanted to double check with you: can I take
the spi-mem patch and include it in that immutable branch which I will
share with you for inclusion in the spi tree?
Thanks,
Miquèl
^ permalink raw reply [flat|nested] 6+ messages in thread