* [PATCH v1 0/4] Add DDR (Dual Data-Rate) support for DW SPI controller
@ 2026-10-22 10:26 Changhuang Liang
2026-10-22 10:26 ` [PATCH v1 1/4] spi: dw: Add DDR (Dual Data-Rate) support for enhanced SPI mode Changhuang Liang
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Changhuang Liang @ 2026-10-22 10:26 UTC (permalink / raw)
To: Pratyush Yadav, Michael Walle, Takahiro Kuwano, Mark Brown,
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra
Cc: linux-spi, linux-kernel, linux-mtd, Changhuang Liang
This series implements DDR support for the DW SPI controller and also
implements 1-4-4-DTR read support for the MX66L1G45G.
This series has been tested on the JHB100 SoC.
# cat /sys/kernel/debug/spi-nor/spi0.1/capabilities
Supported read modes by the flash
[...]
1S-4D-4D
opcode 0xee
mode cycles 0
dummy cycles 6
Changhuang Liang (4):
spi: dw: Add DDR (Dual Data-Rate) support for enhanced SPI mode
mtd: spi-nor: Support mixed 1S-xD-xD DTR protocols in
spi_nor_spimem_setup_op()
mtd: spi-nor: debugfs: Correct DTR protocol names for 1S-xD-xD modes
mtd: spi-nor: macronix: Add 1-4-4 DTR read support for MX66L1G45G
drivers/mtd/spi-nor/core.c | 21 +++++++++-----
drivers/mtd/spi-nor/debugfs.c | 8 +++---
drivers/mtd/spi-nor/macronix.c | 28 +++++++++++++++++-
drivers/spi/spi-dw-core.c | 52 +++++++++++++++++++++++++++++-----
drivers/spi/spi-dw.h | 6 ++++
5 files changed, 96 insertions(+), 19 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 1/4] spi: dw: Add DDR (Dual Data-Rate) support for enhanced SPI mode
2026-10-22 10:26 [PATCH v1 0/4] Add DDR (Dual Data-Rate) support for DW SPI controller Changhuang Liang
@ 2026-10-22 10:26 ` Changhuang Liang
2026-10-22 10:41 ` Miquel Raynal
2026-10-22 10:26 ` [PATCH v1 2/4] mtd: spi-nor: Support mixed 1S-xD-xD DTR protocols in spi_nor_spimem_setup_op() Changhuang Liang
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Changhuang Liang @ 2026-10-22 10:26 UTC (permalink / raw)
To: Pratyush Yadav, Michael Walle, Takahiro Kuwano, Mark Brown,
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra
Cc: linux-spi, linux-kernel, linux-mtd, Changhuang Liang
Add support for DDR (Dual Data-Rate) transfers in the enhanced SPI
mode of the DW SPI controller.
The enhanced SPI control register (SPI_CTRLR0) has dedicated fields to
enable DDR mode for the instruction phase (INST_DDR_EN) and for the
address/dummy/data phases (SPI_DDR_EN). Populate these from the
corresponding dtr flags of the spi_mem_op.
For DDR transfers, the dummy phase consumes two bits per clock per
line, so the computed wait cycles must be halved. Factor the wait cycle
calculation into a helper, dw_spi_enh_wait_cycles(), so that both the
supports check and the exec path use the same value.
When SPI DDR is enabled, program the DDR_DRIVE_EDGE register. The
recommended TDE value is clk_div / 4, clamped to clk_div / 2 - 1 and to
the field width.
Finally, advertise DTR support to the SPI memory layer through a
dedicated dw_spi_enh_mem_caps, selected when the controller has
DW_SPI_CAP_EMODE, so that spi-mem may issue DDR operations.
Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
---
drivers/spi/spi-dw-core.c | 52 +++++++++++++++++++++++++++++++++------
drivers/spi/spi-dw.h | 6 +++++
2 files changed, 51 insertions(+), 7 deletions(-)
diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 47434fa78e4b..6ff142c8a6bd 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -46,6 +46,8 @@ struct dw_spi_enh_cfg {
u8 inst_l;
u8 addr_l;
u8 trans_t;
+ bool inst_ddr;
+ bool spi_ddr;
};
#ifdef CONFIG_DEBUG_FS
@@ -418,6 +420,7 @@ static void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
u32 cr0 = chip->cr0;
u32 speed_hz;
u16 clk_div;
+ u32 tde = 0;
/* CTRLR0[ 4/3: 0] or CTRLR0[ 20: 16] Data Frame Size */
cr0 |= (cfg->dfs - 1) << dws->dfs_offset;
@@ -468,11 +471,26 @@ static void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
if (enh_cfg) {
cr0 = DW_SPI_ENH_CTRLR0_CLK_STRETCH_EN;
+ if (enh_cfg->inst_ddr)
+ cr0 |= DW_SPI_ENH_CTRLR0_INST_DDR_EN;
+ if (enh_cfg->spi_ddr)
+ cr0 |= DW_SPI_ENH_CTRLR0_SPI_DDR_EN;
cr0 |= FIELD_PREP(DW_SPI_ENH_CTRLR0_WAIT_CYCLE_MASK, enh_cfg->wait_c);
cr0 |= FIELD_PREP(DW_SPI_ENH_CTRLR0_INST_L_MASK, enh_cfg->inst_l);
cr0 |= FIELD_PREP(DW_SPI_ENH_CTRLR0_ADDR_L_MASK, enh_cfg->addr_l);
cr0 |= FIELD_PREP(DW_SPI_ENH_CTRLR0_TRANS_TYPE_MASK, enh_cfg->trans_t);
dw_writel(dws, DW_SPI_SPI_CTRLR0, cr0);
+
+ /*
+ * The recommended value of TDE is clk_div / 4, and it must not exceed
+ * SCKDV / 2 - 1
+ */
+ if (enh_cfg->spi_ddr)
+ tde = min3(clk_div / 4U, clk_div / 2U - 1,
+ FIELD_MAX(DW_SPI_DDR_DRIVE_EDGE_TDE_MASK));
+
+ dw_writel(dws, DW_SPI_DDR_DRIVE_EDGE,
+ FIELD_PREP(DW_SPI_DDR_DRIVE_EDGE_TDE_MASK, tde));
}
}
@@ -656,6 +674,21 @@ static int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op)
return 0;
}
+static u32 dw_spi_enh_wait_cycles(const struct spi_mem_op *op)
+{
+ u32 wait_c;
+
+ if (!op->dummy.nbytes || !op->dummy.buswidth)
+ return 0;
+
+ wait_c = op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth;
+ /* DTR transfers two bits per clock on each line. */
+ if (op->dummy.dtr)
+ wait_c >>= 1;
+
+ return wait_c;
+}
+
static bool dw_spi_supports_enh_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
@@ -678,10 +711,7 @@ static bool dw_spi_supports_enh_mem_op(struct spi_mem *mem,
if (op->dummy.nbytes != 0 && op->data.dir == SPI_MEM_DATA_OUT)
return false;
- /* WAIT_CYCLES is a 5-bit field in SPI_CTRLR0 */
- if (op->dummy.nbytes != 0 &&
- op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth >
- FIELD_MAX(DW_SPI_ENH_CTRLR0_WAIT_CYCLE_MASK))
+ if (dw_spi_enh_wait_cycles(op) > FIELD_MAX(DW_SPI_ENH_CTRLR0_WAIT_CYCLE_MASK))
return false;
if ((dws->quirk_flags & DW_SPI_QUIRK_JHB100) && op->addr.nbytes &&
@@ -1074,8 +1104,10 @@ static int dw_spi_exec_enh_mem_op(struct spi_mem *mem, const struct spi_mem_op *
else
enh_cfg.inst_l = DW_SPI_ENH_CTRLR0_INST_L_INST_L0;
- if (op->dummy.buswidth)
- enh_cfg.wait_c = op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth;
+ enh_cfg.wait_c = dw_spi_enh_wait_cycles(op);
+
+ enh_cfg.inst_ddr = op->cmd.dtr;
+ enh_cfg.spi_ddr = op->addr.dtr || op->dummy.dtr || op->data.dtr;
dw_spi_enable_chip(dws, 0);
@@ -1383,6 +1415,11 @@ static const struct spi_controller_mem_caps dw_spi_mem_caps = {
.per_op_freq = true,
};
+static const struct spi_controller_mem_caps dw_spi_enh_mem_caps = {
+ .per_op_freq = true,
+ .dtr = true,
+};
+
int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
{
struct spi_controller *ctlr;
@@ -1439,7 +1476,8 @@ int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
ctlr->set_cs = dw_spi_set_cs;
if (dws->mem_ops.exec_op) {
ctlr->mem_ops = &dws->mem_ops;
- ctlr->mem_caps = &dw_spi_mem_caps;
+ ctlr->mem_caps = (dws->caps & DW_SPI_CAP_EMODE) ?
+ &dw_spi_enh_mem_caps : &dw_spi_mem_caps;
}
ctlr->max_speed_hz = dws->max_freq;
ctlr->flags = SPI_CONTROLLER_GPIO_SS;
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index c16225c5c887..67b4e0098ac3 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -66,6 +66,7 @@
#define DW_SPI_RX_SAMPLE_DLY 0xf0
#define DW_SPI_SPI_CTRLR0 0xf4
#define DW_SPI_CS_OVERRIDE 0xf4
+#define DW_SPI_DDR_DRIVE_EDGE 0xf8
/* Register offsets (StarFive JHB100 DWC SSI IP-cores) */
#define DW_SPI_JHB100_INST 0x1000
@@ -139,6 +140,8 @@
/* Bit fields in SPI_CTRLR0 */
#define DW_SPI_ENH_CTRLR0_CLK_STRETCH_EN BIT(30)
+#define DW_SPI_ENH_CTRLR0_INST_DDR_EN BIT(17)
+#define DW_SPI_ENH_CTRLR0_SPI_DDR_EN BIT(16)
#define DW_SPI_ENH_CTRLR0_WAIT_CYCLE_MASK GENMASK(15, 11)
#define DW_SPI_ENH_CTRLR0_INST_L_MASK GENMASK(9, 8)
#define DW_SPI_ENH_CTRLR0_INST_L_INST_L0 0x0
@@ -150,6 +153,9 @@
#define DW_SPI_ENH_CTRLR0_TRANS_TYPE_TT2 0x2
#define DW_SPI_ENH_CTRLR0_TRANS_TYPE_MASK GENMASK(1, 0)
+/* Bit fields in DDR_DRIVE_EDGE */
+#define DW_SPI_DDR_DRIVE_EDGE_TDE_MASK GENMASK(7, 0)
+
/* Mem/DMA operations helpers */
#define DW_SPI_WAIT_RETRIES 5
#define DW_SPI_BUF_SIZE \
--
2.25.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 2/4] mtd: spi-nor: Support mixed 1S-xD-xD DTR protocols in spi_nor_spimem_setup_op()
2026-10-22 10:26 [PATCH v1 0/4] Add DDR (Dual Data-Rate) support for DW SPI controller Changhuang Liang
2026-10-22 10:26 ` [PATCH v1 1/4] spi: dw: Add DDR (Dual Data-Rate) support for enhanced SPI mode Changhuang Liang
@ 2026-10-22 10:26 ` Changhuang Liang
2026-10-22 10:45 ` Miquel Raynal
2026-10-22 10:26 ` [PATCH v1 3/4] mtd: spi-nor: debugfs: Correct DTR protocol names for 1S-xD-xD modes Changhuang Liang
2026-10-22 10:26 ` [PATCH v1 4/4] mtd: spi-nor: macronix: Add 1-4-4 DTR read support for MX66L1G45G Changhuang Liang
3 siblings, 1 reply; 9+ messages in thread
From: Changhuang Liang @ 2026-10-22 10:26 UTC (permalink / raw)
To: Pratyush Yadav, Michael Walle, Takahiro Kuwano, Mark Brown,
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra
Cc: linux-spi, linux-kernel, linux-mtd, Changhuang Liang
Currently spi_nor_spimem_setup_op() sets all four phases (cmd, addr,
dummy, data) to DTR whenever spi_nor_protocol_is_dtr(proto) is true.
This is too coarse: the 1S-xD-xD DTR protocols (1_1_1_DTR, 1_2_2_DTR,
1_4_4_DTR, 1_8_8_DTR) send the command phase in STR on a single line,
and only the address, dummy and data phases in DTR. SPIMEM supports
such mixed DTR modes.
Split the handling:
- For SNOR_PROTO_8_8_8_DTR, keep the existing behavior: set all
phases to DTR and use a 2-byte opcode (opcode + extension).
- For the other DTR protocols, set the command phase to STR and only
the address, dummy and data phases to DTR. Double op->dummy.nbytes
since DTR transfers 2 bytes per clock cycle, matching how the dummy
cycle count is specified for these protocols.
No in-tree flash currently declares SNOR_HWCAPS_READ_1_x_x_DTR, so
this is not a bug fix but preparation for enabling these protocols.
A follow-up patch will enable 1S-4D-4D for the MX66L1G45G. The
8D-8D-8D path is unchanged.
Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
---
drivers/mtd/spi-nor/core.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 90524c58602e..43e506e728ab 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -97,13 +97,7 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor,
if (op->data.nbytes)
op->data.buswidth = spi_nor_get_protocol_data_nbits(proto);
- if (spi_nor_protocol_is_dtr(proto)) {
- /*
- * SPIMEM supports mixed DTR modes, but right now we can only
- * have all phases either DTR or STR. IOW, SPIMEM can have
- * something like 4S-4D-4D, but SPI NOR can't. So, set all 4
- * phases to either DTR or STR.
- */
+ if (proto == SNOR_PROTO_8_8_8_DTR) {
op->cmd.dtr = true;
op->addr.dtr = true;
op->dummy.dtr = true;
@@ -115,6 +109,19 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor,
ext = spi_nor_get_cmd_ext(nor, op);
op->cmd.opcode = (op->cmd.opcode << 8) | ext;
op->cmd.nbytes = 2;
+ } else if (spi_nor_protocol_is_dtr(proto)) {
+ /*
+ * 1S-xD-xD protocols: the opcode is sent in STR on a single
+ * line, only the address, dummy and data phases are DTR. The
+ * opcode stays 1 byte (no command extension).
+ */
+ op->cmd.dtr = false;
+ op->addr.dtr = true;
+ op->dummy.dtr = true;
+ op->data.dtr = true;
+
+ /* 2 bytes per clock cycle in DTR mode. */
+ op->dummy.nbytes *= 2;
}
if (proto == SNOR_PROTO_8_8_8_DTR && params->flags & SNOR_F_SWAP16)
--
2.25.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 3/4] mtd: spi-nor: debugfs: Correct DTR protocol names for 1S-xD-xD modes
2026-10-22 10:26 [PATCH v1 0/4] Add DDR (Dual Data-Rate) support for DW SPI controller Changhuang Liang
2026-10-22 10:26 ` [PATCH v1 1/4] spi: dw: Add DDR (Dual Data-Rate) support for enhanced SPI mode Changhuang Liang
2026-10-22 10:26 ` [PATCH v1 2/4] mtd: spi-nor: Support mixed 1S-xD-xD DTR protocols in spi_nor_spimem_setup_op() Changhuang Liang
@ 2026-10-22 10:26 ` Changhuang Liang
2026-10-22 10:46 ` Miquel Raynal
2026-10-22 10:26 ` [PATCH v1 4/4] mtd: spi-nor: macronix: Add 1-4-4 DTR read support for MX66L1G45G Changhuang Liang
3 siblings, 1 reply; 9+ messages in thread
From: Changhuang Liang @ 2026-10-22 10:26 UTC (permalink / raw)
To: Pratyush Yadav, Michael Walle, Takahiro Kuwano, Mark Brown,
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra
Cc: linux-spi, linux-kernel, linux-mtd, Changhuang Liang
The debugfs protocol names for the mixed DTR modes (1-1-1, 1-2-2,
1-4-4, 1-8-8) currently print the command phase as "1D", i.e. dual
transfer on a single line. That does not match the protocol
definition: these modes issue the opcode on a single line in single
data rate (S), and only the address, dummy and data phases use DTR
(D). The "1D" prefix is therefore wrong.
Rename them to "1S-xD-xD" so the names reflect that the first phase
is single-data-rate on one line, consistent with the "8D-8D-8D"
naming for SNOR_PROTO_8_8_8_DTR.
This only changes the strings printed by debugfs; no functional
behavior is affected.
Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
---
drivers/mtd/spi-nor/debugfs.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c
index 3f8d586a7622..f9ec5697aab0 100644
--- a/drivers/mtd/spi-nor/debugfs.c
+++ b/drivers/mtd/spi-nor/debugfs.c
@@ -45,10 +45,10 @@ static const char *spi_nor_protocol_name(enum spi_nor_protocol proto)
case SNOR_PROTO_2_2_2: return "2S-2S-2S";
case SNOR_PROTO_4_4_4: return "4S-4S-4S";
case SNOR_PROTO_8_8_8: return "8S-8S-8S";
- case SNOR_PROTO_1_1_1_DTR: return "1D-1D-1D";
- case SNOR_PROTO_1_2_2_DTR: return "1D-2D-2D";
- case SNOR_PROTO_1_4_4_DTR: return "1D-4D-4D";
- case SNOR_PROTO_1_8_8_DTR: return "1D-8D-8D";
+ case SNOR_PROTO_1_1_1_DTR: return "1S-1D-1D";
+ case SNOR_PROTO_1_2_2_DTR: return "1S-2D-2D";
+ case SNOR_PROTO_1_4_4_DTR: return "1S-4D-4D";
+ case SNOR_PROTO_1_8_8_DTR: return "1S-8D-8D";
case SNOR_PROTO_8_8_8_DTR: return "8D-8D-8D";
}
--
2.25.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 4/4] mtd: spi-nor: macronix: Add 1-4-4 DTR read support for MX66L1G45G
2026-10-22 10:26 [PATCH v1 0/4] Add DDR (Dual Data-Rate) support for DW SPI controller Changhuang Liang
` (2 preceding siblings ...)
2026-10-22 10:26 ` [PATCH v1 3/4] mtd: spi-nor: debugfs: Correct DTR protocol names for 1S-xD-xD modes Changhuang Liang
@ 2026-10-22 10:26 ` Changhuang Liang
2026-10-22 10:47 ` Miquel Raynal
3 siblings, 1 reply; 9+ messages in thread
From: Changhuang Liang @ 2026-10-22 10:26 UTC (permalink / raw)
To: Pratyush Yadav, Michael Walle, Takahiro Kuwano, Mark Brown,
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra
Cc: linux-spi, linux-kernel, linux-mtd, Changhuang Liang
The MX66L1G45G supports the 1-4-4 DTR read mode. This flash uses 6
dummy cycles by default in 1-4-4 DTR mode, but the kernel's SFDP
parser does not derive any SNOR_HWCAPS_READ_1_4_4_DTR capability from
the BFPT table, and 4BAIT only filters already-known capabilities.
The exact number of dummy cycles is also not directly given in the
SFDP tables.
Therefore, implement late_init to initialize support for this opcode,
configuring the read settings with the default 6 dummy cycles. When a
4BAIT table is present, SFDP parsing has already converted all read
opcodes to their 4-byte variants and spi_nor_set_4byte_opcodes() is
skipped later on, so select the 4-byte opcode in that case.
The part also supports the 4-byte opcode set but its SFDP does not
expose a 4BAIT table, so set SPI_NOR_4B_OPCODES like MX66L51235F
(0xc2 0x20 0x1a) to let spi_nor_set_4byte_opcodes() pick the 4-byte
variants, including 0xEE for 1-4-4 DTR.
Add a dedicated fixup for the part (SNOR_ID 0xc2, 0x20, 0x1b) that
keeps the existing QPP 4-byte post-SFDP fixup and additionally
advertises the 1-4-4 DTR read capability in late_init.
Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
---
drivers/mtd/spi-nor/macronix.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c
index b3fdb4b2fa1c..3401275f096b 100644
--- a/drivers/mtd/spi-nor/macronix.c
+++ b/drivers/mtd/spi-nor/macronix.c
@@ -103,6 +103,26 @@ mx25l12805d_4pp3b_post_sfdp_fixups(struct spi_nor *nor)
return 0;
}
+static int mx66l1g45g_late_init_fixups(struct spi_nor *nor)
+{
+ struct spi_nor_flash_parameter *params = nor->params;
+ u8 opcode = SPINOR_OP_READ_1_4_4_DTR;
+
+ /*
+ * When a 4BAIT table is present, SFDP parsing already converted all
+ * read opcodes to their 4-byte variants and spi_nor_set_4byte_opcodes()
+ * is skipped later on, so select the 4-byte opcode here.
+ */
+ if (params->flags & SNOR_F_HAS_4BAIT)
+ opcode = SPINOR_OP_READ_1_4_4_DTR_4B;
+
+ params->hwcaps.mask |= SNOR_HWCAPS_READ_1_4_4_DTR;
+ spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_4_4_DTR],
+ 0, 6, opcode, SNOR_PROTO_1_4_4_DTR);
+
+ return 0;
+}
+
static const struct spi_nor_fixups mx25l25635_fixups = {
.post_bfpt = mx25l25635_post_bfpt_fixups,
.post_sfdp = macronix_qpp4b_post_sfdp_fixups,
@@ -120,6 +140,11 @@ static const struct spi_nor_fixups mx25l12805d_4pp3b_fixups = {
.post_sfdp = mx25l12805d_4pp3b_post_sfdp_fixups,
};
+static const struct spi_nor_fixups mx66l1g45g_fixups = {
+ .post_sfdp = macronix_qpp4b_post_sfdp_fixups,
+ .late_init = mx66l1g45g_late_init_fixups,
+};
+
static const struct flash_info macronix_nor_parts[] = {
{
.id = SNOR_ID(0xc2, 0x20, 0x10),
@@ -355,7 +380,8 @@ static const struct spi_nor_fixup macronix_fixups[] = {
{ .id = SNOR_ID(0xc2, 0x20, 0x19), .fixups = &mx25l25635_fixups },
{ .id = SNOR_ID(0xc2, 0x20, 0x1a), .fixups = ¯onix_qpp4b_fixups,
.fixup_flags = SPI_NOR_4B_OPCODES },
- { .id = SNOR_ID(0xc2, 0x20, 0x1b), .fixups = ¯onix_qpp4b_fixups },
+ { .id = SNOR_ID(0xc2, 0x20, 0x1b), .fixups = &mx66l1g45g_fixups,
+ .fixup_flags = SPI_NOR_4B_OPCODES },
{ .id = SNOR_ID(0xc2, 0x20, 0x1c), .fixups = ¯onix_qpp4b_fixups },
{ .id = SNOR_ID(0xc2, 0x25, 0x3a), .fixups = ¯onix_qpp4b_fixups },
{ .id = SNOR_ID(0xc2, 0x25, 0x3b), .fixups = ¯onix_qpp4b_fixups },
--
2.25.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v1 1/4] spi: dw: Add DDR (Dual Data-Rate) support for enhanced SPI mode
2026-10-22 10:26 ` [PATCH v1 1/4] spi: dw: Add DDR (Dual Data-Rate) support for enhanced SPI mode Changhuang Liang
@ 2026-10-22 10:41 ` Miquel Raynal
0 siblings, 0 replies; 9+ messages in thread
From: Miquel Raynal @ 2026-10-22 10:41 UTC (permalink / raw)
To: Changhuang Liang
Cc: Pratyush Yadav, Michael Walle, Takahiro Kuwano, Mark Brown,
Richard Weinberger, Vignesh Raghavendra, linux-spi, linux-kernel,
linux-mtd
On 22/10/2026 at 03:26:11 -07, Changhuang Liang <changhuang.liang@starfivetech.com> wrote:
> Add support for DDR (Dual Data-Rate) transfers in the enhanced SPI
> mode of the DW SPI controller.
>
> The enhanced SPI control register (SPI_CTRLR0) has dedicated fields to
> enable DDR mode for the instruction phase (INST_DDR_EN) and for the
> address/dummy/data phases (SPI_DDR_EN). Populate these from the
> corresponding dtr flags of the spi_mem_op.
>
> For DDR transfers, the dummy phase consumes two bits per clock per
> line, so the computed wait cycles must be halved. Factor the wait cycle
> calculation into a helper, dw_spi_enh_wait_cycles(), so that both the
> supports check and the exec path use the same value.
>
> When SPI DDR is enabled, program the DDR_DRIVE_EDGE register. The
> recommended TDE value is clk_div / 4, clamped to clk_div / 2 - 1 and to
> the field width.
>
> Finally, advertise DTR support to the SPI memory layer through a
> dedicated dw_spi_enh_mem_caps, selected when the controller has
> DW_SPI_CAP_EMODE, so that spi-mem may issue DDR operations.
>
> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
> ---
> drivers/spi/spi-dw-core.c | 52 +++++++++++++++++++++++++++++++++------
> drivers/spi/spi-dw.h | 6 +++++
> 2 files changed, 51 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
> index 47434fa78e4b..6ff142c8a6bd 100644
> --- a/drivers/spi/spi-dw-core.c
> +++ b/drivers/spi/spi-dw-core.c
> @@ -46,6 +46,8 @@ struct dw_spi_enh_cfg {
> u8 inst_l;
> u8 addr_l;
> u8 trans_t;
> + bool inst_ddr;
> + bool spi_ddr;
If I understand this correctly, spi_ddr is quite a bad name because it
means address and dummy and data ddr (but not instr). Can you try to
come up with a better name for this variable?
Also, if my above understanding is correct, you must provide a
supports_op() callback which would refuse any xS-xS-xD but allow
xD-xD-xD and xS-xD-D modes.
Thanks,
Miquèl
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v1 2/4] mtd: spi-nor: Support mixed 1S-xD-xD DTR protocols in spi_nor_spimem_setup_op()
2026-10-22 10:26 ` [PATCH v1 2/4] mtd: spi-nor: Support mixed 1S-xD-xD DTR protocols in spi_nor_spimem_setup_op() Changhuang Liang
@ 2026-10-22 10:45 ` Miquel Raynal
0 siblings, 0 replies; 9+ messages in thread
From: Miquel Raynal @ 2026-10-22 10:45 UTC (permalink / raw)
To: Changhuang Liang
Cc: Pratyush Yadav, Michael Walle, Takahiro Kuwano, Mark Brown,
Richard Weinberger, Vignesh Raghavendra, linux-spi, linux-kernel,
linux-mtd
On 22/10/2026 at 03:26:12 -07, Changhuang Liang <changhuang.liang@starfivetech.com> wrote:
> Currently spi_nor_spimem_setup_op() sets all four phases (cmd, addr,
> dummy, data) to DTR whenever spi_nor_protocol_is_dtr(proto) is true.
> This is too coarse: the 1S-xD-xD DTR protocols (1_1_1_DTR, 1_2_2_DTR,
> 1_4_4_DTR, 1_8_8_DTR) send the command phase in STR on a single line,
> and only the address, dummy and data phases in DTR. SPIMEM supports
> such mixed DTR modes.
>
> Split the handling:
>
> - For SNOR_PROTO_8_8_8_DTR, keep the existing behavior: set all
> phases to DTR and use a 2-byte opcode (opcode + extension).
>
> - For the other DTR protocols, set the command phase to STR and only
> the address, dummy and data phases to DTR. Double op->dummy.nbytes
> since DTR transfers 2 bytes per clock cycle, matching how the dummy
> cycle count is specified for these protocols.
>
> No in-tree flash currently declares SNOR_HWCAPS_READ_1_x_x_DTR, so
> this is not a bug fix but preparation for enabling these protocols.
> A follow-up patch will enable 1S-4D-4D for the MX66L1G45G. The
> 8D-8D-8D path is unchanged.
>
> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
> ---
> drivers/mtd/spi-nor/core.c | 21 ++++++++++++++-------
> 1 file changed, 14 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
> index 90524c58602e..43e506e728ab 100644
> --- a/drivers/mtd/spi-nor/core.c
> +++ b/drivers/mtd/spi-nor/core.c
> @@ -97,13 +97,7 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor,
> if (op->data.nbytes)
> op->data.buswidth = spi_nor_get_protocol_data_nbits(proto);
>
> - if (spi_nor_protocol_is_dtr(proto)) {
> - /*
> - * SPIMEM supports mixed DTR modes, but right now we can only
> - * have all phases either DTR or STR. IOW, SPIMEM can have
> - * something like 4S-4D-4D, but SPI NOR can't. So, set all 4
> - * phases to either DTR or STR.
> - */
> + if (proto == SNOR_PROTO_8_8_8_DTR) {
> op->cmd.dtr = true;
> op->addr.dtr = true;
> op->dummy.dtr = true;
> @@ -115,6 +109,19 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor,
> ext = spi_nor_get_cmd_ext(nor, op);
> op->cmd.opcode = (op->cmd.opcode << 8) | ext;
> op->cmd.nbytes = 2;
> + } else if (spi_nor_protocol_is_dtr(proto)) {
> + /*
> + * 1S-xD-xD protocols: the opcode is sent in STR on a single
> + * line, only the address, dummy and data phases are DTR. The
> + * opcode stays 1 byte (no command extension).
> + */
> + op->cmd.dtr = false;
> + op->addr.dtr = true;
> + op->dummy.dtr = true;
> + op->data.dtr = true;
Still to coarse IMHO.
What about xS-xS-xD?
As mentioned in the spi controller patch you must make sure these are
refused if they are not supported by your controller because SPI NAND at
least allow them (and I believe SPI NOR might as well)?.
> +
> + /* 2 bytes per clock cycle in DTR mode. */
> + op->dummy.nbytes *= 2;
> }
>
> if (proto == SNOR_PROTO_8_8_8_DTR && params->flags & SNOR_F_SWAP16)
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v1 3/4] mtd: spi-nor: debugfs: Correct DTR protocol names for 1S-xD-xD modes
2026-10-22 10:26 ` [PATCH v1 3/4] mtd: spi-nor: debugfs: Correct DTR protocol names for 1S-xD-xD modes Changhuang Liang
@ 2026-10-22 10:46 ` Miquel Raynal
0 siblings, 0 replies; 9+ messages in thread
From: Miquel Raynal @ 2026-10-22 10:46 UTC (permalink / raw)
To: Changhuang Liang
Cc: Pratyush Yadav, Michael Walle, Takahiro Kuwano, Mark Brown,
Richard Weinberger, Vignesh Raghavendra, linux-spi, linux-kernel,
linux-mtd
On 22/10/2026 at 03:26:13 -07, Changhuang Liang <changhuang.liang@starfivetech.com> wrote:
> The debugfs protocol names for the mixed DTR modes (1-1-1, 1-2-2,
> 1-4-4, 1-8-8) currently print the command phase as "1D", i.e. dual
> transfer on a single line. That does not match the protocol
> definition: these modes issue the opcode on a single line in single
> data rate (S), and only the address, dummy and data phases use DTR
> (D). The "1D" prefix is therefore wrong.
>
> Rename them to "1S-xD-xD" so the names reflect that the first phase
> is single-data-rate on one line, consistent with the "8D-8D-8D"
> naming for SNOR_PROTO_8_8_8_DTR.
>
> This only changes the strings printed by debugfs; no functional
> behavior is affected.
>
> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
> ---
That's likely correct.
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v1 4/4] mtd: spi-nor: macronix: Add 1-4-4 DTR read support for MX66L1G45G
2026-10-22 10:26 ` [PATCH v1 4/4] mtd: spi-nor: macronix: Add 1-4-4 DTR read support for MX66L1G45G Changhuang Liang
@ 2026-10-22 10:47 ` Miquel Raynal
0 siblings, 0 replies; 9+ messages in thread
From: Miquel Raynal @ 2026-10-22 10:47 UTC (permalink / raw)
To: Changhuang Liang
Cc: Pratyush Yadav, Michael Walle, Takahiro Kuwano, Mark Brown,
Richard Weinberger, Vignesh Raghavendra, linux-spi, linux-kernel,
linux-mtd
On 22/10/2026 at 03:26:14 -07, Changhuang Liang <changhuang.liang@starfivetech.com> wrote:
> The MX66L1G45G supports the 1-4-4 DTR read mode. This flash uses 6
> dummy cycles by default in 1-4-4 DTR mode, but the kernel's SFDP
> parser does not derive any SNOR_HWCAPS_READ_1_4_4_DTR capability from
> the BFPT table, and 4BAIT only filters already-known capabilities.
> The exact number of dummy cycles is also not directly given in the
> SFDP tables.
>
> Therefore, implement late_init to initialize support for this opcode,
> configuring the read settings with the default 6 dummy cycles. When a
> 4BAIT table is present, SFDP parsing has already converted all read
> opcodes to their 4-byte variants and spi_nor_set_4byte_opcodes() is
> skipped later on, so select the 4-byte opcode in that case.
>
> The part also supports the 4-byte opcode set but its SFDP does not
> expose a 4BAIT table, so set SPI_NOR_4B_OPCODES like MX66L51235F
> (0xc2 0x20 0x1a) to let spi_nor_set_4byte_opcodes() pick the 4-byte
> variants, including 0xEE for 1-4-4 DTR.
>
> Add a dedicated fixup for the part (SNOR_ID 0xc2, 0x20, 0x1b) that
> keeps the existing QPP 4-byte post-SFDP fixup and additionally
> advertises the 1-4-4 DTR read capability in late_init.
>
> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
Maybe in your v2 you can add (as hinted in the documentation) traces of
a test run with the SFDP tables, proof that it works in this mode, etc.
Thanks,
Miquèl
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-10-22 10:47 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-22 10:26 [PATCH v1 0/4] Add DDR (Dual Data-Rate) support for DW SPI controller Changhuang Liang
2026-10-22 10:26 ` [PATCH v1 1/4] spi: dw: Add DDR (Dual Data-Rate) support for enhanced SPI mode Changhuang Liang
2026-10-22 10:41 ` Miquel Raynal
2026-10-22 10:26 ` [PATCH v1 2/4] mtd: spi-nor: Support mixed 1S-xD-xD DTR protocols in spi_nor_spimem_setup_op() Changhuang Liang
2026-10-22 10:45 ` Miquel Raynal
2026-10-22 10:26 ` [PATCH v1 3/4] mtd: spi-nor: debugfs: Correct DTR protocol names for 1S-xD-xD modes Changhuang Liang
2026-10-22 10:46 ` Miquel Raynal
2026-10-22 10:26 ` [PATCH v1 4/4] mtd: spi-nor: macronix: Add 1-4-4 DTR read support for MX66L1G45G Changhuang Liang
2026-10-22 10:47 ` Miquel Raynal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®