* [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support
@ 2026-04-10 17:41 Miquel Raynal
2026-04-10 17:41 ` [PATCH 1/5] spi: cadence-qspi: Revert the filtering of certain opcodes in ODTR Miquel Raynal
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Miquel Raynal @ 2026-04-10 17:41 UTC (permalink / raw)
To: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
Pratyush Yadav
Cc: Steam Lin, Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd,
Miquel Raynal
Winbond chips W35N02JW and W35N04JW differ slightly from W35N01JW. As
they have more blocks, they require a couple more bits to fully address
the whole device. These address bits have been stuffed at the end of the
command cycles, which is non standard, and this is something I didn't
catch in the first place.
Stuffing these address bits there implies the creation of a new spi-mem
command template.
While testing, I realized one of my former patches in the Cadence
controller was totally wrong, so it needs to be reverted.
Mark, if it is not too late, you may want to pull in the first 2
patches, and I will apply the SPI NAND patches in a fixes PR after -rc1
is out.
Sorry for the mess :-)
Thanks,
Miquèl
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
Miquel Raynal (5):
spi: cadence-qspi: Revert the filtering of certain opcodes in ODTR
spi: spi-mem: Add a packed command operation
mtd: spinand: Add support for packed read data ODTR commands
mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW
mtd: spinand: winbond: Fix ODTR write VCR on W35NxxJW
drivers/mtd/nand/spi/core.c | 24 +++++++++++++++++++++---
drivers/mtd/nand/spi/winbond.c | 6 +++---
drivers/spi/spi-cadence-quadspi.c | 4 ----
include/linux/mtd/spinand.h | 7 +++++++
include/linux/spi/spi-mem.h | 8 ++++++++
5 files changed, 39 insertions(+), 10 deletions(-)
---
base-commit: a2e786cb711f88509c39b82d8e5a7e52b169b1a6
change-id: 20260410-winbond-6-19-rc1-oddr-7a87b98c452c
Best regards,
--
Miquel Raynal <miquel.raynal@bootlin.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/5] spi: cadence-qspi: Revert the filtering of certain opcodes in ODTR
2026-04-10 17:41 [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Miquel Raynal
@ 2026-04-10 17:41 ` Miquel Raynal
2026-04-10 17:41 ` [PATCH 2/5] spi: spi-mem: Add a packed command operation Miquel Raynal
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Miquel Raynal @ 2026-04-10 17:41 UTC (permalink / raw)
To: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
Pratyush Yadav
Cc: Steam Lin, Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd,
Miquel Raynal
I got mislead while analyzing the driver by the fact that the second
opcode byte was in all cases smashed:
if (op->cmd.dtr)
opcode = op->cmd.opcode >> 8;
else
opcode = op->cmd.opcode;
While at a first glance this doesn't let a chance to the second byte to
be shifted out on the bus, this is actually the second step of an
initialization, where the byte being apparently "ignored" in DTR mode
has already been written in a dedicated "extended opcode" register. As
such, the comment and the extra check that I proposed were entirely
wrong, remove them.
Fixes: bee085476d27 ("spi: cadence-qspi: Make sure we filter out unsupported ops")
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
My apologies for this mistake. Until now I never had to deal with "non
repeated" opcodes. Now that I do, I realize that this was wrong.
---
drivers/spi/spi-cadence-quadspi.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index 649ff55333f0..87e49d913591 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -1538,10 +1538,6 @@ static bool cqspi_supports_mem_op(struct spi_mem *mem,
if (op->data.nbytes && op->data.buswidth != 8)
return false;
- /* A single opcode is supported, it will be repeated */
- if ((op->cmd.opcode >> 8) != (op->cmd.opcode & 0xFF))
- return false;
-
if (cqspi->is_rzn1)
return false;
} else if (!all_false) {
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/5] spi: spi-mem: Add a packed command operation
2026-04-10 17:41 [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Miquel Raynal
2026-04-10 17:41 ` [PATCH 1/5] spi: cadence-qspi: Revert the filtering of certain opcodes in ODTR Miquel Raynal
@ 2026-04-10 17:41 ` Miquel Raynal
2026-04-10 17:41 ` [PATCH 3/5] mtd: spinand: Add support for packed read data ODTR commands Miquel Raynal
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Miquel Raynal @ 2026-04-10 17:41 UTC (permalink / raw)
To: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
Pratyush Yadav
Cc: Steam Lin, Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd,
Miquel Raynal
Instead of repeating the command opcode twice, some flash devices try to
pack command and address bits. In this case, the second opcode byte
being sent (LSB) is free to be used. The input data must be ANDed to
only provide the relevant bits.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
include/linux/spi/spi-mem.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 5774e554c0f0..f54c708f4c50 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -28,6 +28,14 @@
.dtr = true, \
}
+#define SPI_MEM_DTR_OP_PACKED_CMD(__opcode, __addr, __buswidth) \
+ { \
+ .nbytes = 2, \
+ .opcode = __opcode << 8 | __addr, \
+ .buswidth = __buswidth, \
+ .dtr = true, \
+ }
+
#define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth) \
{ \
.nbytes = __nbytes, \
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/5] mtd: spinand: Add support for packed read data ODTR commands
2026-04-10 17:41 [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Miquel Raynal
2026-04-10 17:41 ` [PATCH 1/5] spi: cadence-qspi: Revert the filtering of certain opcodes in ODTR Miquel Raynal
2026-04-10 17:41 ` [PATCH 2/5] spi: spi-mem: Add a packed command operation Miquel Raynal
@ 2026-04-10 17:41 ` Miquel Raynal
2026-04-10 17:41 ` [PATCH 4/5] mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW Miquel Raynal
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Miquel Raynal @ 2026-04-10 17:41 UTC (permalink / raw)
To: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
Pratyush Yadav
Cc: Steam Lin, Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd,
Miquel Raynal
Some devices stuff address bits in the double byte opcode (in place of
the repeated byte) in order to be able to increase the size of the
devices, without adding extra address bytes.
Create a flag to identify those devices. When the flag is set, use the
"packed" variant for the read data operation.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/spi/core.c | 24 +++++++++++++++++++++---
include/linux/mtd/spinand.h | 7 +++++++
2 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 66c90419f6d5..96154f359e1a 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -100,6 +100,17 @@ spinand_fill_page_read_op(struct spinand_device *spinand, u64 addr)
return op;
}
+static struct spi_mem_op
+spinand_fill_page_read_packed_op(struct spinand_device *spinand, u64 addr)
+{
+ struct spi_mem_op op = spinand->op_templates->page_read;
+
+ op.cmd.opcode |= addr >> 16;
+ op.addr.val = addr & 0xFFFF;
+
+ return op;
+}
+
struct spi_mem_op
spinand_fill_prog_exec_op(struct spinand_device *spinand, u64 addr)
{
@@ -453,7 +464,10 @@ static int spinand_load_page_op(struct spinand_device *spinand,
{
struct nand_device *nand = spinand_to_nand(spinand);
unsigned int row = nanddev_pos_to_row(nand, &req->pos);
- struct spi_mem_op op = SPINAND_OP(spinand, page_read, row);
+ bool packed = spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ;
+ struct spi_mem_op op = packed ?
+ SPINAND_OP(spinand, page_read_packed, row) :
+ SPINAND_OP(spinand, page_read, row);
return spi_mem_exec_op(spinand->spimem, &op);
}
@@ -1489,9 +1503,13 @@ static int spinand_init_odtr_instruction_set(struct spinand_device *spinand)
if (!spi_mem_supports_op(spinand->spimem, &tmpl->blk_erase))
return -EOPNOTSUPP;
- tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0);
- if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read))
+ if (spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ)
+ tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(0);
+ else
+ tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0);
+ if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read)) {
return -EOPNOTSUPP;
+ }
tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_8D_8D_0_OP(0);
if (!spi_mem_supports_op(spinand->spimem, &tmpl->prog_exec))
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 6a024cf1c53a..f2f80103649d 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -290,6 +290,12 @@
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA)
+#define SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(addr) \
+ SPI_MEM_OP(SPI_MEM_DTR_OP_PACKED_CMD(0x13, addr >> 16, 8), \
+ SPI_MEM_DTR_OP_ADDR(2, addr & 0xffff, 8), \
+ SPI_MEM_OP_NO_DUMMY, \
+ SPI_MEM_OP_NO_DATA)
+
#define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
@@ -482,6 +488,7 @@ struct spinand_ecc_info {
#define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2)
#define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3)
#define SPINAND_NO_RAW_ACCESS BIT(4)
+#define SPINAND_ODTR_PACKED_PAGE_READ BIT(5)
/**
* struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/5] mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW
2026-04-10 17:41 [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Miquel Raynal
` (2 preceding siblings ...)
2026-04-10 17:41 ` [PATCH 3/5] mtd: spinand: Add support for packed read data ODTR commands Miquel Raynal
@ 2026-04-10 17:41 ` Miquel Raynal
2026-04-10 17:41 ` [PATCH 5/5] mtd: spinand: winbond: Fix ODTR write VCR on W35NxxJW Miquel Raynal
2026-04-11 10:53 ` (subset) [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Mark Brown
5 siblings, 0 replies; 8+ messages in thread
From: Miquel Raynal @ 2026-04-10 17:41 UTC (permalink / raw)
To: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
Pratyush Yadav
Cc: Steam Lin, Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd,
Miquel Raynal
Both W35N02JW and W35N04JW diverge from W35N01JW when it comes to the
"data read" operation in ODTR mode. In order to stuff more address
bits (up to 18), the second command byte is replaced by the most
significant address bits, keeping the number of address bytes to 2.
Fixes: 44a2f49b9bdc ("mtd: spinand: winbond: W35N octal DTR support")
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/spi/winbond.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 6dfd0dcc8ee7..a3fca8a1cff1 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -515,7 +515,7 @@ static const struct spinand_info winbond_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
&write_cache_octal_variants,
&update_cache_octal_variants),
- 0,
+ SPINAND_ODTR_PACKED_PAGE_READ,
SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
@@ -526,7 +526,7 @@ static const struct spinand_info winbond_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
&write_cache_octal_variants,
&update_cache_octal_variants),
- 0,
+ SPINAND_ODTR_PACKED_PAGE_READ,
SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/5] mtd: spinand: winbond: Fix ODTR write VCR on W35NxxJW
2026-04-10 17:41 [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Miquel Raynal
` (3 preceding siblings ...)
2026-04-10 17:41 ` [PATCH 4/5] mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW Miquel Raynal
@ 2026-04-10 17:41 ` Miquel Raynal
2026-04-11 10:53 ` (subset) [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Mark Brown
5 siblings, 0 replies; 8+ messages in thread
From: Miquel Raynal @ 2026-04-10 17:41 UTC (permalink / raw)
To: Mark Brown, Richard Weinberger, Vignesh Raghavendra,
Pratyush Yadav
Cc: Steam Lin, Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd,
Miquel Raynal
In most scenarios this variant is actually unused (VCR is written in
SSDR mode), but we need to provide an octal variant. The address is 24
bits but is sent over 4 bytes MSB first. This means we need to shift the
register address by one extra byte for the address to be correct.
I didn't catch this initially because the volatile register region is
256 bytes wide, so the write-then-read procedure did work with the small
register addresses I was using at that time: 0 and 1.
Fixes: 44a2f49b9bdc ("mtd: spinand: winbond: W35N octal DTR support")
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/spi/winbond.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index a3fca8a1cff1..269fc587c5fe 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -99,7 +99,7 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
#define SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, buf) \
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x81, 8), \
- SPI_MEM_DTR_OP_ADDR(4, reg, 8), \
+ SPI_MEM_DTR_OP_ADDR(4, reg << 8, 8), \
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_DTR_OP_DATA_OUT(2, buf, 8))
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: (subset) [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support
2026-04-10 17:41 [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Miquel Raynal
` (4 preceding siblings ...)
2026-04-10 17:41 ` [PATCH 5/5] mtd: spinand: winbond: Fix ODTR write VCR on W35NxxJW Miquel Raynal
@ 2026-04-11 10:53 ` Mark Brown
2026-04-27 13:10 ` Miquel Raynal
5 siblings, 1 reply; 8+ messages in thread
From: Mark Brown @ 2026-04-11 10:53 UTC (permalink / raw)
To: Richard Weinberger, Vignesh Raghavendra, Pratyush Yadav,
Miquel Raynal
Cc: Steam Lin, Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd
On Fri, 10 Apr 2026 19:41:00 +0200, Miquel Raynal wrote:
> mtd/spi: Fix Winbond W35N02JW / W35N04JW support
>
> Winbond chips W35N02JW and W35N04JW differ slightly from W35N01JW. As
> they have more blocks, they require a couple more bits to fully address
> the whole device. These address bits have been stuffed at the end of the
> command cycles, which is non standard, and this is something I didn't
> catch in the first place.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-7.1
Thanks!
[1/5] spi: cadence-qspi: Revert the filtering of certain opcodes in ODTR
https://git.kernel.org/broonie/spi/c/5e75c1d4d386
[2/5] spi: spi-mem: Add a packed command operation
https://git.kernel.org/broonie/spi/c/f79ee9e4b232
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: (subset) [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support
2026-04-11 10:53 ` (subset) [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Mark Brown
@ 2026-04-27 13:10 ` Miquel Raynal
0 siblings, 0 replies; 8+ messages in thread
From: Miquel Raynal @ 2026-04-27 13:10 UTC (permalink / raw)
To: Mark Brown
Cc: Richard Weinberger, Vignesh Raghavendra, Pratyush Yadav,
Steam Lin, Thomas Petazzoni, linux-spi, linux-kernel, linux-mtd
>> Winbond chips W35N02JW and W35N04JW differ slightly from W35N01JW. As
>> they have more blocks, they require a couple more bits to fully address
>> the whole device. These address bits have been stuffed at the end of the
>> command cycles, which is non standard, and this is something I didn't
>> catch in the first place.
>>
>> [...]
>
> Applied to
>
> https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-7.1
>
> Thanks!
>
> [1/5] spi: cadence-qspi: Revert the filtering of certain opcodes in ODTR
> https://git.kernel.org/broonie/spi/c/5e75c1d4d386
> [2/5] spi: spi-mem: Add a packed command operation
> https://git.kernel.org/broonie/spi/c/f79ee9e4b232
The 3 other patches have been queued for the next mtd/fixes PR.
Thanks a lot Mark for the responsiveness.
Bes regards,
Miquèl
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-04-27 13:10 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-10 17:41 [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Miquel Raynal
2026-04-10 17:41 ` [PATCH 1/5] spi: cadence-qspi: Revert the filtering of certain opcodes in ODTR Miquel Raynal
2026-04-10 17:41 ` [PATCH 2/5] spi: spi-mem: Add a packed command operation Miquel Raynal
2026-04-10 17:41 ` [PATCH 3/5] mtd: spinand: Add support for packed read data ODTR commands Miquel Raynal
2026-04-10 17:41 ` [PATCH 4/5] mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW Miquel Raynal
2026-04-10 17:41 ` [PATCH 5/5] mtd: spinand: winbond: Fix ODTR write VCR on W35NxxJW Miquel Raynal
2026-04-11 10:53 ` (subset) [PATCH 0/5] mtd/spi: Fix Winbond W35N02JW / W35N04JW support Mark Brown
2026-04-27 13:10 ` Miquel Raynal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox