summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiquel Raynal <miquel.raynal@bootlin.com>2026-04-29 19:56:42 +0200
committerMiquel Raynal <miquel.raynal@bootlin.com>2026-05-04 15:02:07 +0200
commit6f96f2fa152518d93ffeedbea781db50aef7f7dc (patch)
tree6cb74020dd4690d9e17988affc37cf081d35db0d
parent39d0ea33123ffe0214217b529830ad91574c8757 (diff)
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. Acked-by: Mark Brown <broonie@kernel.org> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
-rw-r--r--drivers/spi/spi-mem.c17
-rw-r--r--include/linux/spi/spi-mem.h5
2 files changed, 22 insertions, 0 deletions
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index e2eaa1ba4ff6..f64eda9bbd9f 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -713,6 +713,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_obj(*desc);
if (!desc)
return ERR_PTR(-ENOMEM);
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 9a96ddace3eb..2012a3b2ef91 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -227,6 +227,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
*
@@ -239,6 +241,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;
};
@@ -382,12 +385,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) \