[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251205-winbond-v6-18-rc1-cont-read-v1-5-01bc48631c73@bootlin.com>
Date: Fri, 05 Dec 2025 20:38:56 +0100
From: Miquel Raynal <miquel.raynal@...tlin.com>
To: Mark Brown <broonie@...nel.org>, Richard Weinberger <richard@....at>,
Vignesh Raghavendra <vigneshr@...com>, Michael Walle <mwalle@...nel.org>
Cc: Tudor Ambarus <tudor.ambarus@...aro.org>,
Pratyush Yadav <pratyush@...nel.org>,
Thomas Petazzoni <thomas.petazzoni@...tlin.com>,
Steam Lin <STLin2@...bond.com>, Santhosh Kumar K <s-k6@...com>,
linux-spi@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-mtd@...ts.infradead.org, Miquel Raynal <miquel.raynal@...tlin.com>
Subject: [PATCH RFC 5/8] spi: spi-mem: Create a secondary read operation
In some situations, direct mappings may need to use different
operation templates.
For instance, when enabling continuous reads, Winbond SPI NANDs no
longer expect address cycles because they would be ignoring them
otherwise. Hence, right after the command opcode, they start counting
dummy cycles, followed by the data cycles as usual.
This breaks the assumptions of "reads from cache" always being done
identically once the best variant has been picked up, across the
lifetime of the system.
In order to support this feature, we must give direct mapping more than
a single operation template to use, in order to switch to using
secondary operations upon request by the upper layer.
Create the concept of optional secondary operation template, which may
or may not be fulfilled by the SPI NAND and SPI NOR cores. If the
underlying SPI controller does not leverage any kind of direct mapping
acceleration, the feature has no impact and can be freely
used. Otherwise, the controller driver needs to opt-in for using this
feature, if supported.
The condition checked to know whether a secondary operation has been
provided or not is to look for a non zero opcode to limit the creation
of extra variables. In practice, the opcode 0x00 exist, but is not
related to any cache related operation.
Signed-off-by: Miquel Raynal <miquel.raynal@...tlin.com>
---
The choice of defining two variables named primary and secondary instead
of using an array of templates is on purpose, to simplify the reading. I
find less obvious the use of an array here but this is personal taste.
---
drivers/spi/spi-mem.c | 17 +++++++++++++++++
include/linux/spi/spi-mem.h | 5 +++++
2 files changed, 22 insertions(+)
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 50f16943dc73..b6debc796cf8 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -708,6 +708,23 @@ spi_mem_dirmap_create(struct spi_mem *mem,
if (info->primary_op_tmpl.data.dir == SPI_MEM_NO_DATA)
return ERR_PTR(-EINVAL);
+ /* Apply similar constraints to the secondary template */
+ if (info->secondary_op_tmpl.cmd.opcode) {
+ if (!info->secondary_op_tmpl.addr.nbytes ||
+ info->secondary_op_tmpl.addr.nbytes > 8)
+ return ERR_PTR(-EINVAL);
+
+ if (info->secondary_op_tmpl.data.dir == SPI_MEM_NO_DATA)
+ return ERR_PTR(-EINVAL);
+
+ if (!spi_mem_supports_op(mem, &info->secondary_op_tmpl))
+ return ERR_PTR(-EOPNOTSUPP);
+
+ if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create &&
+ !spi_mem_controller_is_capable(ctlr, secondary_op_tmpl))
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
if (!desc)
return ERR_PTR(-ENOMEM);
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 3092caefa0b6..099de23e7084 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -207,6 +207,8 @@ struct spi_mem_op {
* struct spi_mem_dirmap_info - Direct mapping information
* @op_tmpl: operation template that should be used by the direct mapping when
* the memory device is accessed
+ * @secondary_op_tmpl: secondary template, may be used as an alternative to the
+ * primary template (decided by the upper layer)
* @offset: absolute offset this direct mapping is pointing to
* @length: length in byte of this direct mapping
*
@@ -219,6 +221,7 @@ struct spi_mem_op {
struct spi_mem_dirmap_info {
struct spi_mem_op *op_tmpl;
struct spi_mem_op primary_op_tmpl;
+ struct spi_mem_op secondary_op_tmpl;
u64 offset;
u64 length;
};
@@ -362,12 +365,14 @@ 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
*/
struct spi_controller_mem_caps {
bool dtr;
bool ecc;
bool swap16;
bool per_op_freq;
+ bool secondary_op_tmpl;
};
#define spi_mem_controller_is_capable(ctlr, cap) \
--
2.51.1
Powered by blists - more mailing lists