* [PATCH v2 0/3] Add quad mode support for QPIC SNAND
@ 2026-08-07 16:03 Md Sadre Alam
2026-08-07 16:03 ` [PATCH v2 1/3] spi: spi-qpic-snand: move command mapping helper Md Sadre Alam
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Md Sadre Alam @ 2026-08-07 16:03 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, linux-kernel, linux-arm-msm, Md Sadre Alam,
Md Sadre Alam
The Qualcomm QPIC SPI-NAND controller supports both single (x1) and
quad (x4) transfer modes, however the current driver operates only in
single-bit mode. This series adds support for quad data transfers and
includes a vendor-specific fix required for Macronix SPI-NAND devices.
Signed-off-by: Md Sadre Alam <mdalam@qti.qualcomm.com>
---
Changes in v2:
- Removed incorrect if check
- Updated snandc->qspi->cmd with quad command for further read in quad
mode.
- Link to v1: https://lore.kernel.org/r/20260716-quad-v1-0-636f74da17e1@qti.qualcomm.com
---
Md Sadre Alam (3):
spi: spi-qpic-snand: move command mapping helper
spi: spi-qpic-snand: add quad mode support
spi: spi-qpic-snand: Handle Macronix quad read opcode 0x6b
drivers/spi/spi-qpic-snand.c | 155 ++++++++++++++++++++++++++++---------------
1 file changed, 103 insertions(+), 52 deletions(-)
---
base-commit: d56fa0b2bd2d9b2fddc10e8f5bdd42d56676935c
change-id: 20260716-quad-ec2765317214
Best regards,
--
Md Sadre Alam <md.alam@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/3] spi: spi-qpic-snand: move command mapping helper
2026-08-07 16:03 [PATCH v2 0/3] Add quad mode support for QPIC SNAND Md Sadre Alam
@ 2026-08-07 16:03 ` Md Sadre Alam
2026-08-07 16:03 ` [PATCH v2 2/3] spi: spi-qpic-snand: add quad mode support Md Sadre Alam
2026-08-07 16:03 ` [PATCH v2 3/3] spi: spi-qpic-snand: Handle Macronix quad read opcode 0x6b Md Sadre Alam
2 siblings, 0 replies; 4+ messages in thread
From: Md Sadre Alam @ 2026-08-07 16:03 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, linux-kernel, linux-arm-msm, Md Sadre Alam,
Md Sadre Alam
Move qcom_spi_cmd_mapping() above qcom_spi_read_page() so it can be
used by read path changes added in a subsequent patch.
No functional change.
Signed-off-by: Md Sadre Alam <md.alam@oss.qualcomm.com>
---
drivers/spi/spi-qpic-snand.c | 96 ++++++++++++++++++++++----------------------
1 file changed, 48 insertions(+), 48 deletions(-)
diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c
index 1e2fc875cd66..db105b3fd601 100644
--- a/drivers/spi/spi-qpic-snand.c
+++ b/drivers/spi/spi-qpic-snand.c
@@ -1004,6 +1004,54 @@ static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc,
return qcom_spi_check_error(snandc);
}
+static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd)
+{
+ switch (opcode) {
+ case SPINAND_RESET:
+ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE);
+ break;
+ case SPINAND_READID:
+ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID);
+ break;
+ case SPINAND_GET_FEATURE:
+ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE);
+ break;
+ case SPINAND_SET_FEATURE:
+ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE |
+ QPIC_SET_FEATURE);
+ break;
+ case SPINAND_READ:
+ if (snandc->qspi->raw_rw) {
+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
+ SPI_WP | SPI_HOLD | OP_PAGE_READ);
+ } else {
+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
+ SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC);
+ }
+
+ break;
+ case SPINAND_ERASE:
+ *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP |
+ SPI_HOLD | SPI_TRANSFER_MODE_x1;
+ break;
+ case SPINAND_WRITE_EN:
+ *cmd = SPINAND_WRITE_EN;
+ break;
+ case SPINAND_PROGRAM_EXECUTE:
+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
+ SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE);
+ break;
+ case SPINAND_PROGRAM_LOAD:
+ *cmd = SPINAND_PROGRAM_LOAD;
+ break;
+ default:
+ dev_err(snandc->dev, "Opcode not supported: %u\n", opcode);
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
static int qcom_spi_read_page(struct qcom_nand_controller *snandc,
const struct spi_mem_op *op)
{
@@ -1268,54 +1316,6 @@ static int qcom_spi_program_execute(struct qcom_nand_controller *snandc,
return 0;
}
-static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd)
-{
- switch (opcode) {
- case SPINAND_RESET:
- *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE);
- break;
- case SPINAND_READID:
- *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID);
- break;
- case SPINAND_GET_FEATURE:
- *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE);
- break;
- case SPINAND_SET_FEATURE:
- *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE |
- QPIC_SET_FEATURE);
- break;
- case SPINAND_READ:
- if (snandc->qspi->raw_rw) {
- *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
- SPI_WP | SPI_HOLD | OP_PAGE_READ);
- } else {
- *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
- SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC);
- }
-
- break;
- case SPINAND_ERASE:
- *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP |
- SPI_HOLD | SPI_TRANSFER_MODE_x1;
- break;
- case SPINAND_WRITE_EN:
- *cmd = SPINAND_WRITE_EN;
- break;
- case SPINAND_PROGRAM_EXECUTE:
- *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
- SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE);
- break;
- case SPINAND_PROGRAM_LOAD:
- *cmd = SPINAND_PROGRAM_LOAD;
- break;
- default:
- dev_err(snandc->dev, "Opcode not supported: %u\n", opcode);
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
static int qcom_spi_write_page(struct qcom_nand_controller *snandc,
const struct spi_mem_op *op)
{
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/3] spi: spi-qpic-snand: add quad mode support
2026-08-07 16:03 [PATCH v2 0/3] Add quad mode support for QPIC SNAND Md Sadre Alam
2026-08-07 16:03 ` [PATCH v2 1/3] spi: spi-qpic-snand: move command mapping helper Md Sadre Alam
@ 2026-08-07 16:03 ` Md Sadre Alam
2026-08-07 16:03 ` [PATCH v2 3/3] spi: spi-qpic-snand: Handle Macronix quad read opcode 0x6b Md Sadre Alam
2 siblings, 0 replies; 4+ messages in thread
From: Md Sadre Alam @ 2026-08-07 16:03 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, linux-kernel, linux-arm-msm, Md Sadre Alam,
Md Sadre Alam
Add support for quad (x4) transfer mode in the QPIC SPI NAND driver.
The controller supports both single (x1) and quad (x4) SPI transfers,
but the driver currently operates only in x1 mode.
Track the QUAD enable state from the device configuration register
(0xB0) and switch the data transfer width accordingly. When the core
enables quad mode, use x4 transfers for read and program operations to
improve throughput.
Introduce a quad_mode flag in struct qpic_spi_nand to cache the current
device state. The flag is updated based on GET_FEATURE responses from
the configuration register.
Signed-off-by: Md Sadre Alam <md.alam@oss.qualcomm.com>
---
drivers/spi/spi-qpic-snand.c | 67 ++++++++++++++++++++++++++++++++++++++------
1 file changed, 58 insertions(+), 9 deletions(-)
diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c
index db105b3fd601..6ad2f96dde8c 100644
--- a/drivers/spi/spi-qpic-snand.c
+++ b/drivers/spi/spi-qpic-snand.c
@@ -46,14 +46,19 @@
#define SPINAND_RESET 0xff
#define SPINAND_READID 0x9f
+#define SPINAND_FEATURE_ADDR 0xb0
#define SPINAND_GET_FEATURE 0x0f
#define SPINAND_SET_FEATURE 0x1f
+#define SPINAND_READ_CACHE 0x0b
#define SPINAND_READ 0x13
+#define SPINAND_READ_QUAD 0xeb
#define SPINAND_ERASE 0xd8
#define SPINAND_WRITE_EN 0x06
#define SPINAND_PROGRAM_EXECUTE 0x10
#define SPINAND_PROGRAM_LOAD 0x84
+#define SPINAND_PROGRAM_LOAD_QUAD 0x34
+#define QUAD_WIDTH 0x4
#define ACC_FEATURE 0xe
#define BAD_BLOCK_MARKER_SIZE 0x2
#define OOB_BUF_SIZE 128
@@ -114,6 +119,7 @@ struct qpic_spi_nand {
bool oob_rw;
bool page_rw;
bool raw_rw;
+ bool quad_mode;
};
static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc,
@@ -1004,8 +1010,15 @@ static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc,
return qcom_spi_check_error(snandc);
}
-static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd)
+static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op, u32 *cmd)
{
+ u32 opcode = op->cmd.opcode;
+ u32 transfer_mode = SPI_TRANSFER_MODE_x1;
+
+ if (snandc->qspi->quad_mode && op->data.buswidth == QUAD_WIDTH)
+ transfer_mode = SPI_TRANSFER_MODE_x4;
+
switch (opcode) {
case SPINAND_RESET:
*cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE);
@@ -1021,11 +1034,13 @@ static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode,
QPIC_SET_FEATURE);
break;
case SPINAND_READ:
+ case SPINAND_READ_QUAD:
+ case SPINAND_READ_CACHE:
if (snandc->qspi->raw_rw) {
- *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
+ *cmd = (PAGE_ACC | LAST_PAGE | transfer_mode |
SPI_WP | SPI_HOLD | OP_PAGE_READ);
} else {
- *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
+ *cmd = (PAGE_ACC | LAST_PAGE | transfer_mode |
SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC);
}
@@ -1038,12 +1053,15 @@ static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode,
*cmd = SPINAND_WRITE_EN;
break;
case SPINAND_PROGRAM_EXECUTE:
- *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
- SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE);
+ *cmd = (PAGE_ACC | LAST_PAGE | transfer_mode |
+ SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE);
break;
case SPINAND_PROGRAM_LOAD:
*cmd = SPINAND_PROGRAM_LOAD;
break;
+ case SPINAND_PROGRAM_LOAD_QUAD:
+ *cmd = SPINAND_PROGRAM_LOAD_QUAD;
+ break;
default:
dev_err(snandc->dev, "Opcode not supported: %u\n", opcode);
return -EOPNOTSUPP;
@@ -1055,6 +1073,16 @@ static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode,
static int qcom_spi_read_page(struct qcom_nand_controller *snandc,
const struct spi_mem_op *op)
{
+ int ret;
+ u32 cmd;
+
+ /* Update the cached command for the cache-read opcode and bus width. */
+ ret = qcom_spi_cmd_mapping(snandc, op, &cmd);
+ if (ret < 0)
+ return ret;
+
+ snandc->qspi->cmd = cpu_to_le32(cmd);
+
if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
return qcom_spi_read_page_raw(snandc, op);
@@ -1322,11 +1350,12 @@ static int qcom_spi_write_page(struct qcom_nand_controller *snandc,
int ret;
u32 cmd;
- ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
+ ret = qcom_spi_cmd_mapping(snandc, op, &cmd);
if (ret < 0)
return ret;
- if (op->cmd.opcode == SPINAND_PROGRAM_LOAD)
+ if (op->cmd.opcode == SPINAND_PROGRAM_LOAD ||
+ op->cmd.opcode == SPINAND_PROGRAM_LOAD_QUAD)
snandc->qspi->data_buf = (u8 *)op->data.buf.out;
return 0;
@@ -1338,7 +1367,7 @@ static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
u32 cmd;
int ret, opcode;
- ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
+ ret = qcom_spi_cmd_mapping(snandc, op, &cmd);
if (ret < 0)
return ret;
@@ -1457,6 +1486,22 @@ static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_
val = le32_to_cpu(*(__le32 *)snandc->reg_read_buf);
val >>= 8;
memcpy(op->data.buf.in, &val, snandc->buf_count);
+
+ /*
+ * Track QUAD mode state from configuration register.
+ * When core layer reads register 0xB0 (CFG), check if
+ * QUAD enable bit (bit 0) is set and update our state
+ * accordingly for future READ/WRITE operations.
+ */
+ if (op->addr.val == SPINAND_FEATURE_ADDR) {
+ bool quad_enabled = !!((u8)val & BIT(0));
+
+ if (snandc->qspi->quad_mode != quad_enabled) {
+ snandc->qspi->quad_mode = quad_enabled;
+ dev_info(snandc->dev, "SPI NAND QUAD mode: %s\n",
+ quad_enabled ? "enabled" : "disabled");
+ }
+ }
}
return 0;
@@ -1497,7 +1542,8 @@ static bool qcom_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *o
return ((!op->addr.nbytes || op->addr.buswidth == 1) &&
(!op->dummy.nbytes || op->dummy.buswidth == 1) &&
- (!op->data.nbytes || op->data.buswidth == 1));
+ (!op->data.nbytes || op->data.buswidth == 1 ||
+ op->data.buswidth == 4));
}
static int qcom_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
@@ -1548,6 +1594,9 @@ static int qcom_spi_probe(struct platform_device *pdev)
if (!qspi)
return -ENOMEM;
+ /* Initialize QUAD mode state */
+ qspi->quad_mode = false;
+
ctlr = __devm_spi_alloc_controller(dev, sizeof(*snandc), false);
if (!ctlr)
return -ENOMEM;
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 3/3] spi: spi-qpic-snand: Handle Macronix quad read opcode 0x6b
2026-08-07 16:03 [PATCH v2 0/3] Add quad mode support for QPIC SNAND Md Sadre Alam
2026-08-07 16:03 ` [PATCH v2 1/3] spi: spi-qpic-snand: move command mapping helper Md Sadre Alam
2026-08-07 16:03 ` [PATCH v2 2/3] spi: spi-qpic-snand: add quad mode support Md Sadre Alam
@ 2026-08-07 16:03 ` Md Sadre Alam
2 siblings, 0 replies; 4+ messages in thread
From: Md Sadre Alam @ 2026-08-07 16:03 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, linux-kernel, linux-arm-msm, Md Sadre Alam,
Md Sadre Alam
Macronix SPI-NAND devices use opcode 0x6b for quad output cache reads,
while most other devices use opcode 0xeb. The QPIC SPI-NAND driver does
not currently recognize opcode 0x6b, causing read operations to fail
when Macronix devices select this cache read variant.
Add the Macronix-specific read opcode to the command mapping logic and
treat it the same as the existing quad read operations.
This allows Macronix SPI-NAND devices to operate correctly in quad read
mode.
Signed-off-by: Md Sadre Alam <md.alam@oss.qualcomm.com>
---
drivers/spi/spi-qpic-snand.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c
index 6ad2f96dde8c..61b1f2eb19ce 100644
--- a/drivers/spi/spi-qpic-snand.c
+++ b/drivers/spi/spi-qpic-snand.c
@@ -52,6 +52,7 @@
#define SPINAND_READ_CACHE 0x0b
#define SPINAND_READ 0x13
#define SPINAND_READ_QUAD 0xeb
+#define SPINAND_READ_MACRONIX 0x6b
#define SPINAND_ERASE 0xd8
#define SPINAND_WRITE_EN 0x06
#define SPINAND_PROGRAM_EXECUTE 0x10
@@ -1036,6 +1037,7 @@ static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc,
case SPINAND_READ:
case SPINAND_READ_QUAD:
case SPINAND_READ_CACHE:
+ case SPINAND_READ_MACRONIX:
if (snandc->qspi->raw_rw) {
*cmd = (PAGE_ACC | LAST_PAGE | transfer_mode |
SPI_WP | SPI_HOLD | OP_PAGE_READ);
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-07 16:04 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-07 16:03 [PATCH v2 0/3] Add quad mode support for QPIC SNAND Md Sadre Alam
2026-08-07 16:03 ` [PATCH v2 1/3] spi: spi-qpic-snand: move command mapping helper Md Sadre Alam
2026-08-07 16:03 ` [PATCH v2 2/3] spi: spi-qpic-snand: add quad mode support Md Sadre Alam
2026-08-07 16:03 ` [PATCH v2 3/3] spi: spi-qpic-snand: Handle Macronix quad read opcode 0x6b Md Sadre Alam
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.