* [PATCH RFC 0/2] remoteproc: qcom: wcss-sec: add IPQ8074 with a separate M3 image
@ 2026-10-25 4:20 John Macias
2026-10-25 4:20 ` [PATCH RFC 1/2] dt-bindings: remoteproc: qcom: wcss-sec: add IPQ8074 John Macias
2026-10-25 4:21 ` [PATCH RFC 2/2] remoteproc: qcom: wcss-sec: add IPQ8074 support John Macias
0 siblings, 2 replies; 3+ messages in thread
From: John Macias @ 2026-10-25 4:20 UTC (permalink / raw)
To: andersson, mathieu.poirier
Cc: robh, krzk+dt, conor+dt, manikanta.mylavarapu,
varadarajan.narayanan, linux-arm-msm, linux-remoteproc,
devicetree, linux-kernel
This adds IPQ8074 to the WCSS secure PIL driver, on top of v14 of
"Add new driver for WCSS secure PIL loading":
https://lore.kernel.org/all/20260803-rproc-v14-0-a1f87b0b0ad2@oss.qualcomm.com/
IPQ8074 needs the PRNG AHB clock, and its firmware ships the M3 image
separately from Q6 with its own load address. On the board I have, the
M3 image goes into its own reserved region with board data between the
two. Patch 1 lets IPQ8074 name its regions "q6" and "m3" and give a
second firmware name; patch 2 loads M3 into that region before the
authenticated Q6 image. Without memory-region-names nothing changes for
any compatible.
Testing:
- dt_binding_check (dtschema 2026.9) passes; the schema also rejects
named regions on other compatibles and a named IPQ8074 node with only
one region or one firmware name.
- arm64 W=1 build of the driver as a module, no warnings.
- Not booted in this form. The equivalent change on OpenWrt's earlier
copy of this driver has run on every boot of a Netgear RAX120 v1
(IPQ8074 hw1.0, WLAN.HK.2.0-01792-QCAHKSWPL_SILICONZ-1).
Varadarajan, would you rather fold this into your series, or should I
resend it once v14 is merged? I am happy to test either way on that
board.
This work was developed with AI assistance (Assisted-by tags on each
patch).
John Macias (2):
dt-bindings: remoteproc: qcom: wcss-sec: add IPQ8074
remoteproc: qcom: wcss-sec: add IPQ8074 support
.../remoteproc/qcom,ipq5018-wcss-sec-pil.yaml | 96 ++++++++++++++++--
drivers/remoteproc/qcom_q6v5_wcss_sec.c | 97 ++++++++++++++++++-
2 files changed, 184 insertions(+), 9 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH RFC 1/2] dt-bindings: remoteproc: qcom: wcss-sec: add IPQ8074
2026-10-25 4:20 [PATCH RFC 0/2] remoteproc: qcom: wcss-sec: add IPQ8074 with a separate M3 image John Macias
@ 2026-10-25 4:20 ` John Macias
2026-10-25 4:21 ` [PATCH RFC 2/2] remoteproc: qcom: wcss-sec: add IPQ8074 support John Macias
1 sibling, 0 replies; 3+ messages in thread
From: John Macias @ 2026-10-25 4:20 UTC (permalink / raw)
To: andersson, mathieu.poirier
Cc: robh, krzk+dt, conor+dt, manikanta.mylavarapu,
varadarajan.narayanan, linux-arm-msm, linux-remoteproc,
devicetree, linux-kernel
Document the IPQ8074 WCSS secure PIL. It needs the PRNG AHB clock, so
move the clock names from the top level into the per-compatible rules;
IPQ5018, IPQ5332 and IPQ9574 keep the same clock constraints.
IPQ8074 firmware ships the M3 image separately from Q6, with its own
load address, and some boards place it in its own reserved region with
board data between the two. Allow IPQ8074 to name its regions "q6" and
"m3" and to give the M3 firmware name as a second firmware-name entry.
Without memory-region-names a single region holds the firmware, as for
the other compatibles, which keep their existing constraints.
Assisted-by: LLM
Signed-off-by: John Macias <dencity7@gmail.com>
---
.../remoteproc/qcom,ipq5018-wcss-sec-pil.yaml | 96 +++++++++++++++++--
1 file changed, 88 insertions(+), 8 deletions(-)
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,ipq5018-wcss-sec-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,ipq5018-wcss-sec-pil.yaml
index 1ec8df60d..89d648769 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,ipq5018-wcss-sec-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,ipq5018-wcss-sec-pil.yaml
@@ -18,14 +18,17 @@ properties:
enum:
- qcom,ipq5018-wcss-sec-pil
- qcom,ipq5332-wcss-sec-pil
+ - qcom,ipq8074-wcss-sec-pil
- qcom,ipq9574-wcss-sec-pil
reg:
maxItems: 1
firmware-name:
- maxItems: 1
- description: Firmware name for the Hexagon core
+ minItems: 1
+ items:
+ - description: Firmware name for the Hexagon core
+ - description: Firmware name for the M3 core, loaded separately
interrupts:
items:
@@ -45,15 +48,11 @@ properties:
clocks:
minItems: 1
- items:
- - description: sleep clock
- - description: AHB interconnect clock
+ maxItems: 2
clock-names:
minItems: 1
- items:
- - const: sleep
- - const: interconnect
+ maxItems: 2
mboxes:
items:
@@ -74,8 +73,18 @@ properties:
- const: shutdown
memory-region:
+ minItems: 1
items:
- description: Q6 reserved region
+ - description: M3 reserved region
+
+ memory-region-names:
+ description:
+ Present only when the M3 firmware is loaded into its own reserved
+ region. Without it, a single region holds the firmware.
+ items:
+ - const: q6
+ - const: m3
glink-edge:
$ref: /schemas/remoteproc/qcom,glink-edge.yaml#
@@ -131,6 +140,40 @@ allOf:
- clocks
- clock-names
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: qcom,ipq8074-wcss-sec-pil
+ then:
+ properties:
+ clocks:
+ items:
+ - description: PRNG AHB clock
+ clock-names:
+ items:
+ - const: prng
+ required:
+ - clocks
+ - clock-names
+ else:
+ properties:
+ firmware-name:
+ maxItems: 1
+ memory-region:
+ maxItems: 1
+ memory-region-names: false
+
+ - if:
+ required:
+ - memory-region-names
+ then:
+ properties:
+ firmware-name:
+ minItems: 2
+ memory-region:
+ minItems: 2
+
- if:
properties:
compatible:
@@ -176,3 +219,40 @@ examples:
mboxes = <&apcs_glb 8>;
};
};
+
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ remoteproc@cd00000 {
+ compatible = "qcom,ipq8074-wcss-sec-pil";
+ reg = <0x0cd00000 0x4040>;
+ firmware-name = "ath11k/IPQ8074/hw1.0/q6_fw.mdt",
+ "ath11k/IPQ8074/hw1.0/m3_fw.mdt";
+ interrupts-extended = <&intc GIC_SPI 325 IRQ_TYPE_EDGE_RISING>,
+ <&wcss_smp2p_in 0 IRQ_TYPE_NONE>,
+ <&wcss_smp2p_in 1 IRQ_TYPE_NONE>,
+ <&wcss_smp2p_in 2 IRQ_TYPE_NONE>,
+ <&wcss_smp2p_in 3 IRQ_TYPE_NONE>;
+ interrupt-names = "wdog",
+ "fatal",
+ "ready",
+ "handover",
+ "stop-ack";
+
+ clocks = <&gcc 50>;
+ clock-names = "prng";
+
+ qcom,smem-states = <&wcss_smp2p_out 1>,
+ <&wcss_smp2p_out 0>;
+ qcom,smem-state-names = "stop",
+ "shutdown";
+ memory-region = <&q6_region>, <&m3_region>;
+ memory-region-names = "q6", "m3";
+
+ glink-edge {
+ interrupts = <GIC_SPI 321 IRQ_TYPE_EDGE_RISING>;
+ label = "rtr";
+ qcom,remote-pid = <1>;
+ mboxes = <&apcs_glb 8>;
+ };
+ };
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH RFC 2/2] remoteproc: qcom: wcss-sec: add IPQ8074 support
2026-10-25 4:20 [PATCH RFC 0/2] remoteproc: qcom: wcss-sec: add IPQ8074 with a separate M3 image John Macias
2026-10-25 4:20 ` [PATCH RFC 1/2] dt-bindings: remoteproc: qcom: wcss-sec: add IPQ8074 John Macias
@ 2026-10-25 4:21 ` John Macias
1 sibling, 0 replies; 3+ messages in thread
From: John Macias @ 2026-10-25 4:21 UTC (permalink / raw)
To: andersson, mathieu.poirier
Cc: robh, krzk+dt, conor+dt, manikanta.mylavarapu,
varadarajan.narayanan, linux-arm-msm, linux-remoteproc,
devicetree, linux-kernel
Add IPQ8074, which uses PAS ID 6 and needs the PRNG AHB clock enabled.
IPQ8074 firmware ships M3 as a separate image whose load address differs
from Q6's. When the node names its regions "q6" and "m3" and gives a
second firmware name, map the M3 region and load the M3 image into it
before the authenticated Q6 image, keeping the order the firmware has
been used with. Load M3 without updating the Q6 relocation base so
da_to_va() keeps translating Q6 addresses. A missing or failed M3 load
stops the Q6 load. Probe fails for a malformed named configuration
(wrong names or counts, a compatible without separate M3 support, or
overlapping regions) instead of picking a different loading policy.
Without memory-region-names nothing changes: extra regions remain
coredump-only.
Tested on a Netgear RAX120 v1 (IPQ8074 hw1.0, WLAN.HK.2.0-01792) only
with the equivalent change on OpenWrt's earlier copy of this driver.
Assisted-by: LLM
Signed-off-by: John Macias <dencity7@gmail.com>
---
drivers/remoteproc/qcom_q6v5_wcss_sec.c | 97 ++++++++++++++++++++++++-
1 file changed, 96 insertions(+), 1 deletion(-)
diff --git a/drivers/remoteproc/qcom_q6v5_wcss_sec.c b/drivers/remoteproc/qcom_q6v5_wcss_sec.c
index 4837825d1..a4ebb79d0 100644
--- a/drivers/remoteproc/qcom_q6v5_wcss_sec.c
+++ b/drivers/remoteproc/qcom_q6v5_wcss_sec.c
@@ -7,6 +7,7 @@
#include <linux/io.h>
#include <linux/mailbox_client.h>
#include <linux/of_reserved_mem.h>
+#include <linux/overflow.h>
#include <linux/platform_device.h>
#include <linux/soc/qcom/mdt_loader.h>
@@ -30,6 +31,10 @@ struct wcss_sec {
phys_addr_t mem_reloc;
void *mem_region;
size_t mem_size;
+ phys_addr_t m3_phys;
+ void *m3_region;
+ size_t m3_size;
+ const char *m3_fw_name;
const struct wcss_data *desc;
};
@@ -37,6 +42,7 @@ struct wcss_data {
u32 pasid;
const char *ss_name;
bool auto_boot;
+ bool separate_m3;
};
static int wcss_sec_start(struct rproc *rproc)
@@ -106,12 +112,43 @@ static void *wcss_sec_da_to_va(struct rproc *rproc, u64 da, size_t len,
return wcss->mem_region + offset;
}
+/*
+ * IPQ8074 firmware ships M3 as a separate image with its own load address.
+ * Load it into its own reserved region before the authenticated Q6 image.
+ */
+static int wcss_sec_load_m3(struct wcss_sec *wcss)
+{
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, wcss->m3_fw_name, wcss->dev);
+ if (ret)
+ return ret;
+
+ /* M3 relocation must not overwrite Q6's da_to_va translation base. */
+ ret = qcom_mdt_load_no_init(wcss->dev, fw, wcss->m3_fw_name,
+ wcss->m3_region, wcss->m3_phys,
+ wcss->m3_size, NULL);
+ release_firmware(fw);
+
+ return ret;
+}
+
static int wcss_sec_load(struct rproc *rproc, const struct firmware *fw)
{
struct wcss_sec *wcss = rproc->priv;
struct device *dev = wcss->dev;
int ret;
+ if (wcss->m3_region) {
+ ret = wcss_sec_load_m3(wcss);
+ if (ret) {
+ dev_err(dev, "unable to load M3 firmware: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+ }
+
ret = qcom_mdt_load(dev, fw, rproc->firmware, wcss->desc->pasid, wcss->mem_region,
wcss->mem_phys, wcss->mem_size, &wcss->mem_reloc);
if (ret)
@@ -206,6 +243,51 @@ static const struct rproc_ops wcss_sec_ops = {
.parse_fw = wcss_sec_dump_segments,
};
+static int wcss_sec_alloc_m3_region(struct wcss_sec *wcss)
+{
+ struct device *dev = wcss->dev;
+ struct device_node *np = dev->of_node;
+ phys_addr_t q6_end, m3_end;
+ struct resource res;
+ int ret;
+
+ /* Unnamed extra regions keep their existing coredump-only meaning. */
+ if (!of_property_present(np, "memory-region-names"))
+ return 0;
+
+ if (!wcss->desc->separate_m3 ||
+ of_property_count_strings(np, "memory-region-names") != 2 ||
+ of_property_match_string(np, "memory-region-names", "q6") != 0 ||
+ of_property_match_string(np, "memory-region-names", "m3") != 1 ||
+ of_reserved_mem_region_count(np) != 2 ||
+ of_property_read_string_index(np, "firmware-name", 1,
+ &wcss->m3_fw_name))
+ return dev_err_probe(dev, -EINVAL,
+ "invalid separate M3 configuration\n");
+
+ ret = of_reserved_mem_region_to_resource(np, 1, &res);
+ if (ret)
+ return dev_err_probe(dev, ret, "unable to acquire M3 region\n");
+
+ if (!wcss->mem_size || !resource_size(&res) ||
+ check_add_overflow(wcss->mem_phys, (phys_addr_t)wcss->mem_size,
+ &q6_end) ||
+ check_add_overflow((phys_addr_t)res.start,
+ (phys_addr_t)resource_size(&res), &m3_end) ||
+ (wcss->mem_phys < m3_end && res.start < q6_end))
+ return dev_err_probe(dev, -EINVAL,
+ "invalid or overlapping Q6/M3 regions\n");
+
+ wcss->m3_phys = res.start;
+ wcss->m3_size = resource_size(&res);
+ wcss->m3_region = devm_ioremap_resource_wc(dev, &res);
+ if (IS_ERR(wcss->m3_region))
+ return dev_err_probe(dev, PTR_ERR(wcss->m3_region),
+ "unable to map M3 region %pR\n", &res);
+
+ return 0;
+}
+
static int wcss_sec_alloc_memory_region(struct wcss_sec *wcss)
{
struct device *dev = wcss->dev;
@@ -227,7 +309,7 @@ static int wcss_sec_alloc_memory_region(struct wcss_sec *wcss)
return PTR_ERR(wcss->mem_region);
}
- return 0;
+ return wcss_sec_alloc_m3_region(wcss);
}
static int wcss_sec_probe(struct platform_device *pdev)
@@ -237,6 +319,7 @@ static int wcss_sec_probe(struct platform_device *pdev)
struct wcss_sec *wcss;
struct clk *sleep_clk;
struct clk *int_clk;
+ struct clk *prng_clk;
struct rproc *rproc;
int ret;
@@ -270,6 +353,11 @@ static int wcss_sec_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(int_clk),
"Failed to get interconnect clock\n");
+ prng_clk = devm_clk_get_optional_enabled(&pdev->dev, "prng");
+ if (IS_ERR(prng_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(prng_clk),
+ "Failed to get prng clock\n");
+
ret = qcom_q6v5_init(&wcss->q6, pdev, rproc,
WCSS_CRASH_REASON, NULL, NULL);
if (ret)
@@ -310,6 +398,12 @@ static const struct wcss_data wcss_sec_ipq5332_res_init = {
.ss_name = "q6wcss",
};
+static const struct wcss_data wcss_sec_ipq8074_res_init = {
+ .pasid = WCSS_PAS_ID,
+ .ss_name = "q6wcss",
+ .separate_m3 = true,
+};
+
static const struct wcss_data wcss_sec_ipq9574_res_init = {
.pasid = WCSS_PAS_ID,
.ss_name = "q6wcss",
@@ -318,6 +412,7 @@ static const struct wcss_data wcss_sec_ipq9574_res_init = {
static const struct of_device_id wcss_sec_of_match[] = {
{ .compatible = "qcom,ipq5018-wcss-sec-pil", .data = &wcss_sec_ipq5332_res_init },
{ .compatible = "qcom,ipq5332-wcss-sec-pil", .data = &wcss_sec_ipq5332_res_init },
+ { .compatible = "qcom,ipq8074-wcss-sec-pil", .data = &wcss_sec_ipq8074_res_init },
{ .compatible = "qcom,ipq9574-wcss-sec-pil", .data = &wcss_sec_ipq9574_res_init },
{ },
};
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-25 4:21 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-25 4:20 [PATCH RFC 0/2] remoteproc: qcom: wcss-sec: add IPQ8074 with a separate M3 image John Macias
2026-10-25 4:20 ` [PATCH RFC 1/2] dt-bindings: remoteproc: qcom: wcss-sec: add IPQ8074 John Macias
2026-10-25 4:21 ` [PATCH RFC 2/2] remoteproc: qcom: wcss-sec: add IPQ8074 support John Macias
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®