From: Miquel Raynal Date: Wed, 29 Apr 2026 17:56:42 +0000 (+0200) Subject: spi: spi-mem: Create a secondary read operation X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f96f2fa152518d93ffeedbea781db50aef7f7dc;p=thirdparty%2Flinux.git 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 Signed-off-by: Miquel Raynal --- diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index e2eaa1ba4ff60..f64eda9bbd9f0 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 9a96ddace3eb2..2012a3b2ef913 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) \