From 70eaa8efaa4c6f5196c4151f865d29c5ec3e5004 Mon Sep 17 00:00:00 2001 From: Soham Metha Date: Wed, 3 Dec 2025 23:33:37 +0530 Subject: [PATCH 01/20] dt-bindings: remoteproc: Fix dead link to Keystone DSP GPIO binding The old text binding 'gpio-dsp-keystone.txt' was replaced by a DT schema in commit aff0a1701b020c8e6b172f28828fd4f3e6eed41a ("dt-bindings: gpio: Convert ti,keystone-dsp-gpio to DT schema"). Update the reference to point to the new file. Signed-off-by: Soham Metha Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20251203180337.50831-1-sohammetha01@gmail.com Signed-off-by: Mathieu Poirier --- .../devicetree/bindings/remoteproc/ti,keystone-rproc.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/remoteproc/ti,keystone-rproc.txt b/Documentation/devicetree/bindings/remoteproc/ti,keystone-rproc.txt index 463a97c11eff..91f0a3b0c0b2 100644 --- a/Documentation/devicetree/bindings/remoteproc/ti,keystone-rproc.txt +++ b/Documentation/devicetree/bindings/remoteproc/ti,keystone-rproc.txt @@ -66,7 +66,7 @@ The following are the mandatory properties: - kick-gpios: Should specify the gpio device needed for the virtio IPC stack. This will be used to interrupt the remote processor. The gpio device to be used is as per the bindings in, - Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt + Documentation/devicetree/bindings/gpio/ti,keystone-dsp-gpio.yaml SoC-specific Required properties: --------------------------------- From d62e0e92e589c53c4320ed5914af5fe103f5ce7e Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Thu, 4 Dec 2025 14:28:23 +0200 Subject: [PATCH 02/20] remoteproc: imx_dsp_rproc: Skip RP_MBOX_SUSPEND_SYSTEM when mailbox TX channel is uninitialized Firmwares that do not use mailbox communication (e.g., the hello_world sample) leave priv->tx_ch as NULL. The current suspend logic unconditionally sends RP_MBOX_SUSPEND_SYSTEM, which is invalid without an initialized TX channel. Detect the no_mailboxes case early and skip sending the suspend message. Instead, proceed directly to the runtime PM suspend path, which is the correct behavior for firmwares that cannot respond to mailbox requests. Signed-off-by: Iuliana Prodan Link: https://lore.kernel.org/r/20251204122825.756106-1-iuliana.prodan@oss.nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_dsp_rproc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index 5130a35214c9..f51deaacc700 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -1242,6 +1242,15 @@ static int imx_dsp_suspend(struct device *dev) if (rproc->state != RPROC_RUNNING) goto out; + /* + * No channel available for sending messages; + * indicates no mailboxes present, so trigger PM runtime suspend + */ + if (!priv->tx_ch) { + dev_dbg(dev, "No initialized mbox tx channel, suspend directly.\n"); + goto out; + } + reinit_completion(&priv->pm_comp); /* Tell DSP that suspend is happening */ From 424f22b48ca38f2071c9dab6ac733f79542c98c5 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Thu, 4 Dec 2025 14:28:24 +0200 Subject: [PATCH 03/20] remoteproc: imx_dsp_rproc: Rename macro to reflect multiple contexts Rename WAIT_FW_READY to WAIT_FW_CONFIRMATION and FEATURE_DONT_WAIT_FW_READY to FEATURE_SKIP_FW_CONFIRMATION. This way, the term CONFIRMATION covers: - waiting for firmware to confirm it is ready to start; - waiting for any other confirmation from firmware. Signed-off-by: Iuliana Prodan Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/20251204122825.756106-2-iuliana.prodan@oss.nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_dsp_rproc.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index f51deaacc700..1f3a35756769 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -38,15 +38,15 @@ MODULE_PARM_DESC(no_mailboxes, /* Flag indicating that the remote is up and running */ #define REMOTE_IS_READY BIT(0) -/* Flag indicating that the host should wait for a firmware-ready response */ -#define WAIT_FW_READY BIT(1) +/* Flag indicating that the host should wait for a firmware-confirmation response */ +#define WAIT_FW_CONFIRMATION BIT(1) #define REMOTE_READY_WAIT_MAX_RETRIES 500 /* * This flag is set in the DSP resource table's features field to indicate - * that the firmware requires the host NOT to wait for a FW_READY response. + * that the firmware requires the host NOT to wait for a FW_CONFIRMATION response. */ -#define FEATURE_DONT_WAIT_FW_READY BIT(0) +#define FEATURE_SKIP_FW_CONFIRMATION BIT(0) /* att flags */ /* DSP own area */ @@ -287,7 +287,7 @@ static int imx_dsp_rproc_ready(struct rproc *rproc) * @avail: available space in the resource table * * Parse the DSP-specific resource entry and update flags accordingly. - * If the WAIT_FW_READY feature is set, the host must wait for the firmware + * If the WAIT_FW_CONFIRMATION feature is set, the host must wait for the firmware * to signal readiness before proceeding with execution. * * Return: RSC_HANDLED if processed successfully, RSC_IGNORED otherwise. @@ -322,7 +322,7 @@ static int imx_dsp_rproc_handle_rsc(struct rproc *rproc, u32 rsc_type, /* * For now, in struct fw_rsc_imx_dsp, version 0, - * only FEATURE_DONT_WAIT_FW_READY is valid. + * only FEATURE_SKIP_FW_CONFIRMATION is valid. * * When adding new features, please upgrade version. */ @@ -332,8 +332,8 @@ static int imx_dsp_rproc_handle_rsc(struct rproc *rproc, u32 rsc_type, return RSC_IGNORED; } - if (imx_dsp_rsc->features & FEATURE_DONT_WAIT_FW_READY) - priv->flags &= ~WAIT_FW_READY; + if (imx_dsp_rsc->features & FEATURE_SKIP_FW_CONFIRMATION) + priv->flags &= ~WAIT_FW_CONFIRMATION; return RSC_HANDLED; } @@ -385,7 +385,7 @@ static int imx_dsp_rproc_start(struct rproc *rproc) return ret; } - if (priv->flags & WAIT_FW_READY) + if (priv->flags & WAIT_FW_CONFIRMATION) return imx_dsp_rproc_ready(rproc); return 0; @@ -1131,8 +1131,8 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev) priv = rproc->priv; priv->rproc = rproc; priv->dsp_dcfg = dsp_dcfg; - /* By default, host waits for fw_ready reply */ - priv->flags |= WAIT_FW_READY; + /* By default, host waits for fw_confirmation reply */ + priv->flags |= WAIT_FW_CONFIRMATION; if (no_mailboxes) imx_dsp_rproc_mbox_init = imx_dsp_rproc_mbox_no_alloc; From 4200f873c4c4c35befca288fd299a41f9544cece Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Thu, 4 Dec 2025 14:28:25 +0200 Subject: [PATCH 04/20] remoteproc: imx_dsp_rproc: Wait for suspend ACK only if WAIT_FW_CONFIRMATION is set The DSP suspend path currently waits unconditionally for a suspend ack from the firmware. This breaks firmwares that do not implement the mailbox-based CONFIRMATION handshake, as the DSP never responds and system suspend fails with -EBUSY. The driver already uses the WAIT_FW_CONFIRMATION flag to indicate that the firmware supports the CONFIRMATION handshake at boot. Apply the same logic during suspend: only send the suspend message and wait for the suspend ack when the firmware is expected to support it. Signed-off-by: Iuliana Prodan Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/20251204122825.756106-3-iuliana.prodan@oss.nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_dsp_rproc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index 1f3a35756769..d03017d6b214 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -1251,6 +1251,12 @@ static int imx_dsp_suspend(struct device *dev) goto out; } + /* No fw confirmation expected, so trigger PM runtime suspend */ + if (!(priv->flags & WAIT_FW_CONFIRMATION)) { + dev_dbg(dev, "No FW_CONFIRMATION needed, suspend directly.\n"); + goto out; + } + reinit_completion(&priv->pm_comp); /* Tell DSP that suspend is happening */ From 93f51b9182a107cf5f5e8a7802cd90df0c9a7154 Mon Sep 17 00:00:00 2001 From: Shenwei Wang Date: Mon, 8 Dec 2025 17:33:02 -0600 Subject: [PATCH 05/20] remoteproc: imx_rproc: Use strstarts for "rsc-table" check The resource name may include an address suffix, for example: rsc-table@1fff8000. To handle such cases, use strstarts() instead of strcmp() when checking for "rsc-table". Signed-off-by: Shenwei Wang Reviewed-by: Daniel Baluta Reviewed-by: Frank Li Reviewed-by: Zhongqiu Han Reviewed-by: Peng Fan Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"") Link: https://lore.kernel.org/r/20251208233302.684139-1-shenwei.wang@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 3be8790c14a2..33f21ab24c92 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -694,7 +694,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, } priv->mem[b].sys_addr = res.start; priv->mem[b].size = resource_size(&res); - if (!strcmp(res.name, "rsc-table")) + if (strstarts(res.name, "rsc-table")) priv->rsc_table = priv->mem[b].cpu_addr; b++; } From a84a1e21c0678032f1185173f816cbb500a87877 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 10 Dec 2025 17:49:06 +0200 Subject: [PATCH 06/20] remoteproc: imx_dsp_rproc: Fix multiple start/stop operations After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_* functions for "memory-region"") following commands with imx-dsp-rproc started to fail: $ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware $ echo start > /sys/class/remoteproc/remoteproc0/state $ echo stop > /sys/class/remoteproc/remoteproc0/state $ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails -sh: echo: write error: Device or resource busy This happens because aforementioned commit replaced devm_ioremap_wc with devm_ioremap_resource_wc which will "reserve" the memory region with the first start and then will fail at the second start if the memory region is already reserved. Even partially reverting the faulty commit won't fix the underlying issue because we map the address in prepare() but we never unmap it at unprepare(), so we will keep leaking memory regions. So, lets use alloc() and release() callbacks for memory carveout handling. This will nicely map() the memory region at prepare() time and unmap() it at unprepare(). Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"") Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20251210154906.99210-1-daniel.baluta@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_dsp_rproc.c | 50 ++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index d03017d6b214..8426d7af9c75 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -644,6 +644,32 @@ static void imx_dsp_rproc_free_mbox(struct imx_dsp_rproc *priv) mbox_free_channel(priv->rxdb_ch); } +static int imx_dsp_rproc_mem_alloc(struct rproc *rproc, + struct rproc_mem_entry *mem) +{ + struct device *dev = rproc->dev.parent; + void *va; + + va = ioremap_wc(mem->dma, mem->len); + if (!va) { + dev_err(dev, "Unable to map memory region: %pa+%zx\n", + &mem->dma, mem->len); + return -ENOMEM; + } + + mem->va = va; + + return 0; +} + +static int imx_dsp_rproc_mem_release(struct rproc *rproc, + struct rproc_mem_entry *mem) +{ + iounmap(mem->va); + + return 0; +} + /** * imx_dsp_rproc_add_carveout() - request mailbox channels * @priv: private data pointer @@ -659,7 +685,6 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv) struct device *dev = rproc->dev.parent; struct device_node *np = dev->of_node; struct rproc_mem_entry *mem; - void __iomem *cpu_addr; int a, i = 0; u64 da; @@ -673,15 +698,10 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv) if (imx_dsp_rproc_sys_to_da(priv, att->sa, att->size, &da)) return -EINVAL; - cpu_addr = devm_ioremap_wc(dev, att->sa, att->size); - if (!cpu_addr) { - dev_err(dev, "failed to map memory %p\n", &att->sa); - return -ENOMEM; - } - /* Register memory region */ - mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa, - att->size, da, NULL, NULL, "dsp_mem"); + mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)att->sa, + att->size, da, imx_dsp_rproc_mem_alloc, + imx_dsp_rproc_mem_release, "dsp_mem"); if (mem) rproc_coredump_add_segment(rproc, da, att->size); @@ -709,15 +729,11 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv) if (imx_dsp_rproc_sys_to_da(priv, res.start, resource_size(&res), &da)) return -EINVAL; - cpu_addr = devm_ioremap_resource_wc(dev, &res); - if (IS_ERR(cpu_addr)) { - dev_err(dev, "failed to map memory %pR\n", &res); - return PTR_ERR(cpu_addr); - } - /* Register memory region */ - mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)res.start, - resource_size(&res), da, NULL, NULL, + mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)res.start, + resource_size(&res), da, + imx_dsp_rproc_mem_alloc, + imx_dsp_rproc_mem_release, "%.*s", strchrnul(res.name, '@') - res.name, res.name); if (!mem) return -ENOMEM; From 2cb0c97ce4392d1b76c178bf7c6613b4e89a4b19 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 29 Dec 2025 16:26:59 +0100 Subject: [PATCH 07/20] dt-bindings: remoteproc: qcom,adsp: Allow cx-supply on qcom,sdm845-slpi-pas One SDM845 board uses cx-supply, which is not allowed by the bindings, as reported by dtbs_check: sdm845-samsung-starqltechn.dtb: remoteproc@5c00000 (qcom,sdm845-slpi-pas): Unevaluated properties are not allowed ('cx-supply' was unexpected) The SDM845 SLPI binding already allows lcx and lmx domains, thus the cx-supply seems like a fake name for something else, e.g. some enable pin. The qcom_q6v5_pas.c driver parses cx-supply, so it is an established ABI, therefore document it for this device only. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20251229152658.284199-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml index 137f95028313..16a245fe2738 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml @@ -32,6 +32,8 @@ properties: reg: maxItems: 1 + cx-supply: true + px-supply: description: Phandle to the PX regulator @@ -159,6 +161,9 @@ allOf: items: - const: lcx - const: lmx + else: + properties: + cx-supply: false - if: properties: From 332c03279bc81a1a88d8dc5dd23f3c956d99d882 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 23 Dec 2025 14:05:34 +0100 Subject: [PATCH 08/20] dt-bindings: remoteproc: qcom,sm8550-pas: Drop SM8750 ADSP from if-branch The binding for SM8750 ADSP PAS uses SM8550 ADSP as fallback, thus "if:then:" block with "contains:" and the fallback does not need to mention qcom,sm8750-adsp-pas. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20251223130533.58468-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml index 2dd479cf4821..11b056d6a480 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml @@ -187,7 +187,6 @@ allOf: enum: - qcom,sm8550-adsp-pas - qcom,sm8650-adsp-pas - - qcom,sm8750-adsp-pas - qcom,x1e80100-adsp-pas then: properties: From b490ddf27be28e64a39c08ae643d7b22561beaf6 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 18 Dec 2025 15:17:50 +0800 Subject: [PATCH 09/20] remoteproc: imx_dsp_rproc: Only reset carveout memory at RPROC_OFFLINE state Do not reset memory at suspend and resume stage, because some memory is used to save the software state for resume, if it is cleared, the resume operation can fail. Fixes: c4c432dfb00f ("remoteproc: imx_dsp_rproc: Add support of recovery and coredump process") Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta Reviewed-by: Iuliana Prodan Link: https://lore.kernel.org/r/20251218071750.2692132-1-shengjiu.wang@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_dsp_rproc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index 8426d7af9c75..008741af9f11 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -1000,9 +1000,11 @@ static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw) * Clear buffers after pm rumtime for internal ocram is not * accessible if power and clock are not enabled. */ - list_for_each_entry(carveout, &rproc->carveouts, node) { - if (carveout->va) - memset(carveout->va, 0, carveout->len); + if (rproc->state == RPROC_OFFLINE) { + list_for_each_entry(carveout, &rproc->carveouts, node) { + if (carveout->va) + memset(carveout->va, 0, carveout->len); + } } ret = imx_dsp_rproc_elf_load_segments(rproc, fw); From 6d183d0530b5dc77ddd7d829bdfcb62a365a210f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 2 Jan 2026 13:48:28 +0100 Subject: [PATCH 10/20] remoteproc: mtk_scp: Simplify with scoped for each OF child loop Use scoped for-each loop when iterating over device nodes to make code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260102124827.64355-3-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index db8fd045468d..328541e62158 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -1287,7 +1287,6 @@ static int scp_add_multi_core(struct platform_device *pdev, struct device *dev = &pdev->dev; struct device_node *np = dev_of_node(dev); struct platform_device *cpdev; - struct device_node *child; struct list_head *scp_list = &scp_cluster->mtk_scp_list; const struct mtk_scp_of_data **cluster_of_data; struct mtk_scp *scp, *temp; @@ -1296,11 +1295,10 @@ static int scp_add_multi_core(struct platform_device *pdev, cluster_of_data = (const struct mtk_scp_of_data **)of_device_get_match_data(dev); - for_each_available_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { if (!cluster_of_data[core_id]) { ret = -EINVAL; dev_err(dev, "Not support core %d\n", core_id); - of_node_put(child); goto init_fail; } @@ -1308,7 +1306,6 @@ static int scp_add_multi_core(struct platform_device *pdev, if (!cpdev) { ret = -ENODEV; dev_err(dev, "Not found platform device for core %d\n", core_id); - of_node_put(child); goto init_fail; } @@ -1317,14 +1314,12 @@ static int scp_add_multi_core(struct platform_device *pdev, if (IS_ERR(scp)) { ret = PTR_ERR(scp); dev_err(dev, "Failed to initialize core %d rproc\n", core_id); - of_node_put(child); goto init_fail; } ret = rproc_add(scp->rproc); if (ret) { dev_err(dev, "Failed to add rproc of core %d\n", core_id); - of_node_put(child); scp_free(scp); goto init_fail; } From 88c31f1b31aec2d73261d9565f870e8d14974543 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 2 Jan 2026 13:48:29 +0100 Subject: [PATCH 11/20] remoteproc: xlnx_r5: Simplify with scoped for each OF child loop Use scoped for-each loop when iterating over device nodes to make code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260102124827.64355-4-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/xlnx_r5_remoteproc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index a7b75235f53e..bd619a6c42aa 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -1271,7 +1271,6 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) struct zynqmp_r5_core **r5_cores; enum rpu_oper_mode fw_reg_val; struct device **child_devs; - struct device_node *child; enum rpu_tcm_comb tcm_mode; int core_count, ret, i; struct mbox_info *ipi; @@ -1350,10 +1349,9 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) } i = 0; - for_each_available_child_of_node(dev_node, child) { + for_each_available_child_of_node_scoped(dev_node, child) { child_pdev = of_find_device_by_node(child); if (!child_pdev) { - of_node_put(child); ret = -ENODEV; goto release_r5_cores; } @@ -1363,7 +1361,6 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) /* create and add remoteproc instance of type struct rproc */ r5_cores[i] = zynqmp_r5_add_rproc_core(&child_pdev->dev); if (IS_ERR(r5_cores[i])) { - of_node_put(child); ret = PTR_ERR(r5_cores[i]); r5_cores[i] = NULL; goto release_r5_cores; @@ -1383,10 +1380,8 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) * If two child nodes are available in dts in lockstep mode, * then ignore second child node. */ - if (cluster_mode == LOCKSTEP_MODE) { - of_node_put(child); + if (cluster_mode == LOCKSTEP_MODE) break; - } i++; } From 4df89cb826e0a2d5986a555703af1f98688ca2bf Mon Sep 17 00:00:00 2001 From: Beleswar Padhi Date: Tue, 6 Jan 2026 16:17:53 +0530 Subject: [PATCH 12/20] dt-bindings: remoteproc: Add HSM M4F core on TI K3 SoCs Some of the TI K3 family of SoCs have a HSM (High Security Module) M4F core in the Wakeup Voltage Domain which could be used to run secure services like Authentication. Add the device tree bindings document for this HSM M4F core. The added example illustrates the DT node for the HSM core present on K3 J722S SoC. Signed-off-by: Beleswar Padhi Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260106104755.948086-2-b-padhi@ti.com Signed-off-by: Mathieu Poirier --- .../bindings/remoteproc/ti,hsm-m4fss.yaml | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/remoteproc/ti,hsm-m4fss.yaml diff --git a/Documentation/devicetree/bindings/remoteproc/ti,hsm-m4fss.yaml b/Documentation/devicetree/bindings/remoteproc/ti,hsm-m4fss.yaml new file mode 100644 index 000000000000..9244e60acee3 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/ti,hsm-m4fss.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/ti,hsm-m4fss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI K3 HSM M4F processor subsystems + +maintainers: + - Beleswar Padhi + +description: | + Some K3 family SoCs have a HSM (High Security Module) M4F core in the + Wakeup Voltage Domain which could be used to run secure services like + Authentication. Some of those are J721S2, J784S4, J722S, AM62X. + +$ref: /schemas/arm/keystone/ti,k3-sci-common.yaml# + +properties: + compatible: + enum: + - ti,hsm-m4fss + + reg: + items: + - description: SRAM0_0 internal memory region + - description: SRAM0_1 internal memory region + - description: SRAM1 internal memory region + + reg-names: + items: + - const: sram0_0 + - const: sram0_1 + - const: sram1 + + resets: + maxItems: 1 + + firmware-name: + maxItems: 1 + +required: + - compatible + - reg + - reg-names + - resets + - firmware-name + - ti,sci + - ti,sci-dev-id + - ti,sci-proc-ids + +unevaluatedProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + remoteproc@43c00000 { + compatible = "ti,hsm-m4fss"; + reg = <0x00 0x43c00000 0x00 0x20000>, + <0x00 0x43c20000 0x00 0x10000>, + <0x00 0x43c30000 0x00 0x10000>; + reg-names = "sram0_0", "sram0_1", "sram1"; + resets = <&k3_reset 225 1>; + firmware-name = "hsm.bin"; + ti,sci = <&sms>; + ti,sci-dev-id = <225>; + ti,sci-proc-ids = <0x80 0xff>; + }; + }; From ac3ea0730a1380f00109e69149f3be1a058c4ba9 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 9 Jan 2026 20:08:01 +0800 Subject: [PATCH 13/20] dt-bindings: remoteproc: fsl,imx-rproc: Add support for i.MX95 Add compatible string for the Cortex-M7 core in i.MX95 Reviewed-by: Frank Li Acked-by: Krzysztof Kozlowski Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20260109-imx95-rproc-2026-1-8-v6-1-d2fefb36263d@nxp.com Signed-off-by: Mathieu Poirier --- Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml index 57d75acb0b5e..ce8ec0119469 100644 --- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml @@ -28,6 +28,7 @@ properties: - fsl,imx8qxp-cm4 - fsl,imx8ulp-cm33 - fsl,imx93-cm33 + - fsl,imx95-cm7 clocks: maxItems: 1 From 454cb78611479bd5da4f191480456f42aca7f07b Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 9 Jan 2026 20:08:02 +0800 Subject: [PATCH 14/20] remoteproc: imx_rproc: Add runtime ops copy to support dynamic behavior Structure imx_rproc_dcfg contains a const pointer to imx_rproc_plat_ops, which defines the start/stop/detect_mode operations for a remote processor. To preserve the const correctness of the static configuration while allowing runtime modification of ops behavior, introduce a new imx_rproc_plat_ops member in struct imx_rproc named `ops`. During initialization, dcfg->ops is assigned to priv->ops. Enable the driver to safely override ops at runtime without affecting the original const configuration. Improve flexibility for platforms that require dynamic operation switching (e.g. i.MX95 Logical Machine ops and CPU ops). Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20260109-imx95-rproc-2026-1-8-v6-2-d2fefb36263d@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 33f21ab24c92..78659c8fb84d 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -116,6 +116,7 @@ struct imx_rproc { u32 entry; /* cpu start address */ u32 core_index; struct dev_pm_domain_list *pd_list; + const struct imx_rproc_plat_ops *ops; }; static const struct imx_rproc_att imx_rproc_att_imx93[] = { @@ -315,7 +316,6 @@ static int imx_rproc_scu_api_start(struct rproc *rproc) static int imx_rproc_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; - const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; int ret; @@ -323,10 +323,10 @@ static int imx_rproc_start(struct rproc *rproc) if (ret) return ret; - if (!dcfg->ops || !dcfg->ops->start) + if (!priv->ops || !priv->ops->start) return -EOPNOTSUPP; - ret = dcfg->ops->start(rproc); + ret = priv->ops->start(rproc); if (ret) dev_err(dev, "Failed to enable remote core!\n"); @@ -372,14 +372,13 @@ static int imx_rproc_scu_api_stop(struct rproc *rproc) static int imx_rproc_stop(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; - const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; int ret; - if (!dcfg->ops || !dcfg->ops->stop) + if (!priv->ops || !priv->ops->stop) return -EOPNOTSUPP; - ret = dcfg->ops->stop(rproc); + ret = priv->ops->stop(rproc); if (ret) dev_err(dev, "Failed to stop remote core\n"); else @@ -584,12 +583,11 @@ static int imx_rproc_scu_api_detach(struct rproc *rproc) static int imx_rproc_detach(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; - const struct imx_rproc_dcfg *dcfg = priv->dcfg; - if (!dcfg->ops || !dcfg->ops->detach) + if (!priv->ops || !priv->ops->detach) return -EOPNOTSUPP; - return dcfg->ops->detach(rproc); + return priv->ops->detach(rproc); } static struct resource_table *imx_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz) @@ -979,18 +977,16 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc) static int imx_rproc_detect_mode(struct imx_rproc *priv) { - const struct imx_rproc_dcfg *dcfg = priv->dcfg; - /* * To i.MX{7,8} ULP, Linux is under control of RTOS, no need - * dcfg->ops or dcfg->ops->detect_mode, it is state RPROC_DETACHED. + * priv->ops or priv->ops->detect_mode, it is state RPROC_DETACHED. */ - if (!dcfg->ops || !dcfg->ops->detect_mode) { + if (!priv->ops || !priv->ops->detect_mode) { priv->rproc->state = RPROC_DETACHED; return 0; } - return dcfg->ops->detect_mode(priv->rproc); + return priv->ops->detect_mode(priv->rproc); } static int imx_rproc_sys_off_handler(struct sys_off_data *data) @@ -1040,6 +1036,9 @@ static int imx_rproc_probe(struct platform_device *pdev) priv->dcfg = dcfg; priv->dev = dev; + if (dcfg->ops) + priv->ops = dcfg->ops; + dev_set_drvdata(dev, rproc); priv->workqueue = create_workqueue(dev_name(dev)); if (!priv->workqueue) { From edd2a9956055ecb50e230cd02c7791205fc8d009 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 9 Jan 2026 20:08:03 +0800 Subject: [PATCH 15/20] remoteproc: imx_rproc: Introduce prepare ops for imx_rproc_dcfg Allow each platform to provide its own prepare operations, preparing for i.MX95 LMM and CPU ops support. No functional changes. Reviewed-by: Daniel Baluta Reviewed-by: Frank Li Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20260109-imx95-rproc-2026-1-8-v6-3-d2fefb36263d@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 5 +++++ drivers/remoteproc/imx_rproc.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 78659c8fb84d..b0857a1a9660 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -527,6 +527,11 @@ static int imx_rproc_prepare(struct rproc *rproc) rproc_coredump_add_segment(rproc, da, resource_size(&res)); rproc_add_carveout(rproc, mem); } + + if (priv->ops && priv->ops->prepare) + return priv->ops->prepare(rproc); + + return 0; } static int imx_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h index 1b2d9f4d6d19..37417568a0ad 100644 --- a/drivers/remoteproc/imx_rproc.h +++ b/drivers/remoteproc/imx_rproc.h @@ -24,6 +24,7 @@ struct imx_rproc_plat_ops { int (*stop)(struct rproc *rproc); int (*detach)(struct rproc *rproc); int (*detect_mode)(struct rproc *rproc); + int (*prepare)(struct rproc *rproc); }; struct imx_rproc_dcfg { From d8ab94fa4370337158e96ea08d41e6e2d8fcb2a2 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 9 Jan 2026 20:08:04 +0800 Subject: [PATCH 16/20] remoteproc: imx_rproc: Add support for System Manager LMM API i.MX95 features a Cortex-M33 core, six Cortex-A55 cores, and one Cortex-M7 core. The System Control Management Interface(SCMI) firmware runs on the M33 core. The i.MX95 SCMI firmware named System Manager(SM) includes vendor extension protocols, Logical Machine Management(LMM) protocol and CPU protocol and etc. Depending on SM configuration, M7 can be used as follows: (1) M7 in a separate Logical Machine (LM) from A55 cores, that Linux can't control (2) M7 in a separate LM from A55 cores that Linux can control using LMM protocol. (3) M7 runs in same Logical Machine as A55 cores, so Linux can control it using CPU protocol So extend the driver to using LMM and CPU protocol to manage the M7 core. - Compare linux LM ID(got using scmi_imx_lmm_info) and M7 LM ID(the ID is fixed as 1 in SM firmware if M7 is in a separate LM), if Linux LM ID is not same as M7 LM ID(linux and M7 in same LM), use LMM protocol to start/stop. CPU protocol support will be added in the following patch. Whether using CPU or LMM protocol to start/stop, the M7 status detection could use CPU protocol to detect started or not. So in imx_rproc_detect_mode, use scmi_imx_cpu_started to check the status of M7. - For above case (1) and (2), Use SCMI_IMX_LMM_POWER_ON to detect whether the M7 LM is under control of A55 LM. - For above case , after using SCMI_IMX_LMM_POWER_ON to check permission, SCMI_IMX_LMM_SHUTDOWN API should be called to shutdown the M7 LM to save power only when M7 LM is going to be started by remoteproc framework. Otherwise bypass SCMI_IMX_LMM_SHUTDOWN API if M7 LM is started before booting Linux. Current setup relies on pre-Linux software(U-Boot) to do M7 TCM ECC initialization. In future, we could add the support in Linux to decouple U-Boot and Linux. Reviewed-by: Daniel Baluta Reviewed-by: Frank Li Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20260109-imx95-rproc-2026-1-8-v6-4-d2fefb36263d@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/Kconfig | 2 + drivers/remoteproc/imx_rproc.c | 166 +++++++++++++++++++++++++++++++++ drivers/remoteproc/imx_rproc.h | 3 + 3 files changed, 171 insertions(+) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 48a0d3a69ed0..ee54436fea5a 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -27,6 +27,8 @@ config IMX_REMOTEPROC tristate "i.MX remoteproc support" depends on ARCH_MXC depends on HAVE_ARM_SMCCC + depends on IMX_SCMI_CPU_DRV || !IMX_SCMI_CPU_DRV + depends on IMX_SCMI_LMM_DRV || !IMX_SCMI_LMM_DRV select MAILBOX help Say y here to support iMX's remote processors via the remote diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index b0857a1a9660..b254045d45ea 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include "imx_rproc.h" @@ -92,9 +94,15 @@ struct imx_rproc_mem { #define ATT_CORE_MASK 0xffff #define ATT_CORE(I) BIT((I)) +/* Linux has permission to handle the Logical Machine of remote cores */ +#define IMX_RPROC_FLAGS_SM_LMM_CTRL BIT(0) + static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block); static void imx_rproc_free_mbox(void *data); +/* Forward declarations for platform operations */ +static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm; + struct imx_rproc { struct device *dev; struct regmap *regmap; @@ -117,6 +125,11 @@ struct imx_rproc { u32 core_index; struct dev_pm_domain_list *pd_list; const struct imx_rproc_plat_ops *ops; + /* + * For i.MX System Manager based systems + * BIT 0: IMX_RPROC_FLAGS_SM_LMM_CTRL(RPROC LM is under Linux control ) + */ + u32 flags; }; static const struct imx_rproc_att imx_rproc_att_imx93[] = { @@ -313,6 +326,33 @@ static int imx_rproc_scu_api_start(struct rproc *rproc) return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); } +static int imx_rproc_sm_lmm_start(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device *dev = priv->dev; + int ret; + + /* + * If the remoteproc core can't start the M7, it will already be + * handled in imx_rproc_sm_lmm_prepare(). + */ + ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0); + if (ret) { + dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n", + dcfg->lmid, dcfg->cpuid, ret); + return ret; + } + + ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_BOOT, 0); + if (ret) { + dev_err(dev, "Failed to boot lmm(%d): %d\n", dcfg->lmid, ret); + return ret; + } + + return 0; +} + static int imx_rproc_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -369,6 +409,17 @@ static int imx_rproc_scu_api_stop(struct rproc *rproc) return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry); } +static int imx_rproc_sm_lmm_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + + if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_CTRL)) + return -EACCES; + + return scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0); +} + static int imx_rproc_stop(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -485,6 +536,36 @@ static int imx_rproc_mem_release(struct rproc *rproc, return 0; } +static int imx_rproc_sm_lmm_prepare(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + int ret; + + /* + * IMX_RPROC_FLAGS_SM_LMM_CTRL not set indicates Linux is not able + * to start/stop M7, then if rproc is not in detached state, + * prepare should fail. If in detached state, this is in rproc_attach() + * path. + */ + if (rproc->state == RPROC_DETACHED) + return 0; + + if (!(priv->flags & IMX_RPROC_FLAGS_SM_LMM_CTRL)) + return -EACCES; + + /* Power on the Logical Machine to make sure TCM is available. */ + ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0); + if (ret) { + dev_err(priv->dev, "Failed to power on lmm(%d): %d\n", dcfg->lmid, ret); + return ret; + } + + dev_info(priv->dev, "lmm(%d) powered on by Linux\n", dcfg->lmid); + + return 0; +} + static int imx_rproc_prepare(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -980,6 +1061,84 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc) return 0; } +/* Check whether remoteproc core is responsible for M7 lifecycle */ +static int imx_rproc_sm_lmm_check(struct rproc *rproc, bool started) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device *dev = priv->dev; + int ret; + + ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_POWER_ON, 0); + if (ret) { + if (ret == -EACCES) { + /* + * M7 is booted before Linux and not under Linux Control, so only + * do IPC between RPROC and Linux, not return failure + */ + dev_info(dev, "lmm(%d) not under Linux Control\n", dcfg->lmid); + return 0; + } + + dev_err(dev, "power on lmm(%d) failed: %d\n", dcfg->lmid, ret); + return ret; + } + + /* Shutdown remote processor if not started */ + if (!started) { + ret = scmi_imx_lmm_operation(dcfg->lmid, SCMI_IMX_LMM_SHUTDOWN, 0); + if (ret) { + dev_err(dev, "shutdown lmm(%d) failed: %d\n", dcfg->lmid, ret); + return ret; + } + } + + priv->flags |= IMX_RPROC_FLAGS_SM_LMM_CTRL; + + return 0; +} + +static int imx_rproc_sm_detect_mode(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device *dev = priv->dev; + struct scmi_imx_lmm_info info; + bool started = false; + int ret; + + ret = scmi_imx_cpu_started(dcfg->cpuid, &started); + if (ret) { + dev_err(dev, "Failed to detect cpu(%d) status: %d\n", dcfg->cpuid, ret); + return ret; + } + + if (started) + priv->rproc->state = RPROC_DETACHED; + + /* Get current Linux Logical Machine ID */ + ret = scmi_imx_lmm_info(LMM_ID_DISCOVER, &info); + if (ret) { + dev_err(dev, "Failed to get current LMM ID err: %d\n", ret); + return ret; + } + + /* + * Check whether M7 is in the same LM as host core(running Linux) + * If yes, use CPU protocol API to manage M7. + * If no, use Logical Machine API to manage M7. + */ + if (dcfg->lmid == info.lmid) { + dev_err(dev, "CPU Protocol OPS is not supported\n"); + return -EOPNOTSUPP; + } + + priv->ops = &imx_rproc_ops_sm_lmm; + dev_info(dev, "Using LMM Protocol OPS\n"); + + return imx_rproc_sm_lmm_check(rproc, started); +} + static int imx_rproc_detect_mode(struct imx_rproc *priv) { /* @@ -1155,6 +1314,13 @@ static const struct imx_rproc_plat_ops imx_rproc_ops_scu_api = { .detect_mode = imx_rproc_scu_api_detect_mode, }; +static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm = { + .detect_mode = imx_rproc_sm_detect_mode, + .prepare = imx_rproc_sm_lmm_prepare, + .start = imx_rproc_sm_lmm_start, + .stop = imx_rproc_sm_lmm_stop, +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { .src_reg = IMX7D_SRC_SCR, .src_mask = IMX7D_M4_RST_MASK, diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h index 37417568a0ad..d37e6f90548c 100644 --- a/drivers/remoteproc/imx_rproc.h +++ b/drivers/remoteproc/imx_rproc.h @@ -38,6 +38,9 @@ struct imx_rproc_dcfg { size_t att_size; u32 flags; const struct imx_rproc_plat_ops *ops; + /* For System Manager(SM) based SoCs */ + u32 cpuid; /* ID of the remote core */ + u32 lmid; /* ID of the Logcial Machine */ }; #endif /* _IMX_RPROC_H */ From 1ae680bbe77fe124916bd28a1dd6548847c56914 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 9 Jan 2026 20:08:05 +0800 Subject: [PATCH 17/20] remoteproc: imx_rproc: Add support for System Manager CPU API When the System Manager configuration places the M7 core in the same Logical Machine(LM) as the A55 cores (M7 LM ID equals A55 LM ID), Linux can control M7 using the CPU protocol API. For more details, see the previous patch that adds LMM API support. Changes include: - Introduce imx_rproc_ops_sm_cpu for CPU API operations. - Reuse imx_rproc_sm_detect_mode to detect shared LM and set priv->ops to imx_rproc_ops_sm_cpu. - Implement imx_rproc_sm_cpu_{start,stop} to handle M7 start and stop. Signed-off-by: Peng Fan Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/20260109-imx95-rproc-2026-1-8-v6-5-d2fefb36263d@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 35 ++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index b254045d45ea..09f168d9ebbe 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -102,6 +102,7 @@ static void imx_rproc_free_mbox(void *data); /* Forward declarations for platform operations */ static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm; +static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu; struct imx_rproc { struct device *dev; @@ -326,6 +327,21 @@ static int imx_rproc_scu_api_start(struct rproc *rproc) return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); } +static int imx_rproc_sm_cpu_start(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + int ret; + + ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false); + if (ret) { + dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret); + return ret; + } + + return scmi_imx_cpu_start(dcfg->cpuid, true); +} + static int imx_rproc_sm_lmm_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -409,6 +425,14 @@ static int imx_rproc_scu_api_stop(struct rproc *rproc) return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry); } +static int imx_rproc_sm_cpu_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + + return scmi_imx_cpu_start(dcfg->cpuid, false); +} + static int imx_rproc_sm_lmm_stop(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -1129,8 +1153,9 @@ static int imx_rproc_sm_detect_mode(struct rproc *rproc) * If no, use Logical Machine API to manage M7. */ if (dcfg->lmid == info.lmid) { - dev_err(dev, "CPU Protocol OPS is not supported\n"); - return -EOPNOTSUPP; + priv->ops = &imx_rproc_ops_sm_cpu; + dev_info(dev, "Using CPU Protocol OPS\n"); + return 0; } priv->ops = &imx_rproc_ops_sm_lmm; @@ -1321,6 +1346,12 @@ static const struct imx_rproc_plat_ops imx_rproc_ops_sm_lmm = { .stop = imx_rproc_sm_lmm_stop, }; +static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu = { + .detect_mode = imx_rproc_sm_detect_mode, + .start = imx_rproc_sm_cpu_start, + .stop = imx_rproc_sm_cpu_stop, +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { .src_reg = IMX7D_SRC_SCR, .src_mask = IMX7D_M4_RST_MASK, From a3bf6ee15a59d25724746f284de167af6dc76baf Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 9 Jan 2026 20:08:06 +0800 Subject: [PATCH 18/20] remoteproc: imx_rproc: Add support for i.MX95 Add imx_rproc_cfg_imx95_m7 and address(TCM and DDR) mapping. Add i.MX95 of_device_id entry. Reviewed-by: Daniel Baluta Reviewed-by: Frank Li Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20260109-imx95-rproc-2026-1-8-v6-6-d2fefb36263d@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 09f168d9ebbe..375de79168a1 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -133,6 +133,18 @@ struct imx_rproc { u32 flags; }; +static const struct imx_rproc_att imx_rproc_att_imx95_m7[] = { + /* dev addr , sys addr , size , flags */ + /* TCM CODE NON-SECURE */ + { 0x00000000, 0x203C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, + + /* TCM SYS NON-SECURE*/ + { 0x20000000, 0x20400000, 0x00040000, ATT_OWN | ATT_IOMEM }, + + /* DDR */ + { 0x80000000, 0x80000000, 0x50000000, 0 }, +}; + static const struct imx_rproc_att imx_rproc_att_imx93[] = { /* dev addr , sys addr , size , flags */ /* TCM CODE NON-SECURE */ @@ -1435,6 +1447,15 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { .flags = IMX_RPROC_NEED_CLKS, }; +static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = { + .att = imx_rproc_att_imx95_m7, + .att_size = ARRAY_SIZE(imx_rproc_att_imx95_m7), + .ops = &imx_rproc_ops_sm_lmm, + /* Must align with System Manager Firmware */ + .cpuid = 1, /* Use 1 as cpu id for M7 core */ + .lmid = 1, /* Use 1 as Logical Machine ID where M7 resides */ +}; + static const struct of_device_id imx_rproc_of_match[] = { { .compatible = "fsl,imx7ulp-cm4", .data = &imx_rproc_cfg_imx7ulp }, { .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d }, @@ -1449,6 +1470,7 @@ static const struct of_device_id imx_rproc_of_match[] = { { .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm }, { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp }, { .compatible = "fsl,imx93-cm33", .data = &imx_rproc_cfg_imx93 }, + { .compatible = "fsl,imx95-cm7", .data = &imx_rproc_cfg_imx95_m7 }, {}, }; MODULE_DEVICE_TABLE(of, imx_rproc_of_match); From d935187cfb27fc4168f78f3959aef4eafaae76bb Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 12 Jan 2026 11:07:55 +0000 Subject: [PATCH 19/20] remoteproc: mediatek: Break lock dependency to `prepare_lock` A potential circular locking dependency (ABBA deadlock) exists between `ec_dev->lock` and the clock framework's `prepare_lock`. The first order (A -> B) occurs when scp_ipi_send() is called while `ec_dev->lock` is held (e.g., within cros_ec_cmd_xfer()): 1. cros_ec_cmd_xfer() acquires `ec_dev->lock` and calls scp_ipi_send(). 2. scp_ipi_send() calls clk_prepare_enable(), which acquires `prepare_lock`. See #0 in the following example calling trace. (Lock Order: `ec_dev->lock` -> `prepare_lock`) The reverse order (B -> A) is more complex and has been observed (learned) by lockdep. It involves the clock prepare operation triggering power domain changes, which then propagates through sysfs and power supply uevents, eventually calling back into the ChromeOS EC driver and attempting to acquire `ec_dev->lock`: 1. Something calls clk_prepare(), which acquires `prepare_lock`. It then triggers genpd operations like genpd_runtime_resume(), which takes `&genpd->mlock`. 2. Power domain changes can trigger regulator changes; regulator changes can then trigger device link changes; device link changes can then trigger sysfs changes. Eventually, power_supply_uevent() is called. 3. This leads to calls like cros_usbpd_charger_get_prop(), which calls cros_ec_cmd_xfer_status(), which then attempts to acquire `ec_dev->lock`. See #1 ~ #6 in the following example calling trace. (Lock Order: `prepare_lock` -> `&genpd->mlock` -> ... -> `&ec_dev->lock`) Move the clk_prepare()/clk_unprepare() operations for `scp->clk` to the remoteproc prepare()/unprepare() callbacks. This ensures `prepare_lock` is only acquired in prepare()/unprepare() callbacks. Since `ec_dev->lock` is not involved in the callbacks, the dependency loop is broken. This means the clock is always "prepared" when the SCP is running. The prolonged "prepared time" for the clock should be acceptable as SCP is designed to be a very power efficient processor. The power consumption impact can be negligible. A simplified calling trace reported by lockdep: > -> #6 (&ec_dev->lock) > cros_ec_cmd_xfer > cros_ec_cmd_xfer_status > cros_usbpd_charger_get_port_status > cros_usbpd_charger_get_prop > power_supply_get_property > power_supply_show_property > power_supply_uevent > dev_uevent > uevent_show > dev_attr_show > sysfs_kf_seq_show > kernfs_seq_show > -> #5 (kn->active#2) > kernfs_drain > __kernfs_remove > kernfs_remove_by_name_ns > sysfs_remove_file_ns > device_del > __device_link_del > device_links_driver_bound > -> #4 (device_links_lock) > device_link_remove > _regulator_put > regulator_put > -> #3 (regulator_list_mutex) > regulator_lock_dependent > regulator_disable > scpsys_power_off > _genpd_power_off > genpd_power_off > -> #2 (&genpd->mlock/1) > genpd_add_subdomain > pm_genpd_add_subdomain > scpsys_add_subdomain > scpsys_probe > -> #1 (&genpd->mlock) > genpd_runtime_resume > __rpm_callback > rpm_callback > rpm_resume > __pm_runtime_resume > clk_core_prepare > clk_prepare > -> #0 (prepare_lock) > clk_prepare > scp_ipi_send > scp_send_ipi > mtk_rpmsg_send > rpmsg_send > cros_ec_pkt_xfer_rpmsg Signed-off-by: Tzung-Bi Shih Reviewed-by: Chen-Yu Tsai Tested-by: Chen-Yu Tsai Link: https://lore.kernel.org/r/20260112110755.2435899-1-tzungbi@kernel.org Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 39 +++++++++++++++++++++++--------- drivers/remoteproc/mtk_scp_ipi.c | 4 ++-- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 328541e62158..4651311aeb07 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -283,7 +283,7 @@ static irqreturn_t scp_irq_handler(int irq, void *priv) struct mtk_scp *scp = priv; int ret; - ret = clk_prepare_enable(scp->clk); + ret = clk_enable(scp->clk); if (ret) { dev_err(scp->dev, "failed to enable clocks\n"); return IRQ_NONE; @@ -291,7 +291,7 @@ static irqreturn_t scp_irq_handler(int irq, void *priv) scp->data->scp_irq_handler(scp); - clk_disable_unprepare(scp->clk); + clk_disable(scp->clk); return IRQ_HANDLED; } @@ -665,7 +665,7 @@ static int scp_load(struct rproc *rproc, const struct firmware *fw) struct device *dev = scp->dev; int ret; - ret = clk_prepare_enable(scp->clk); + ret = clk_enable(scp->clk); if (ret) { dev_err(dev, "failed to enable clocks\n"); return ret; @@ -680,7 +680,7 @@ static int scp_load(struct rproc *rproc, const struct firmware *fw) ret = scp_elf_load_segments(rproc, fw); leave: - clk_disable_unprepare(scp->clk); + clk_disable(scp->clk); return ret; } @@ -691,14 +691,14 @@ static int scp_parse_fw(struct rproc *rproc, const struct firmware *fw) struct device *dev = scp->dev; int ret; - ret = clk_prepare_enable(scp->clk); + ret = clk_enable(scp->clk); if (ret) { dev_err(dev, "failed to enable clocks\n"); return ret; } ret = scp_ipi_init(scp, fw); - clk_disable_unprepare(scp->clk); + clk_disable(scp->clk); return ret; } @@ -709,7 +709,7 @@ static int scp_start(struct rproc *rproc) struct scp_run *run = &scp->run; int ret; - ret = clk_prepare_enable(scp->clk); + ret = clk_enable(scp->clk); if (ret) { dev_err(dev, "failed to enable clocks\n"); return ret; @@ -734,14 +734,14 @@ static int scp_start(struct rproc *rproc) goto stop; } - clk_disable_unprepare(scp->clk); + clk_disable(scp->clk); dev_info(dev, "SCP is ready. FW version %s\n", run->fw_ver); return 0; stop: scp->data->scp_reset_assert(scp); - clk_disable_unprepare(scp->clk); + clk_disable(scp->clk); return ret; } @@ -909,7 +909,7 @@ static int scp_stop(struct rproc *rproc) struct mtk_scp *scp = rproc->priv; int ret; - ret = clk_prepare_enable(scp->clk); + ret = clk_enable(scp->clk); if (ret) { dev_err(scp->dev, "failed to enable clocks\n"); return ret; @@ -917,12 +917,29 @@ static int scp_stop(struct rproc *rproc) scp->data->scp_reset_assert(scp); scp->data->scp_stop(scp); - clk_disable_unprepare(scp->clk); + clk_disable(scp->clk); return 0; } +static int scp_prepare(struct rproc *rproc) +{ + struct mtk_scp *scp = rproc->priv; + + return clk_prepare(scp->clk); +} + +static int scp_unprepare(struct rproc *rproc) +{ + struct mtk_scp *scp = rproc->priv; + + clk_unprepare(scp->clk); + return 0; +} + static const struct rproc_ops scp_ops = { + .prepare = scp_prepare, + .unprepare = scp_unprepare, .start = scp_start, .stop = scp_stop, .load = scp_load, diff --git a/drivers/remoteproc/mtk_scp_ipi.c b/drivers/remoteproc/mtk_scp_ipi.c index c068227e251e..7a37e273b3af 100644 --- a/drivers/remoteproc/mtk_scp_ipi.c +++ b/drivers/remoteproc/mtk_scp_ipi.c @@ -171,7 +171,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len, WARN_ON(len > scp_sizes->ipi_share_buffer_size) || WARN_ON(!buf)) return -EINVAL; - ret = clk_prepare_enable(scp->clk); + ret = clk_enable(scp->clk); if (ret) { dev_err(scp->dev, "failed to enable clock\n"); return ret; @@ -211,7 +211,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len, unlock_mutex: mutex_unlock(&scp->send_lock); - clk_disable_unprepare(scp->clk); + clk_disable(scp->clk); return ret; } From 26aa5295010ffaebcf8f1991c53fa7cf2ee1b20d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 29 Jan 2026 09:44:48 +0800 Subject: [PATCH 20/20] remoteproc: imx_rproc: Fix invalid loaded resource table detection imx_rproc_elf_find_loaded_rsc_table() may incorrectly report a loaded resource table even when the current firmware does not provide one. When the device tree contains a "rsc-table" entry, priv->rsc_table is non-NULL and denotes where a resource table would be located if one is present in memory. However, when the current firmware has no resource table, rproc->table_ptr is NULL. The function still returns priv->rsc_table, and the remoteproc core interprets this as a valid loaded resource table. Fix this by returning NULL from imx_rproc_elf_find_loaded_rsc_table() when there is no resource table for the current firmware (i.e. when rproc->table_ptr is NULL). This aligns the function's semantics with the remoteproc core: a loaded resource table is only reported when a valid table_ptr exists. With this change, starting firmware without a resource table no longer triggers a crash. Fixes: e954a1bd1610 ("remoteproc: imx_rproc: Use imx specific hook for find_loaded_rsc_table") Cc: stable@vger.kernel.org Signed-off-by: Peng Fan Acked-by: Daniel Baluta Link: https://lore.kernel.org/r/20260129-imx-rproc-fix-v3-1-fc4e41e6e750@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 375de79168a1..f5f916d67905 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -729,6 +729,10 @@ imx_rproc_elf_find_loaded_rsc_table(struct rproc *rproc, const struct firmware * { struct imx_rproc *priv = rproc->priv; + /* No resource table in the firmware */ + if (!rproc->table_ptr) + return NULL; + if (priv->rsc_table) return (struct resource_table *)priv->rsc_table;