* [PATCH 1/4] dt-bindings: mtd: qcom,nandc: Add MDM9607 QPIC NAND controller
2026-06-08 13:20 [PATCH 0/4] mtd: rawnand: qcom: Add MDM9607 Stephan Gerhold
@ 2026-06-08 13:20 ` Stephan Gerhold
2026-06-08 13:20 ` [PATCH 2/4] mtd: rawnand: qcom: Make "aon" clock optional Stephan Gerhold
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Stephan Gerhold @ 2026-06-08 13:20 UTC (permalink / raw)
To: Manivannan Sadhasivam, Miquel Raynal
Cc: Richard Weinberger, Vignesh Raghavendra, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-mtd, linux-arm-msm,
devicetree, linux-kernel
Add the qcom,mdm9607-nand compatible for the QPIC NAND controller used
inside the MDM9607 SoC.
On MDM9607, there is only a single controllable clock for the NAND
controller (RPM_SMD_QPIC_CLK). The same situation also applies e.g. for
qcom,sdx55-nand, but the corresponding device tree (qcom-sdx55.dtsi) works
around that by assigning a dummy clock (&nand_clk_dummy) to the second
clock ("aon") that is required by the dt-bindings. This is not really
useful, so avoid doing that for new platforms by excluding the second "aon"
clock entry in the dt-bindings.
Signed-off-by: Stephan Gerhold <stephan.gerhold@linaro.org>
---
.../devicetree/bindings/mtd/qcom,nandc.yaml | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
index 5511389960f0..4a9ba32cbddd 100644
--- a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
+++ b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
@@ -22,17 +22,20 @@ properties:
- qcom,ipq4019-nand
- qcom,ipq6018-nand
- qcom,ipq8074-nand
+ - qcom,mdm9607-nand
- qcom,sdx55-nand
reg:
maxItems: 1
clocks:
+ minItems: 1
items:
- description: Core Clock
- description: Always ON Clock
clock-names:
+ minItems: 1
items:
- const: core
- const: aon
@@ -101,6 +104,26 @@ allOf:
items:
- const: rxtx
+ # MDM9607 has no (separately controllable) "aon" clock, only "core"
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,mdm9607-nand
+ then:
+ properties:
+ clocks:
+ maxItems: 1
+ clock-names:
+ maxItems: 1
+ else:
+ properties:
+ clocks:
+ minItems: 2
+ clock-names:
+ minItems: 2
+
- if:
properties:
compatible:
@@ -121,6 +144,7 @@ allOf:
- qcom,ipq4019-nand
- qcom,ipq6018-nand
- qcom,ipq8074-nand
+ - qcom,mdm9607-nand
- qcom,sdx55-nand
then:
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/4] mtd: rawnand: qcom: Make "aon" clock optional
2026-06-08 13:20 [PATCH 0/4] mtd: rawnand: qcom: Add MDM9607 Stephan Gerhold
2026-06-08 13:20 ` [PATCH 1/4] dt-bindings: mtd: qcom,nandc: Add MDM9607 QPIC NAND controller Stephan Gerhold
@ 2026-06-08 13:20 ` Stephan Gerhold
2026-06-08 13:30 ` sashiko-bot
2026-06-08 13:20 ` [PATCH 3/4] mtd: rawnand: qcom: Make has_onfi_read_op separate from qpic_version2 Stephan Gerhold
2026-06-08 13:20 ` [PATCH 4/4] mtd: rawnand: qcom: Add MDM9607 compatible Stephan Gerhold
3 siblings, 1 reply; 7+ messages in thread
From: Stephan Gerhold @ 2026-06-08 13:20 UTC (permalink / raw)
To: Manivannan Sadhasivam, Miquel Raynal
Cc: Richard Weinberger, Vignesh Raghavendra, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-mtd, linux-arm-msm,
devicetree, linux-kernel
Some SoCs (e.g. MDM9607, SDX55) have only a single separately controllable
clock for the NAND controller. The actual clocks in the hardware are
managed by the firmware and turned on all together when needed. In this
case, there is no separate "aon" clock that can be described in the device
tree.
Make the second "aon" clock optional to avoid an error when it is missing.
For platforms that really need it, the dt-bindings are responsible for
validating that.
Signed-off-by: Stephan Gerhold <stephan.gerhold@linaro.org>
---
drivers/mtd/nand/raw/qcom_nandc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index 4b80ce084d9a..0251dd591d40 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2280,7 +2280,7 @@ static int qcom_nandc_probe(struct platform_device *pdev)
if (IS_ERR(nandc->core_clk))
return PTR_ERR(nandc->core_clk);
- nandc->aon_clk = devm_clk_get(dev, "aon");
+ nandc->aon_clk = devm_clk_get_optional(dev, "aon");
if (IS_ERR(nandc->aon_clk))
return PTR_ERR(nandc->aon_clk);
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/4] mtd: rawnand: qcom: Make "aon" clock optional
2026-06-08 13:20 ` [PATCH 2/4] mtd: rawnand: qcom: Make "aon" clock optional Stephan Gerhold
@ 2026-06-08 13:30 ` sashiko-bot
0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-06-08 13:30 UTC (permalink / raw)
To: Stephan Gerhold; +Cc: conor+dt, robh, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Use-After-Free due to missing MTD device unregistration on boot partition parsing failure.
- [High] Use-After-Free due to missing MTD unregistration for successful child nodes on probe failure.
--
commit 36076ea85a481eb0cc14bb0f987501c4cc6b4d63
Author: Stephan Gerhold <stephan.gerhold@linaro.org>
Subject: mtd: rawnand: qcom: Make "aon" clock optional
Some SoCs (e.g. MDM9607, SDX55) have only a single separately controllable
clock for the NAND controller. The actual clocks in the hardware are
managed by the firmware and turned on all together when needed. In this
case, there is no separate "aon" clock that can be described in the device
tree. Make the second "aon" clock optional to avoid an error when it is
missing.
> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
> index 4b80ce084d9ac..0251dd591d40a 100644
> --- a/drivers/mtd/nand/raw/qcom_nandc.c
> +++ b/drivers/mtd/nand/raw/qcom_nandc.c
> @@ -2280,7 +2280,7 @@ static int qcom_nandc_probe(struct platform_device *pdev)
> if (IS_ERR(nandc->core_clk))
> return PTR_ERR(nandc->core_clk);
>
> - nandc->aon_clk = devm_clk_get(dev, "aon");
> + nandc->aon_clk = devm_clk_get_optional(dev, "aon");
> if (IS_ERR(nandc->aon_clk))
> return PTR_ERR(nandc->aon_clk);
[Severity: High]
This is a pre-existing issue, but I noticed a potential use-after-free in
qcom_probe_nand_devices() that could occur during probe failure.
If an earlier child node is successfully registered, but a later one fails
to allocate memory, the function returns directly:
drivers/mtd/nand/raw/qcom_nandc.c:qcom_probe_nand_devices() {
...
for_each_available_child_of_node_scoped(dn, child) {
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host)
return -ENOMEM;
...
}
Are the previously successful children left registered with the MTD
subsystem? Since they are never unregistered before the error is returned,
the driver core will automatically free their memory via devres, which
might leave dangling pointers in the MTD lists.
[Severity: High]
This isn't a bug introduced by this patch, but there appears to be another
missing unregistration path in qcom_nand_host_init_and_register().
If mtd_device_parse_register() succeeds, the device is fully registered:
drivers/mtd/nand/raw/qcom_nandc.c:qcom_nand_host_init_and_register() {
...
ret = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
if (ret)
goto err;
if (nandc->props->use_codeword_fixup) {
ret = qcom_nand_host_parse_boot_partitions(nandc, host, dn);
if (ret)
goto err;
...
err:
nand_cleanup(chip);
return ret;
}
If qcom_nand_host_parse_boot_partitions() fails, the code jumps to the err
label and performs nand_cleanup(), but doesn't call mtd_device_unregister().
When qcom_probe_nand_devices() subsequently frees the host memory via
devm_kfree(), could this leave the MTD device registered while freeing
its backing memory?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260608-qcom-nandc-mdm9607-v1-0-4639a0492274@linaro.org?part=2
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/4] mtd: rawnand: qcom: Make has_onfi_read_op separate from qpic_version2
2026-06-08 13:20 [PATCH 0/4] mtd: rawnand: qcom: Add MDM9607 Stephan Gerhold
2026-06-08 13:20 ` [PATCH 1/4] dt-bindings: mtd: qcom,nandc: Add MDM9607 QPIC NAND controller Stephan Gerhold
2026-06-08 13:20 ` [PATCH 2/4] mtd: rawnand: qcom: Make "aon" clock optional Stephan Gerhold
@ 2026-06-08 13:20 ` Stephan Gerhold
2026-06-08 13:34 ` sashiko-bot
2026-06-08 13:20 ` [PATCH 4/4] mtd: rawnand: qcom: Add MDM9607 compatible Stephan Gerhold
3 siblings, 1 reply; 7+ messages in thread
From: Stephan Gerhold @ 2026-06-08 13:20 UTC (permalink / raw)
To: Manivannan Sadhasivam, Miquel Raynal
Cc: Richard Weinberger, Vignesh Raghavendra, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-mtd, linux-arm-msm,
devicetree, linux-kernel
QPIC v1.5 requires using the OP_PAGE_READ_ONFI_READ command, but is missing
the rest of the hardware changes that are currently covered by the QPIC v2
(qpic_version2) check in the driver. Split that into an extra
has_onfi_read_op feature flag so it can be separately enabled.
No functional change.
Signed-off-by: Stephan Gerhold <stephan.gerhold@linaro.org>
---
drivers/mtd/nand/raw/qcom_nandc.c | 15 ++++++++-------
include/linux/mtd/nand-qpic-common.h | 2 ++
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index 0251dd591d40..9217e8de5512 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -1564,7 +1564,7 @@ static int qcom_op_cmd_mapping(struct nand_chip *chip, u8 opcode,
cmd = OP_FETCH_ID;
break;
case NAND_CMD_PARAM:
- if (nandc->props->qpic_version2)
+ if (nandc->props->has_onfi_read_op)
cmd = OP_PAGE_READ_ONFI_READ;
else
cmd = OP_PAGE_READ;
@@ -1903,7 +1903,7 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_
nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
/* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
- if (!nandc->props->qpic_version2) {
+ if (!nandc->props->has_onfi_read_op) {
nandc->regs->vld = cpu_to_le32((nandc->vld & ~READ_START_VLD));
nandc->regs->cmd1 = cpu_to_le32((nandc->cmd1 & ~READ_ADDR_MASK) |
FIELD_PREP(READ_ADDR_MASK, NAND_CMD_PARAM));
@@ -1911,7 +1911,7 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_
nandc->regs->exec = cpu_to_le32(1);
- if (!nandc->props->qpic_version2) {
+ if (!nandc->props->has_onfi_read_op) {
nandc->regs->orig_cmd1 = cpu_to_le32(nandc->cmd1);
nandc->regs->orig_vld = cpu_to_le32(nandc->vld);
}
@@ -1925,7 +1925,7 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_
else
nandc_set_read_loc_first(chip, reg_base, 0, len, 1);
- if (!nandc->props->qpic_version2) {
+ if (!nandc->props->has_onfi_read_op) {
qcom_write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0);
qcom_write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
}
@@ -1939,7 +1939,7 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_
nandc->buf_count, 0);
/* restore CMD1 and VLD regs */
- if (!nandc->props->qpic_version2) {
+ if (!nandc->props->has_onfi_read_op) {
qcom_write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0);
qcom_write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1,
NAND_BAM_NEXT_SGL);
@@ -2041,7 +2041,7 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
if (!nandc->props->nandc_part_of_qpic)
nandc_write(nandc, SFLASHC_BURST_CFG, 0);
- if (!nandc->props->qpic_version2)
+ if (!nandc->props->has_onfi_read_op)
nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
NAND_DEV_CMD_VLD_VAL);
@@ -2063,7 +2063,7 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
}
/* save the original values of these registers */
- if (!nandc->props->qpic_version2) {
+ if (!nandc->props->has_onfi_read_op) {
nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
nandc->vld = NAND_DEV_CMD_VLD_VAL;
}
@@ -2385,6 +2385,7 @@ static const struct qcom_nandc_props sdx55_nandc_props = {
.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
.supports_bam = true,
.nandc_part_of_qpic = true,
+ .has_onfi_read_op = true,
.qpic_version2 = true,
.dev_cmd_reg_start = 0x7000,
.bam_offset = 0x30000,
diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h
index 006ca8c978a9..437448995187 100644
--- a/include/linux/mtd/nand-qpic-common.h
+++ b/include/linux/mtd/nand-qpic-common.h
@@ -443,6 +443,7 @@ struct qcom_nand_controller {
* @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
* @supports_bam - whether NAND controller is using BAM
* @nandc_part_of_qpic - whether NAND controller is part of qpic IP
+ * @has_onfi_read_op - whether ONFI param page read command is supported
* @qpic_version2 - flag to indicate QPIC IP version 2
* @use_codeword_fixup - whether NAND has different layout for boot partitions
*/
@@ -452,6 +453,7 @@ struct qcom_nandc_props {
u32 bam_offset;
bool supports_bam;
bool nandc_part_of_qpic;
+ bool has_onfi_read_op;
bool qpic_version2;
bool use_codeword_fixup;
};
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH 3/4] mtd: rawnand: qcom: Make has_onfi_read_op separate from qpic_version2
2026-06-08 13:20 ` [PATCH 3/4] mtd: rawnand: qcom: Make has_onfi_read_op separate from qpic_version2 Stephan Gerhold
@ 2026-06-08 13:34 ` sashiko-bot
0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-06-08 13:34 UTC (permalink / raw)
To: Stephan Gerhold; +Cc: robh, devicetree, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Hardware initialization for `NAND_DEV_CMD_VLD` is incorrectly skipped for QPIC v1.5 controllers, potentially breaking all standard NAND operations.
--
commit 246019a946e357d7d6d6cced97c09e17d7879610
Author: Stephan Gerhold <stephan.gerhold@linaro.org>
mtd: rawnand: qcom: Make has_onfi_read_op separate from qpic_version2
This commit splits the OP_PAGE_READ_ONFI_READ support into a separate
has_onfi_read_op flag. This allows QPIC v1.5 controllers to utilize the
command without needing to enable all QPIC v2 hardware assumptions.
> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
> index 0251dd591d40a..9217e8de55129 100644
> --- a/drivers/mtd/nand/raw/qcom_nandc.c
> +++ b/drivers/mtd/nand/raw/qcom_nandc.c
[ ... ]
> @@ -2041,7 +2041,7 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
> if (!nandc->props->nandc_part_of_qpic)
> nandc_write(nandc, SFLASHC_BURST_CFG, 0);
>
> - if (!nandc->props->qpic_version2)
> + if (!nandc->props->has_onfi_read_op)
[Severity: High]
Will this skip the initialization of NAND_DEV_CMD_VLD for QPIC v1.5
controllers?
Since a QPIC v1.5 controller has has_onfi_read_op set to true but
qpic_version2 set to false, replacing the qpic_version2 check here means
the initialization will be bypassed.
Could this regression leave the hardware register in an undefined state and
prevent the controller from recognizing standard read, write, and erase
command start bits?
> nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
> NAND_DEV_CMD_VLD_VAL);
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260608-qcom-nandc-mdm9607-v1-0-4639a0492274@linaro.org?part=3
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 4/4] mtd: rawnand: qcom: Add MDM9607 compatible
2026-06-08 13:20 [PATCH 0/4] mtd: rawnand: qcom: Add MDM9607 Stephan Gerhold
` (2 preceding siblings ...)
2026-06-08 13:20 ` [PATCH 3/4] mtd: rawnand: qcom: Make has_onfi_read_op separate from qpic_version2 Stephan Gerhold
@ 2026-06-08 13:20 ` Stephan Gerhold
3 siblings, 0 replies; 7+ messages in thread
From: Stephan Gerhold @ 2026-06-08 13:20 UTC (permalink / raw)
To: Manivannan Sadhasivam, Miquel Raynal
Cc: Richard Weinberger, Vignesh Raghavendra, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-mtd, linux-arm-msm,
devicetree, linux-kernel
MDM9607 has QPIC v1.5 that supports the OP_PAGE_READ_ONFI_READ command, but
is missing the rest of the hardware changes in QPIC v2. Add the new
qcom,mdm9607-nand compatible and set it to use has_onfi_read_op without
also setting qpic_version2.
Signed-off-by: Stephan Gerhold <stephan.gerhold@linaro.org>
---
drivers/mtd/nand/raw/qcom_nandc.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index 9217e8de5512..d7642db2e2df 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2381,6 +2381,15 @@ static const struct qcom_nandc_props ipq8074_nandc_props = {
.bam_offset = 0x30000,
};
+static const struct qcom_nandc_props mdm9607_nandc_props = {
+ .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+ .supports_bam = true,
+ .nandc_part_of_qpic = true,
+ .has_onfi_read_op = true,
+ .dev_cmd_reg_start = 0x7000,
+ .bam_offset = 0x30000,
+};
+
static const struct qcom_nandc_props sdx55_nandc_props = {
.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
.supports_bam = true,
@@ -2412,6 +2421,10 @@ static const struct of_device_id qcom_nandc_of_match[] = {
.compatible = "qcom,ipq8074-nand",
.data = &ipq8074_nandc_props,
},
+ {
+ .compatible = "qcom,mdm9607-nand",
+ .data = &mdm9607_nandc_props,
+ },
{
.compatible = "qcom,sdx55-nand",
.data = &sdx55_nandc_props,
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread