From c4c432dfb00fcb69d56cc9778f527cce71cec9bb Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 22 Jul 2025 15:52:25 +0800 Subject: [PATCH 01/29] remoteproc: imx_dsp_rproc: Add support of recovery and coredump process When enabled FW recovery, but is broken because software reset is missed in this recovery flow. So move software reset from imx_dsp_runtime_resume() to .load() and clear memory before loading firmware to make recovery work. Add call rproc_coredump_set_elf_info() to initialize the elf info for coredump, otherwise coredump will report error "ELF class is not set". Fixes: ec0e5549f358 ("remoteproc: imx_dsp_rproc: Add remoteproc driver for DSP on i.MX") Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/20250722075225.544319-1-shengjiu.wang@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_dsp_rproc.c | 45 +++++++++++++++++++----------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index 5ee622bf5352..6e78a01755c7 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -774,7 +774,6 @@ static int imx_dsp_rproc_prepare(struct rproc *rproc) { struct imx_dsp_rproc *priv = rproc->priv; struct device *dev = rproc->dev.parent; - struct rproc_mem_entry *carveout; int ret; ret = imx_dsp_rproc_add_carveout(priv); @@ -785,15 +784,6 @@ static int imx_dsp_rproc_prepare(struct rproc *rproc) pm_runtime_get_sync(dev); - /* - * 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); - } - return 0; } @@ -1022,13 +1012,39 @@ static int imx_dsp_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw return 0; } +static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw) +{ + struct imx_dsp_rproc *priv = rproc->priv; + const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; + struct rproc_mem_entry *carveout; + int ret; + + /* Reset DSP if needed */ + if (dsp_dcfg->reset) + dsp_dcfg->reset(priv); + /* + * 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); + } + + ret = imx_dsp_rproc_elf_load_segments(rproc, fw); + if (ret) + return ret; + + return 0; +} + static const struct rproc_ops imx_dsp_rproc_ops = { .prepare = imx_dsp_rproc_prepare, .unprepare = imx_dsp_rproc_unprepare, .start = imx_dsp_rproc_start, .stop = imx_dsp_rproc_stop, .kick = imx_dsp_rproc_kick, - .load = imx_dsp_rproc_elf_load_segments, + .load = imx_dsp_rproc_load, .parse_fw = imx_dsp_rproc_parse_fw, .handle_rsc = imx_dsp_rproc_handle_rsc, .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, @@ -1189,6 +1205,8 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev) goto err_detach_domains; } + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_XTENSA); + pm_runtime_enable(dev); return 0; @@ -1214,7 +1232,6 @@ static int imx_dsp_runtime_resume(struct device *dev) { struct rproc *rproc = dev_get_drvdata(dev); struct imx_dsp_rproc *priv = rproc->priv; - const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; int ret; /* @@ -1235,10 +1252,6 @@ static int imx_dsp_runtime_resume(struct device *dev) return ret; } - /* Reset DSP if needed */ - if (dsp_dcfg->reset) - dsp_dcfg->reset(priv); - return 0; } From f9a4c582e508c210d1e8e70493a69c6e5708476c Mon Sep 17 00:00:00 2001 From: Hiago De Franco Date: Wed, 6 Aug 2025 14:48:17 -0300 Subject: [PATCH 02/29] remoteproc: k3: Remove remote processor mailbox ping As of today, pinging the remote processor during k3_rproc_request_mbox() does not have any functional effect. This behavior was originally based on the OMAP remoteproc driver, where the idea was to send messages such as suspend requests (among others) to the remote processor, but this was never upstreamed. Currently, the ping message has no effect in upstream usage and causes an unread message to remain in the mailbox, which ultimately prevents the system from entering suspend mode: Freezing remaining freezable tasks completed (elapsed 0.001 seconds) printk: Suspending console(s) (use no_console_suspend to debug) omap-mailbox 29000000.mailbox: fifo 1 has unexpected unread messages omap-mailbox 29000000.mailbox: PM: dpm_run_callback(): platform_pm_suspend returns -16 omap-mailbox 29000000.mailbox: PM: failed to suspend: error -16 The ping is only replied if the remote core firmware is capable of doing it, otherwise the unread message stays into the mailbox. Remove the ping and fix the suspend issue. Suggested-by: Andrew Davis Signed-off-by: Hiago De Franco Acked-by: Andrew Davis Link: https://lore.kernel.org/r/20250806-v1-fix-am62-hmp-suspend-v1-1-1c4a81bb5dde@toradex.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/ti_k3_common.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/remoteproc/ti_k3_common.c b/drivers/remoteproc/ti_k3_common.c index d4f20900f33b..8266e11914af 100644 --- a/drivers/remoteproc/ti_k3_common.c +++ b/drivers/remoteproc/ti_k3_common.c @@ -160,7 +160,6 @@ int k3_rproc_request_mbox(struct rproc *rproc) struct k3_rproc *kproc = rproc->priv; struct mbox_client *client = &kproc->client; struct device *dev = kproc->dev; - int ret; client->dev = dev; client->tx_done = NULL; @@ -173,20 +172,6 @@ int k3_rproc_request_mbox(struct rproc *rproc) return dev_err_probe(dev, PTR_ERR(kproc->mbox), "mbox_request_channel failed\n"); - /* - * Ping the remote processor, this is only for sanity-sake for now; - * there is no functional effect whatsoever. - * - * Note that the reply will _not_ arrive immediately: this message - * will wait in the mailbox fifo until the remote processor is booted. - */ - ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); - if (ret < 0) { - dev_err(dev, "mbox_send_message failed (%pe)\n", ERR_PTR(ret)); - mbox_free_channel(kproc->mbox); - return ret; - } - return 0; } EXPORT_SYMBOL_GPL(k3_rproc_request_mbox); From 127d874a7df05b30e937951864b18fb11babff95 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 08:55:30 -0500 Subject: [PATCH 03/29] remoteproc: da8xx: Use devm_rproc_alloc() helper Use the device lifecycle managed allocation function. This helps prevent mistakes like freeing out of order in cleanup functions and forgetting to free on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814135532.638040-1-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/da8xx_remoteproc.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 93031f0867d1..47df21bea525 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -276,8 +276,8 @@ static int da8xx_rproc_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "device does not have specific CMA pool\n"); } - rproc = rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, - sizeof(*drproc)); + rproc = devm_rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, + sizeof(*drproc)); if (!rproc) { ret = -ENOMEM; goto free_mem; @@ -294,7 +294,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = da8xx_rproc_get_internal_memories(pdev, drproc); if (ret) - goto free_rproc; + goto free_mem; platform_set_drvdata(pdev, rproc); @@ -304,7 +304,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) rproc); if (ret) { dev_err(dev, "devm_request_threaded_irq error: %d\n", ret); - goto free_rproc; + goto free_mem; } /* @@ -314,7 +314,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) */ ret = reset_control_assert(dsp_reset); if (ret) - goto free_rproc; + goto free_mem; drproc->chipsig = chipsig; drproc->bootreg = bootreg; @@ -325,13 +325,11 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = rproc_add(rproc); if (ret) { dev_err(dev, "rproc_add failed: %d\n", ret); - goto free_rproc; + goto free_mem; } return 0; -free_rproc: - rproc_free(rproc); free_mem: if (dev->of_node) of_reserved_mem_device_release(dev); @@ -352,7 +350,6 @@ static void da8xx_rproc_remove(struct platform_device *pdev) disable_irq(drproc->irq); rproc_del(rproc); - rproc_free(rproc); if (dev->of_node) of_reserved_mem_device_release(dev); } From 16689f33e5addec4a61cd4c102900a154349dc2a Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 08:55:31 -0500 Subject: [PATCH 04/29] remoteproc: da8xx: Use devm action to release reserved memory This helps prevent mistakes like freeing out of order in cleanup functions and forgetting to free on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814135532.638040-2-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/da8xx_remoteproc.c | 30 +++++++++++++-------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 47df21bea525..58b4f05283d9 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -233,6 +233,13 @@ static int da8xx_rproc_get_internal_memories(struct platform_device *pdev, return 0; } +static void da8xx_rproc_mem_release(void *data) +{ + struct device *dev = data; + + of_reserved_mem_device_release(dev); +} + static int da8xx_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -274,14 +281,13 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = of_reserved_mem_device_init(dev); if (ret) return dev_err_probe(dev, ret, "device does not have specific CMA pool\n"); + devm_add_action_or_reset(&pdev->dev, da8xx_rproc_mem_release, &pdev->dev); } rproc = devm_rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, sizeof(*drproc)); - if (!rproc) { - ret = -ENOMEM; - goto free_mem; - } + if (!rproc) + return -ENOMEM; /* error recovery is not supported at present */ rproc->recovery_disabled = true; @@ -294,7 +300,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = da8xx_rproc_get_internal_memories(pdev, drproc); if (ret) - goto free_mem; + return ret; platform_set_drvdata(pdev, rproc); @@ -304,7 +310,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) rproc); if (ret) { dev_err(dev, "devm_request_threaded_irq error: %d\n", ret); - goto free_mem; + return ret; } /* @@ -314,7 +320,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) */ ret = reset_control_assert(dsp_reset); if (ret) - goto free_mem; + return ret; drproc->chipsig = chipsig; drproc->bootreg = bootreg; @@ -325,22 +331,16 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = rproc_add(rproc); if (ret) { dev_err(dev, "rproc_add failed: %d\n", ret); - goto free_mem; + return ret; } return 0; - -free_mem: - if (dev->of_node) - of_reserved_mem_device_release(dev); - return ret; } static void da8xx_rproc_remove(struct platform_device *pdev) { struct rproc *rproc = platform_get_drvdata(pdev); struct da8xx_rproc *drproc = rproc->priv; - struct device *dev = &pdev->dev; /* * The devm subsystem might end up releasing things before @@ -350,8 +350,6 @@ static void da8xx_rproc_remove(struct platform_device *pdev) disable_irq(drproc->irq); rproc_del(rproc); - if (dev->of_node) - of_reserved_mem_device_release(dev); } static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = { From 7183e39ac915ec047586a755746cae5b79f5f93c Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 08:55:32 -0500 Subject: [PATCH 05/29] remoteproc: da8xx: Use devm_rproc_add() helper Use the device lifecycle managed add function. This helps prevent mistakes like deleting out of order in cleanup functions and forgetting to delete on error paths. As this now makes the IRQ free ordered correctly, we can drop that from the remove() callback, which is now empty and can also be removed. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814135532.638040-3-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/da8xx_remoteproc.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 58b4f05283d9..e418a2bf5d2e 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -302,8 +302,6 @@ static int da8xx_rproc_probe(struct platform_device *pdev) if (ret) return ret; - platform_set_drvdata(pdev, rproc); - /* everything the ISR needs is now setup, so hook it up */ ret = devm_request_threaded_irq(dev, irq, da8xx_rproc_callback, handle_event, 0, "da8xx-remoteproc", @@ -328,7 +326,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) drproc->irq_data = irq_data; drproc->irq = irq; - ret = rproc_add(rproc); + ret = devm_rproc_add(dev, rproc); if (ret) { dev_err(dev, "rproc_add failed: %d\n", ret); return ret; @@ -337,21 +335,6 @@ static int da8xx_rproc_probe(struct platform_device *pdev) return 0; } -static void da8xx_rproc_remove(struct platform_device *pdev) -{ - struct rproc *rproc = platform_get_drvdata(pdev); - struct da8xx_rproc *drproc = rproc->priv; - - /* - * The devm subsystem might end up releasing things before - * freeing the irq, thus allowing an interrupt to sneak in while - * the device is being removed. This should prevent that. - */ - disable_irq(drproc->irq); - - rproc_del(rproc); -} - static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = { { .compatible = "ti,da850-dsp", }, { /* sentinel */ }, @@ -360,7 +343,6 @@ MODULE_DEVICE_TABLE(of, davinci_rproc_of_match); static struct platform_driver da8xx_rproc_driver = { .probe = da8xx_rproc_probe, - .remove = da8xx_rproc_remove, .driver = { .name = "davinci-rproc", .of_match_table = of_match_ptr(davinci_rproc_of_match), From 01e4ed11c5d4120a47ffc3b15dd9050e922cde53 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 09:08:31 -0500 Subject: [PATCH 06/29] remoteproc: keystone: Use devm action to release reserved memory This helps prevent mistakes like freeing out of order in cleanup functions and forgetting to free on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814140835.651652-1-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/keystone_remoteproc.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 7b41b4547fa8..6fc27e0d7b3d 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -349,6 +349,13 @@ static int keystone_rproc_of_get_dev_syscon(struct platform_device *pdev, return 0; } +static void keystone_rproc_mem_release(void *data) +{ + struct device *dev = data; + + of_reserved_mem_device_release(dev); +} + static int keystone_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -425,8 +432,14 @@ static int keystone_rproc_probe(struct platform_device *pdev) goto disable_clk; } - if (of_reserved_mem_device_init(dev)) + ret = of_reserved_mem_device_init(dev); + if (ret) { dev_warn(dev, "device does not have specific CMA pool\n"); + } else { + ret = devm_add_action_or_reset(dev, keystone_rproc_mem_release, dev); + if (ret) + goto disable_clk; + } /* ensure the DSP is in reset before loading firmware */ ret = reset_control_status(ksproc->reset); @@ -450,7 +463,6 @@ static int keystone_rproc_probe(struct platform_device *pdev) return 0; release_mem: - of_reserved_mem_device_release(dev); gpiod_put(ksproc->kick_gpio); disable_clk: pm_runtime_put_sync(dev); @@ -467,7 +479,6 @@ static void keystone_rproc_remove(struct platform_device *pdev) gpiod_put(ksproc->kick_gpio); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - of_reserved_mem_device_release(&pdev->dev); } static const struct of_device_id keystone_rproc_of_match[] = { From db0427a8a595d0e4880043f9dff8e99c061e5d55 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 09:08:32 -0500 Subject: [PATCH 07/29] remoteproc: keystone: Use devm_pm_runtime_enable() helper Use device life-cycle managed runtime enable function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814140835.651652-2-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/keystone_remoteproc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 6fc27e0d7b3d..558678d793b0 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -401,12 +401,13 @@ static int keystone_rproc_probe(struct platform_device *pdev) return PTR_ERR(ksproc->reset); /* enable clock for accessing DSP internal memories */ - pm_runtime_enable(dev); + ret = devm_pm_runtime_enable(dev); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); + ret = pm_runtime_resume_and_get(dev); - if (ret < 0) { - dev_err(dev, "failed to enable clock, status = %d\n", ret); - goto disable_rpm; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to enable clock\n"); ret = keystone_rproc_of_get_memories(pdev, ksproc); if (ret) @@ -466,8 +467,6 @@ static int keystone_rproc_probe(struct platform_device *pdev) gpiod_put(ksproc->kick_gpio); disable_clk: pm_runtime_put_sync(dev); -disable_rpm: - pm_runtime_disable(dev); return ret; } @@ -478,7 +477,6 @@ static void keystone_rproc_remove(struct platform_device *pdev) rproc_del(ksproc->rproc); gpiod_put(ksproc->kick_gpio); pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); } static const struct of_device_id keystone_rproc_of_match[] = { From a2ab9cd283ce7daf1b634260a73618733af9d99f Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 09:08:33 -0500 Subject: [PATCH 08/29] remoteproc: keystone: Use devm action to call PM runtime put sync This helps prevent mistakes like putting out of order in cleanup functions and forgetting to put sync on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814140835.651652-3-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/keystone_remoteproc.c | 37 ++++++++++++------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 558678d793b0..558b53575890 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -356,6 +356,13 @@ static void keystone_rproc_mem_release(void *data) of_reserved_mem_device_release(dev); } +static void keystone_rproc_pm_runtime_put(void *data) +{ + struct device *dev = data; + + pm_runtime_put_sync(dev); +} + static int keystone_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -409,29 +416,26 @@ static int keystone_rproc_probe(struct platform_device *pdev) if (ret < 0) return dev_err_probe(dev, ret, "failed to enable clock\n"); + ret = devm_add_action_or_reset(dev, keystone_rproc_pm_runtime_put, dev); + if (ret) + return dev_err_probe(dev, ret, "failed to add disable pm devm action\n"); + ret = keystone_rproc_of_get_memories(pdev, ksproc); if (ret) - goto disable_clk; + return ret; ksproc->irq_ring = platform_get_irq_byname(pdev, "vring"); - if (ksproc->irq_ring < 0) { - ret = ksproc->irq_ring; - goto disable_clk; - } + if (ksproc->irq_ring < 0) + return ksproc->irq_ring; ksproc->irq_fault = platform_get_irq_byname(pdev, "exception"); - if (ksproc->irq_fault < 0) { - ret = ksproc->irq_fault; - goto disable_clk; - } + if (ksproc->irq_fault < 0) + return ksproc->irq_fault; ksproc->kick_gpio = gpiod_get(dev, "kick", GPIOD_ASIS); ret = PTR_ERR_OR_ZERO(ksproc->kick_gpio); - if (ret) { - dev_err(dev, "failed to get gpio for virtio kicks, status = %d\n", - ret); - goto disable_clk; - } + if (ret) + return dev_err_probe(dev, ret, "failed to get gpio for virtio kicks\n"); ret = of_reserved_mem_device_init(dev); if (ret) { @@ -439,7 +443,7 @@ static int keystone_rproc_probe(struct platform_device *pdev) } else { ret = devm_add_action_or_reset(dev, keystone_rproc_mem_release, dev); if (ret) - goto disable_clk; + return ret; } /* ensure the DSP is in reset before loading firmware */ @@ -465,8 +469,6 @@ static int keystone_rproc_probe(struct platform_device *pdev) release_mem: gpiod_put(ksproc->kick_gpio); -disable_clk: - pm_runtime_put_sync(dev); return ret; } @@ -476,7 +478,6 @@ static void keystone_rproc_remove(struct platform_device *pdev) rproc_del(ksproc->rproc); gpiod_put(ksproc->kick_gpio); - pm_runtime_put_sync(&pdev->dev); } static const struct of_device_id keystone_rproc_of_match[] = { From 49493852bd80109db5bdc02c2eb86751ec0d4906 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 09:08:34 -0500 Subject: [PATCH 09/29] remoteproc: keystone: Use devm_gpiod_get() helper Use device life-cycle managed GPIO get function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814140835.651652-4-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/keystone_remoteproc.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 558b53575890..7826853a00fc 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -432,7 +432,7 @@ static int keystone_rproc_probe(struct platform_device *pdev) if (ksproc->irq_fault < 0) return ksproc->irq_fault; - ksproc->kick_gpio = gpiod_get(dev, "kick", GPIOD_ASIS); + ksproc->kick_gpio = devm_gpiod_get(dev, "kick", GPIOD_ASIS); ret = PTR_ERR_OR_ZERO(ksproc->kick_gpio); if (ret) return dev_err_probe(dev, ret, "failed to get gpio for virtio kicks\n"); @@ -449,27 +449,19 @@ static int keystone_rproc_probe(struct platform_device *pdev) /* ensure the DSP is in reset before loading firmware */ ret = reset_control_status(ksproc->reset); if (ret < 0) { - dev_err(dev, "failed to get reset status, status = %d\n", ret); - goto release_mem; + return dev_err_probe(dev, ret, "failed to get reset status\n"); } else if (ret == 0) { WARN(1, "device is not in reset\n"); keystone_rproc_dsp_reset(ksproc); } ret = rproc_add(rproc); - if (ret) { - dev_err(dev, "failed to add register device with remoteproc core, status = %d\n", - ret); - goto release_mem; - } + if (ret) + return dev_err_probe(dev, ret, "failed to register device with remoteproc core\n"); platform_set_drvdata(pdev, ksproc); return 0; - -release_mem: - gpiod_put(ksproc->kick_gpio); - return ret; } static void keystone_rproc_remove(struct platform_device *pdev) @@ -477,7 +469,6 @@ static void keystone_rproc_remove(struct platform_device *pdev) struct keystone_rproc *ksproc = platform_get_drvdata(pdev); rproc_del(ksproc->rproc); - gpiod_put(ksproc->kick_gpio); } static const struct of_device_id keystone_rproc_of_match[] = { From ac4393af3cb66c371fafc894a14e795f70a7c5e0 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 09:08:35 -0500 Subject: [PATCH 10/29] remoteproc: keystone: Use devm_rproc_add() helper Use the device lifecycle managed add function. This helps prevent mistakes like deleting out of order in cleanup functions and forgetting to delete on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814140835.651652-5-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/keystone_remoteproc.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 7826853a00fc..4d6550b48567 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -455,22 +455,13 @@ static int keystone_rproc_probe(struct platform_device *pdev) keystone_rproc_dsp_reset(ksproc); } - ret = rproc_add(rproc); + ret = devm_rproc_add(dev, rproc); if (ret) return dev_err_probe(dev, ret, "failed to register device with remoteproc core\n"); - platform_set_drvdata(pdev, ksproc); - return 0; } -static void keystone_rproc_remove(struct platform_device *pdev) -{ - struct keystone_rproc *ksproc = platform_get_drvdata(pdev); - - rproc_del(ksproc->rproc); -} - static const struct of_device_id keystone_rproc_of_match[] = { { .compatible = "ti,k2hk-dsp", }, { .compatible = "ti,k2l-dsp", }, @@ -482,7 +473,6 @@ MODULE_DEVICE_TABLE(of, keystone_rproc_of_match); static struct platform_driver keystone_rproc_driver = { .probe = keystone_rproc_probe, - .remove = keystone_rproc_remove, .driver = { .name = "keystone-rproc", .of_match_table = keystone_rproc_of_match, From 461edcf73eec57bc0006fbb5209f5012c514c58b Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 10:39:37 -0500 Subject: [PATCH 11/29] remoteproc: wkup_m3: Use devm_pm_runtime_enable() helper Use device life-cycle managed runtime enable function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814153940.670564-1-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/wkup_m3_rproc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index d8be21e71721..35c2145b12db 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -148,7 +148,9 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) return -ENODEV; } - pm_runtime_enable(&pdev->dev); + ret = devm_pm_runtime_enable(dev); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); @@ -219,7 +221,6 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) rproc_free(rproc); err: pm_runtime_put_noidle(dev); - pm_runtime_disable(dev); return ret; } @@ -230,7 +231,6 @@ static void wkup_m3_rproc_remove(struct platform_device *pdev) rproc_del(rproc); rproc_free(rproc); pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); } #ifdef CONFIG_PM From 642f8c01e31dd2918e9e655f29846326bf7fad4c Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 10:39:38 -0500 Subject: [PATCH 12/29] remoteproc: wkup_m3: Use devm action to call PM runtime put sync This helps prevent mistakes like putting out of order in cleanup functions and forgetting to put sync on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814153940.670564-2-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/wkup_m3_rproc.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 35c2145b12db..2569f041d9ca 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -125,6 +125,13 @@ static const struct of_device_id wkup_m3_rproc_of_match[] = { }; MODULE_DEVICE_TABLE(of, wkup_m3_rproc_of_match); +static void wkup_m3_rproc_pm_runtime_put(void *data) +{ + struct device *dev = data; + + pm_runtime_put_sync(dev); +} + static int wkup_m3_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -152,17 +159,16 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) if (ret < 0) return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); - goto err; - } + if (ret < 0) + return dev_err_probe(dev, ret, "pm_runtime_get_sync() failed\n"); + ret = devm_add_action_or_reset(dev, wkup_m3_rproc_pm_runtime_put, dev); + if (ret) + return dev_err_probe(dev, ret, "failed to add disable pm devm action\n"); rproc = rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops, fw_name, sizeof(*wkupm3)); - if (!rproc) { - ret = -ENOMEM; - goto err; - } + if (!rproc) + return -ENOMEM; rproc->auto_boot = false; rproc->sysfs_read_only = true; @@ -219,8 +225,6 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) err_put_rproc: rproc_free(rproc); -err: - pm_runtime_put_noidle(dev); return ret; } @@ -230,7 +234,6 @@ static void wkup_m3_rproc_remove(struct platform_device *pdev) rproc_del(rproc); rproc_free(rproc); - pm_runtime_put_sync(&pdev->dev); } #ifdef CONFIG_PM From 9b84eec6f3b78795ab57f9c2c808948e12d18bad Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 10:39:39 -0500 Subject: [PATCH 13/29] remoteproc: wkup_m3: Use devm_rproc_alloc() helper Use the device lifecycle managed allocation function. This helps prevent mistakes like freeing out of order in cleanup functions and forgetting to free on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814153940.670564-3-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/wkup_m3_rproc.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 2569f041d9ca..30e9ecd75657 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -165,8 +165,8 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "failed to add disable pm devm action\n"); - rproc = rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops, - fw_name, sizeof(*wkupm3)); + rproc = devm_rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops, + fw_name, sizeof(*wkupm3)); if (!rproc) return -ENOMEM; @@ -183,9 +183,7 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) if (!wkupm3->rsts) { if (!(pdata && pdata->deassert_reset && pdata->assert_reset && pdata->reset_name)) { - dev_err(dev, "Platform data missing!\n"); - ret = -ENODEV; - goto err_put_rproc; + return dev_err_probe(dev, -ENODEV, "Platform data missing!\n"); } } @@ -193,12 +191,9 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, mem_names[i]); wkupm3->mem[i].cpu_addr = devm_ioremap_resource(dev, res); - if (IS_ERR(wkupm3->mem[i].cpu_addr)) { - dev_err(&pdev->dev, "devm_ioremap_resource failed for resource %d\n", - i); - ret = PTR_ERR(wkupm3->mem[i].cpu_addr); - goto err_put_rproc; - } + if (IS_ERR(wkupm3->mem[i].cpu_addr)) + return dev_err_probe(dev, PTR_ERR(wkupm3->mem[i].cpu_addr), + "devm_ioremap_resource failed for resource %d\n", i); wkupm3->mem[i].bus_addr = res->start; wkupm3->mem[i].size = resource_size(res); addrp = of_get_address(dev->of_node, i, &size, NULL); @@ -216,16 +211,10 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) dev_set_drvdata(dev, rproc); ret = rproc_add(rproc); - if (ret) { - dev_err(dev, "rproc_add failed\n"); - goto err_put_rproc; - } + if (ret) + return dev_err_probe(dev, ret, "rproc_add failed\n"); return 0; - -err_put_rproc: - rproc_free(rproc); - return ret; } static void wkup_m3_rproc_remove(struct platform_device *pdev) @@ -233,7 +222,6 @@ static void wkup_m3_rproc_remove(struct platform_device *pdev) struct rproc *rproc = platform_get_drvdata(pdev); rproc_del(rproc); - rproc_free(rproc); } #ifdef CONFIG_PM From 3df0bee9c5b94ca9e3e2ff0f4c4e9886eac86055 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 10:39:40 -0500 Subject: [PATCH 14/29] remoteproc: wkup_m3: Use devm_rproc_add() helper Use the device lifecycle managed add function. This helps prevent mistakes like deleting out of order in cleanup functions and forgetting to delete on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814153940.670564-4-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/wkup_m3_rproc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 30e9ecd75657..2d5bfbefcacc 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -210,20 +210,13 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) dev_set_drvdata(dev, rproc); - ret = rproc_add(rproc); + ret = devm_rproc_add(dev, rproc); if (ret) return dev_err_probe(dev, ret, "rproc_add failed\n"); return 0; } -static void wkup_m3_rproc_remove(struct platform_device *pdev) -{ - struct rproc *rproc = platform_get_drvdata(pdev); - - rproc_del(rproc); -} - #ifdef CONFIG_PM static int wkup_m3_rpm_suspend(struct device *dev) { @@ -242,7 +235,6 @@ static const struct dev_pm_ops wkup_m3_rproc_pm_ops = { static struct platform_driver wkup_m3_rproc_driver = { .probe = wkup_m3_rproc_probe, - .remove = wkup_m3_rproc_remove, .driver = { .name = "wkup_m3_rproc", .of_match_table = wkup_m3_rproc_of_match, From 2433961962be8b8ff32058763339b818128e8ff0 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 24 Aug 2025 21:52:37 +0200 Subject: [PATCH 15/29] remoteproc: k3: Correctly release some resources allocated in k3_rproc_request_mbox() If an error occurs after a successful k3_rproc_request_mbox() call, mbox_free_channel() should be called to avoid a leak. Such a call is missing in the error handling path of k3_dsp_rproc_probe(). It is also missing both in the error handling path of k3_m4_rproc_probe() and in the (in-existent) corresponding remove function. Switch to managed resources to avoid these leaks and simplify the code. Remove the now unneeded mbox_free_channel(). Signed-off-by: Christophe JAILLET Reviewed-by: Beleswar Padhi Tested-by: Beleswar Padhi Link: https://lore.kernel.org/r/df853ede72e9972c464415990b196289680e6acb.1756065142.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mathieu Poirier --- drivers/remoteproc/ti_k3_common.c | 12 ++++++++++++ drivers/remoteproc/ti_k3_dsp_remoteproc.c | 2 -- drivers/remoteproc/ti_k3_r5_remoteproc.c | 2 -- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/remoteproc/ti_k3_common.c b/drivers/remoteproc/ti_k3_common.c index 8266e11914af..56b71652e449 100644 --- a/drivers/remoteproc/ti_k3_common.c +++ b/drivers/remoteproc/ti_k3_common.c @@ -155,11 +155,19 @@ int k3_rproc_release(struct k3_rproc *kproc) } EXPORT_SYMBOL_GPL(k3_rproc_release); +static void k3_rproc_free_channel(void *data) +{ + struct k3_rproc *kproc = data; + + mbox_free_channel(kproc->mbox); +} + int k3_rproc_request_mbox(struct rproc *rproc) { struct k3_rproc *kproc = rproc->priv; struct mbox_client *client = &kproc->client; struct device *dev = kproc->dev; + int ret; client->dev = dev; client->tx_done = NULL; @@ -172,6 +180,10 @@ int k3_rproc_request_mbox(struct rproc *rproc) return dev_err_probe(dev, PTR_ERR(kproc->mbox), "mbox_request_channel failed\n"); + ret = devm_add_action_or_reset(dev, k3_rproc_free_channel, kproc); + if (ret) + return ret; + return 0; } EXPORT_SYMBOL_GPL(k3_rproc_request_mbox); diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c index 7a72933bd403..d6ceea6dc920 100644 --- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c +++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c @@ -175,8 +175,6 @@ static void k3_dsp_rproc_remove(struct platform_device *pdev) if (ret) dev_err(dev, "failed to detach proc (%pe)\n", ERR_PTR(ret)); } - - mbox_free_channel(kproc->mbox); } static const struct k3_rproc_mem_data c66_mems[] = { diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index ca5ff280d2dc..04f23295ffc1 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -1206,8 +1206,6 @@ static void k3_r5_cluster_rproc_exit(void *data) return; } } - - mbox_free_channel(kproc->mbox); } } From ff24e5b26dc6853364b0c006130b653f65a15acd Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:45 +0800 Subject: [PATCH 16/29] remoteproc: imx_rproc: Introduce start/stop/detect_mode ops for imx_rproc_dcfg Simplify the logic in imx_rproc_start(), imx_rproc_stop() and imx_rproc_detect_mode(), introduce start, stop and detect_mode ops for the imx_rproc_dcfg structure. Allow each platform to provide its own implementation of start/stop/detect_mode operations, and prepare to eliminate the need for multiple switch-case statements. Improve code readability and maintainability by encapsulating platform-specific behavior. No functional changes. Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-1-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 15 +++++++++++++++ drivers/remoteproc/imx_rproc.h | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index a6eef0080ca9..5cdc5045e575 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -376,6 +376,11 @@ static int imx_rproc_start(struct rproc *rproc) if (ret) return ret; + if (dcfg->ops && dcfg->ops->start) { + ret = dcfg->ops->start(rproc); + goto start_ret; + } + switch (dcfg->method) { case IMX_RPROC_MMIO: if (priv->gpr) { @@ -398,6 +403,7 @@ static int imx_rproc_start(struct rproc *rproc) return -EOPNOTSUPP; } +start_ret: if (ret) dev_err(dev, "Failed to enable remote core!\n"); @@ -412,6 +418,11 @@ static int imx_rproc_stop(struct rproc *rproc) struct arm_smccc_res res; int ret; + if (dcfg->ops && dcfg->ops->stop) { + ret = dcfg->ops->stop(rproc); + goto stop_ret; + } + switch (dcfg->method) { case IMX_RPROC_MMIO: if (priv->gpr) { @@ -440,6 +451,7 @@ static int imx_rproc_stop(struct rproc *rproc) return -EOPNOTSUPP; } +stop_ret: if (ret) dev_err(dev, "Failed to stop remote core\n"); else @@ -933,6 +945,9 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) u32 val; u8 pt; + if (dcfg->ops && dcfg->ops->detect_mode) + return dcfg->ops->detect_mode(priv->rproc); + switch (dcfg->method) { case IMX_RPROC_NONE: priv->rproc->state = RPROC_DETACHED; diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h index cfd38d37e146..3a9adaaf048b 100644 --- a/drivers/remoteproc/imx_rproc.h +++ b/drivers/remoteproc/imx_rproc.h @@ -31,6 +31,12 @@ enum imx_rproc_method { /* dcfg flags */ #define IMX_RPROC_NEED_SYSTEM_OFF BIT(0) +struct imx_rproc_plat_ops { + int (*start)(struct rproc *rproc); + int (*stop)(struct rproc *rproc); + int (*detect_mode)(struct rproc *rproc); +}; + struct imx_rproc_dcfg { u32 src_reg; u32 src_mask; @@ -42,6 +48,7 @@ struct imx_rproc_dcfg { size_t att_size; enum imx_rproc_method method; u32 flags; + const struct imx_rproc_plat_ops *ops; }; #endif /* _IMX_RPROC_H */ From 11a8d3cb4c624a2b29e2fa1d8b5046f69b71b40f Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:46 +0800 Subject: [PATCH 17/29] remoteproc: imx_rproc: Move imx_rproc_dcfg closer to imx_rproc_of_match Move the imx_rproc_dcfg structure definitions closer to imx_rproc_of_match to prepare for adding start/stop/detect_mode ops for each i.MX variant. This relocation avoids the need to declare function prototypes such as 'static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block)' at the beginning of the file, improving code organization and readability. No functional changes. Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-2-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 158 ++++++++++++++++----------------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 5cdc5045e575..af7b69d750de 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -285,85 +285,6 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { - .src_reg = IMX7D_SRC_SCR, - .src_mask = IMX7D_M4_RST_MASK, - .src_start = IMX7D_M4_START, - .src_stop = IMX8M_M7_STOP, - .gpr_reg = IMX8M_GPR22, - .gpr_wait = IMX8M_GPR22_CM7_CPUWAIT, - .att = imx_rproc_att_imx8mn, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), - .method = IMX_RPROC_MMIO, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { - .att = imx_rproc_att_imx8mn, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), - .method = IMX_RPROC_SMC, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { - .src_reg = IMX7D_SRC_SCR, - .src_mask = IMX7D_M4_RST_MASK, - .src_start = IMX7D_M4_START, - .src_stop = IMX7D_M4_STOP, - .att = imx_rproc_att_imx8mq, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), - .method = IMX_RPROC_MMIO, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { - .att = imx_rproc_att_imx8qm, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8qm), - .method = IMX_RPROC_SCU_API, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qxp = { - .att = imx_rproc_att_imx8qxp, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8qxp), - .method = IMX_RPROC_SCU_API, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = { - .att = imx_rproc_att_imx8ulp, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp), - .method = IMX_RPROC_NONE, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = { - .att = imx_rproc_att_imx7ulp, - .att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp), - .method = IMX_RPROC_NONE, - .flags = IMX_RPROC_NEED_SYSTEM_OFF, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { - .src_reg = IMX7D_SRC_SCR, - .src_mask = IMX7D_M4_RST_MASK, - .src_start = IMX7D_M4_START, - .src_stop = IMX7D_M4_STOP, - .att = imx_rproc_att_imx7d, - .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), - .method = IMX_RPROC_MMIO, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { - .src_reg = IMX6SX_SRC_SCR, - .src_mask = IMX6SX_M4_RST_MASK, - .src_start = IMX6SX_M4_START, - .src_stop = IMX6SX_M4_STOP, - .att = imx_rproc_att_imx6sx, - .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), - .method = IMX_RPROC_MMIO, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { - .att = imx_rproc_att_imx93, - .att_size = ARRAY_SIZE(imx_rproc_att_imx93), - .method = IMX_RPROC_SMC, -}; - static int imx_rproc_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -1222,6 +1143,85 @@ static void imx_rproc_remove(struct platform_device *pdev) destroy_workqueue(priv->workqueue); } +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX8M_M7_STOP, + .gpr_reg = IMX8M_GPR22, + .gpr_wait = IMX8M_GPR22_CM7_CPUWAIT, + .att = imx_rproc_att_imx8mn, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), + .method = IMX_RPROC_MMIO, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { + .att = imx_rproc_att_imx8mn, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), + .method = IMX_RPROC_SMC, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX7D_M4_STOP, + .att = imx_rproc_att_imx8mq, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), + .method = IMX_RPROC_MMIO, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { + .att = imx_rproc_att_imx8qm, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8qm), + .method = IMX_RPROC_SCU_API, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qxp = { + .att = imx_rproc_att_imx8qxp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8qxp), + .method = IMX_RPROC_SCU_API, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = { + .att = imx_rproc_att_imx8ulp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp), + .method = IMX_RPROC_NONE, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = { + .att = imx_rproc_att_imx7ulp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp), + .method = IMX_RPROC_NONE, + .flags = IMX_RPROC_NEED_SYSTEM_OFF, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX7D_M4_STOP, + .att = imx_rproc_att_imx7d, + .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), + .method = IMX_RPROC_MMIO, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { + .src_reg = IMX6SX_SRC_SCR, + .src_mask = IMX6SX_M4_RST_MASK, + .src_start = IMX6SX_M4_START, + .src_stop = IMX6SX_M4_STOP, + .att = imx_rproc_att_imx6sx, + .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), + .method = IMX_RPROC_MMIO, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { + .att = imx_rproc_att_imx93, + .att_size = ARRAY_SIZE(imx_rproc_att_imx93), + .method = IMX_RPROC_SMC, +}; + 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 }, From e14168bf3493aa86dcca1eb2666318a61b450b18 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:47 +0800 Subject: [PATCH 18/29] remoteproc: imx_rproc: Simplify IMX_RPROC_MMIO switch case Introduce imx_rproc_mmio_{start, stop, detect_mode}() helper functions for all i.MX variants using IMX_RPROC_MMIO to manage remote processors. This allows the removal of the IMX_RPROC_MMIO switch-case blocks from imx_rproc_start(), imx_rproc_stop(), and imx_rproc_detect_mode(), resulting in cleaner and more maintainable code. No functional changes. Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-3-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 148 +++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 62 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index af7b69d750de..c37dd6759596 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -285,6 +285,17 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; +static int imx_rproc_mmio_start(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + + if (priv->gpr) + return regmap_clear_bits(priv->gpr, dcfg->gpr_reg, dcfg->gpr_wait); + + return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_start); +} + static int imx_rproc_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -303,16 +314,6 @@ static int imx_rproc_start(struct rproc *rproc) } switch (dcfg->method) { - case IMX_RPROC_MMIO: - if (priv->gpr) { - ret = regmap_clear_bits(priv->gpr, dcfg->gpr_reg, - dcfg->gpr_wait); - } else { - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, - dcfg->src_mask, - dcfg->src_start); - } - break; case IMX_RPROC_SMC: arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); ret = res.a0; @@ -331,6 +332,23 @@ static int imx_rproc_start(struct rproc *rproc) return ret; } +static int imx_rproc_mmio_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + int ret; + + if (priv->gpr) { + ret = regmap_set_bits(priv->gpr, dcfg->gpr_reg, dcfg->gpr_wait); + if (ret) { + dev_err(priv->dev, "Failed to quiescence M4 platform!\n"); + return ret; + } + } + + return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_stop); +} + static int imx_rproc_stop(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -345,20 +363,6 @@ static int imx_rproc_stop(struct rproc *rproc) } switch (dcfg->method) { - case IMX_RPROC_MMIO: - if (priv->gpr) { - ret = regmap_set_bits(priv->gpr, dcfg->gpr_reg, - dcfg->gpr_wait); - if (ret) { - dev_err(priv->dev, - "Failed to quiescence M4 platform!\n"); - return ret; - } - } - - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, - dcfg->src_stop); - break; case IMX_RPROC_SMC: arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); ret = res.a0; @@ -855,15 +859,60 @@ static int imx_rproc_attach_pd(struct imx_rproc *priv) return 0; } -static int imx_rproc_detect_mode(struct imx_rproc *priv) +static int imx_rproc_mmio_detect_mode(struct rproc *rproc) { - struct regmap_config config = { .name = "imx-rproc" }; + const struct regmap_config config = { .name = "imx-rproc" }; + struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; struct regmap *regmap; + u32 val; + int ret; + + priv->gpr = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,iomuxc-gpr"); + if (IS_ERR(priv->gpr)) + priv->gpr = NULL; + + regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to find syscon\n"); + return PTR_ERR(regmap); + } + + priv->regmap = regmap; + regmap_attach_dev(dev, regmap, &config); + + if (priv->gpr) { + ret = regmap_read(priv->gpr, dcfg->gpr_reg, &val); + if (val & dcfg->gpr_wait) { + /* + * After cold boot, the CM indicates its in wait + * state, but not fully powered off. Power it off + * fully so firmware can be loaded into it. + */ + imx_rproc_stop(priv->rproc); + return 0; + } + } + + ret = regmap_read(regmap, dcfg->src_reg, &val); + if (ret) { + dev_err(dev, "Failed to read src\n"); + return ret; + } + + if ((val & dcfg->src_mask) != dcfg->src_stop) + priv->rproc->state = RPROC_DETACHED; + + return 0; +} + +static int imx_rproc_detect_mode(struct imx_rproc *priv) +{ + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device *dev = priv->dev; struct arm_smccc_res res; int ret; - u32 val; u8 pt; if (dcfg->ops && dcfg->ops->detect_mode) @@ -937,41 +986,6 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) break; } - priv->gpr = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,iomuxc-gpr"); - if (IS_ERR(priv->gpr)) - priv->gpr = NULL; - - regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); - if (IS_ERR(regmap)) { - dev_err(dev, "failed to find syscon\n"); - return PTR_ERR(regmap); - } - - priv->regmap = regmap; - regmap_attach_dev(dev, regmap, &config); - - if (priv->gpr) { - ret = regmap_read(priv->gpr, dcfg->gpr_reg, &val); - if (val & dcfg->gpr_wait) { - /* - * After cold boot, the CM indicates its in wait - * state, but not fully powered off. Power it off - * fully so firmware can be loaded into it. - */ - imx_rproc_stop(priv->rproc); - return 0; - } - } - - ret = regmap_read(regmap, dcfg->src_reg, &val); - if (ret) { - dev_err(dev, "Failed to read src\n"); - return ret; - } - - if ((val & dcfg->src_mask) != dcfg->src_stop) - priv->rproc->state = RPROC_DETACHED; - return 0; } @@ -1143,6 +1157,12 @@ static void imx_rproc_remove(struct platform_device *pdev) destroy_workqueue(priv->workqueue); } +static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = { + .start = imx_rproc_mmio_start, + .stop = imx_rproc_mmio_stop, + .detect_mode = imx_rproc_mmio_detect_mode, +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { .src_reg = IMX7D_SRC_SCR, .src_mask = IMX7D_M4_RST_MASK, @@ -1153,6 +1173,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { .att = imx_rproc_att_imx8mn, .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { @@ -1169,6 +1190,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { .att = imx_rproc_att_imx8mq, .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { @@ -1204,6 +1226,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { .att = imx_rproc_att_imx7d, .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { @@ -1214,6 +1237,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { .att = imx_rproc_att_imx6sx, .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { From b7ea858a82194160952875a2e8643ceda1943db5 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:48 +0800 Subject: [PATCH 19/29] remoteproc: imx_rproc: Simplify IMX_RPROC_SCU_API switch case Introduce imx_rproc_scu_api_{start, stop, detect_mode}() helper functions for all i.MX variants using IMX_RPROC_SCU_API to manage remote processors. This allows the removal of the IMX_RPROC_SCU_API switch-case blocks from imx_rproc_start(), imx_rproc_stop(), and imx_rproc_detect_mode(), resulting in cleaner and more maintainable code. No functional changes. Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-4-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 149 +++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 64 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index c37dd6759596..ea34080970c6 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -296,6 +296,13 @@ static int imx_rproc_mmio_start(struct rproc *rproc) return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_start); } +static int imx_rproc_scu_api_start(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + + return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); +} + static int imx_rproc_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -318,9 +325,6 @@ static int imx_rproc_start(struct rproc *rproc) arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); ret = res.a0; break; - case IMX_RPROC_SCU_API: - ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); - break; default: return -EOPNOTSUPP; } @@ -349,6 +353,13 @@ static int imx_rproc_mmio_stop(struct rproc *rproc) return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_stop); } +static int imx_rproc_scu_api_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + + return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry); +} + static int imx_rproc_stop(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -369,9 +380,6 @@ static int imx_rproc_stop(struct rproc *rproc) if (res.a1) dev_info(dev, "Not in wfi, force stopped\n"); break; - case IMX_RPROC_SCU_API: - ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry); - break; default: return -EOPNOTSUPP; } @@ -907,13 +915,73 @@ static int imx_rproc_mmio_detect_mode(struct rproc *rproc) return 0; } +static int imx_rproc_scu_api_detect_mode(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + struct device *dev = priv->dev; + int ret; + u8 pt; + + ret = imx_scu_get_handle(&priv->ipc_handle); + if (ret) + return ret; + ret = of_property_read_u32(dev->of_node, "fsl,resource-id", &priv->rsrc_id); + if (ret) { + dev_err(dev, "No fsl,resource-id property\n"); + return ret; + } + + if (priv->rsrc_id == IMX_SC_R_M4_1_PID0) + priv->core_index = 1; + else + priv->core_index = 0; + + /* + * If Mcore resource is not owned by Acore partition, It is kicked by ROM, + * and Linux could only do IPC with Mcore and nothing else. + */ + if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) { + if (of_property_read_u32(dev->of_node, "fsl,entry-address", &priv->entry)) + return -EINVAL; + + return imx_rproc_attach_pd(priv); + } + + priv->rproc->state = RPROC_DETACHED; + priv->rproc->recovery_disabled = false; + rproc_set_feature(priv->rproc, RPROC_FEAT_ATTACH_ON_RECOVERY); + + /* Get partition id and enable irq in SCFW */ + ret = imx_sc_rm_get_resource_owner(priv->ipc_handle, priv->rsrc_id, &pt); + if (ret) { + dev_err(dev, "not able to get resource owner\n"); + return ret; + } + + priv->rproc_pt = pt; + priv->rproc_nb.notifier_call = imx_rproc_partition_notify; + + ret = imx_scu_irq_register_notifier(&priv->rproc_nb); + if (ret) { + dev_err(dev, "register scu notifier failed, %d\n", ret); + return ret; + } + + ret = imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED, BIT(priv->rproc_pt), + true); + if (ret) { + imx_scu_irq_unregister_notifier(&priv->rproc_nb); + dev_err(dev, "Enable irq failed, %d\n", ret); + return ret; + } + + return 0; +} + static int imx_rproc_detect_mode(struct imx_rproc *priv) { const struct imx_rproc_dcfg *dcfg = priv->dcfg; - struct device *dev = priv->dev; struct arm_smccc_res res; - int ret; - u8 pt; if (dcfg->ops && dcfg->ops->detect_mode) return dcfg->ops->detect_mode(priv->rproc); @@ -927,61 +995,6 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) if (res.a0) priv->rproc->state = RPROC_DETACHED; return 0; - case IMX_RPROC_SCU_API: - ret = imx_scu_get_handle(&priv->ipc_handle); - if (ret) - return ret; - ret = of_property_read_u32(dev->of_node, "fsl,resource-id", &priv->rsrc_id); - if (ret) { - dev_err(dev, "No fsl,resource-id property\n"); - return ret; - } - - if (priv->rsrc_id == IMX_SC_R_M4_1_PID0) - priv->core_index = 1; - else - priv->core_index = 0; - - /* - * If Mcore resource is not owned by Acore partition, It is kicked by ROM, - * and Linux could only do IPC with Mcore and nothing else. - */ - if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) { - if (of_property_read_u32(dev->of_node, "fsl,entry-address", &priv->entry)) - return -EINVAL; - - return imx_rproc_attach_pd(priv); - } - - priv->rproc->state = RPROC_DETACHED; - priv->rproc->recovery_disabled = false; - rproc_set_feature(priv->rproc, RPROC_FEAT_ATTACH_ON_RECOVERY); - - /* Get partition id and enable irq in SCFW */ - ret = imx_sc_rm_get_resource_owner(priv->ipc_handle, priv->rsrc_id, &pt); - if (ret) { - dev_err(dev, "not able to get resource owner\n"); - return ret; - } - - priv->rproc_pt = pt; - priv->rproc_nb.notifier_call = imx_rproc_partition_notify; - - ret = imx_scu_irq_register_notifier(&priv->rproc_nb); - if (ret) { - dev_err(dev, "register scu notifier failed, %d\n", ret); - return ret; - } - - ret = imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED, BIT(priv->rproc_pt), - true); - if (ret) { - imx_scu_irq_unregister_notifier(&priv->rproc_nb); - dev_err(dev, "Enable irq failed, %d\n", ret); - return ret; - } - - return 0; default: break; } @@ -1163,6 +1176,12 @@ static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = { .detect_mode = imx_rproc_mmio_detect_mode, }; +static const struct imx_rproc_plat_ops imx_rproc_ops_scu_api = { + .start = imx_rproc_scu_api_start, + .stop = imx_rproc_scu_api_stop, + .detect_mode = imx_rproc_scu_api_detect_mode, +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { .src_reg = IMX7D_SRC_SCR, .src_mask = IMX7D_M4_RST_MASK, @@ -1197,12 +1216,14 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { .att = imx_rproc_att_imx8qm, .att_size = ARRAY_SIZE(imx_rproc_att_imx8qm), .method = IMX_RPROC_SCU_API, + .ops = &imx_rproc_ops_scu_api, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qxp = { .att = imx_rproc_att_imx8qxp, .att_size = ARRAY_SIZE(imx_rproc_att_imx8qxp), .method = IMX_RPROC_SCU_API, + .ops = &imx_rproc_ops_scu_api, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = { From ecadd767fb83556fe4db599fd5305b08b8328cef Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:49 +0800 Subject: [PATCH 20/29] remoteproc: imx_rproc: Simplify IMX_RPROC_SMC switch case Introduce imx_rproc_arm_smc_{start, stop, detect_mode}() helper functions for all i.MX variants using IMX_RPROC_SMC to manage remote processors. This allows the removal of the IMX_RPROC_SMC switch-case blocks from imx_rproc_start(), imx_rproc_stop(), and imx_rproc_detect_mode(), resulting in cleaner and more maintainable code. Since this is the last switch in imx_rproc_{start,stop}{}, remove the switch-case. No functional changes. Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-5-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 69 +++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index ea34080970c6..5fa729f4286f 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -285,6 +285,15 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; +static int imx_rproc_arm_smc_start(struct rproc *rproc) +{ + struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); + + return res.a0; +} + static int imx_rproc_mmio_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -308,7 +317,6 @@ 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; - struct arm_smccc_res res; int ret; ret = imx_rproc_xtr_mbox_init(rproc, true); @@ -320,14 +328,7 @@ static int imx_rproc_start(struct rproc *rproc) goto start_ret; } - switch (dcfg->method) { - case IMX_RPROC_SMC: - arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); - ret = res.a0; - break; - default: - return -EOPNOTSUPP; - } + return -EOPNOTSUPP; start_ret: if (ret) @@ -336,6 +337,18 @@ static int imx_rproc_start(struct rproc *rproc) return ret; } +static int imx_rproc_arm_smc_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); + if (res.a1) + dev_info(priv->dev, "Not in wfi, force stopped\n"); + + return res.a0; +} + static int imx_rproc_mmio_stop(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -365,7 +378,6 @@ 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; - struct arm_smccc_res res; int ret; if (dcfg->ops && dcfg->ops->stop) { @@ -373,16 +385,7 @@ static int imx_rproc_stop(struct rproc *rproc) goto stop_ret; } - switch (dcfg->method) { - case IMX_RPROC_SMC: - arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); - ret = res.a0; - if (res.a1) - dev_info(dev, "Not in wfi, force stopped\n"); - break; - default: - return -EOPNOTSUPP; - } + return -EOPNOTSUPP; stop_ret: if (ret) @@ -867,6 +870,18 @@ static int imx_rproc_attach_pd(struct imx_rproc *priv) return 0; } +static int imx_rproc_arm_smc_detect_mode(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + priv->rproc->state = RPROC_DETACHED; + + return 0; +} + static int imx_rproc_mmio_detect_mode(struct rproc *rproc) { const struct regmap_config config = { .name = "imx-rproc" }; @@ -981,7 +996,6 @@ 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; - struct arm_smccc_res res; if (dcfg->ops && dcfg->ops->detect_mode) return dcfg->ops->detect_mode(priv->rproc); @@ -990,11 +1004,6 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) case IMX_RPROC_NONE: priv->rproc->state = RPROC_DETACHED; return 0; - case IMX_RPROC_SMC: - arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res); - if (res.a0) - priv->rproc->state = RPROC_DETACHED; - return 0; default: break; } @@ -1170,6 +1179,12 @@ static void imx_rproc_remove(struct platform_device *pdev) destroy_workqueue(priv->workqueue); } +static const struct imx_rproc_plat_ops imx_rproc_ops_arm_smc = { + .start = imx_rproc_arm_smc_start, + .stop = imx_rproc_arm_smc_stop, + .detect_mode = imx_rproc_arm_smc_detect_mode, +}; + static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = { .start = imx_rproc_mmio_start, .stop = imx_rproc_mmio_stop, @@ -1199,6 +1214,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { .att = imx_rproc_att_imx8mn, .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), .method = IMX_RPROC_SMC, + .ops = &imx_rproc_ops_arm_smc, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { @@ -1265,6 +1281,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { .att = imx_rproc_att_imx93, .att_size = ARRAY_SIZE(imx_rproc_att_imx93), .method = IMX_RPROC_SMC, + .ops = &imx_rproc_ops_arm_smc, }; static const struct of_device_id imx_rproc_of_match[] = { From e65a9ed4c3ec11fb40474f3340b9c1e1551c6b7a Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:50 +0800 Subject: [PATCH 21/29] remoteproc: imx_rproc: Clean up after ops introduction With the switch-case in imx_rproc_{start,stop}{} removed, simplify the code logic by removing 'goto'. The last switch-case in imx_rproc_detect_mode() are no longer needed and can be removed. This cleanup improves code readability and aligns with the new ops-based design. No functional changes. Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-6-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 5fa729f4286f..bb25221a4a89 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -323,14 +323,10 @@ static int imx_rproc_start(struct rproc *rproc) if (ret) return ret; - if (dcfg->ops && dcfg->ops->start) { - ret = dcfg->ops->start(rproc); - goto start_ret; - } + if (!dcfg->ops || !dcfg->ops->start) + return -EOPNOTSUPP; - return -EOPNOTSUPP; - -start_ret: + ret = dcfg->ops->start(rproc); if (ret) dev_err(dev, "Failed to enable remote core!\n"); @@ -380,14 +376,10 @@ static int imx_rproc_stop(struct rproc *rproc) struct device *dev = priv->dev; int ret; - if (dcfg->ops && dcfg->ops->stop) { - ret = dcfg->ops->stop(rproc); - goto stop_ret; - } + if (!dcfg->ops || !dcfg->ops->stop) + return -EOPNOTSUPP; - return -EOPNOTSUPP; - -stop_ret: + ret = dcfg->ops->stop(rproc); if (ret) dev_err(dev, "Failed to stop remote core\n"); else @@ -997,18 +989,16 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) { const struct imx_rproc_dcfg *dcfg = priv->dcfg; - if (dcfg->ops && dcfg->ops->detect_mode) - return dcfg->ops->detect_mode(priv->rproc); - - switch (dcfg->method) { - case IMX_RPROC_NONE: + /* + * 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. + */ + if (!dcfg->ops || !dcfg->ops->detect_mode) { priv->rproc->state = RPROC_DETACHED; return 0; - default: - break; } - return 0; + return dcfg->ops->detect_mode(priv->rproc); } static int imx_rproc_clk_enable(struct imx_rproc *priv) From 581e3dea0ece4b59cf714c9dfe195a178d3ae13b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 6 Jul 2025 17:47:08 +0300 Subject: [PATCH 22/29] remoteproc: qcom_q6v5_mss: support loading MBN file on msm8974 On MSM8974 / APQ8074, MSM8226 and MSM8926 the MSS requires loading raw MBA image instead of the ELF file. Skip the ELF headers if mba.mbn was specified as the firmware image. Fixes: a5a4e02d083d ("remoteproc: qcom: Add support for parsing fw dt bindings") Signed-off-by: Dmitry Baryshkov Signed-off-by: Dmitry Baryshkov Tested-by: Luca Weiss # msm8974pro-fairphone-fp2 Link: https://lore.kernel.org/r/20250706-msm8974-fix-mss-v4-1-630907dbd898@oss.qualcomm.com [bjorn: Unwrapped the long memcpy line, to taste] Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 0c0199fb0e68..3087d895b87f 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -498,6 +498,8 @@ static void q6v5_debug_policy_load(struct q6v5 *qproc, void *mba_region) release_firmware(dp_fw); } +#define MSM8974_B00_OFFSET 0x1000 + static int q6v5_load(struct rproc *rproc, const struct firmware *fw) { struct q6v5 *qproc = rproc->priv; @@ -516,7 +518,14 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw) return -EBUSY; } - memcpy(mba_region, fw->data, fw->size); + if ((qproc->version == MSS_MSM8974 || + qproc->version == MSS_MSM8226 || + qproc->version == MSS_MSM8926) && + fw->size > MSM8974_B00_OFFSET && + !memcmp(fw->data, ELFMAG, SELFMAG)) + memcpy(mba_region, fw->data + MSM8974_B00_OFFSET, fw->size - MSM8974_B00_OFFSET); + else + memcpy(mba_region, fw->data, fw->size); q6v5_debug_policy_load(qproc, mba_region); memunmap(mba_region); From 24723d7c09ddac90bdd9e9864f92eb43ed70a083 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 15 Sep 2025 13:15:18 +0200 Subject: [PATCH 23/29] dt-bindings: remoteproc: qcom,milos-pas: Document remoteprocs Document the bindings for the ADSP, CDSP, MPSS and WPSS PAS on the Milos (e.g. SM7635) SoC. Signed-off-by: Luca Weiss Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250915-sm7635-remoteprocs-v5-1-96526cac59c6@fairphone.com Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/qcom,milos-pas.yaml | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml new file mode 100644 index 000000000000..c47d97004b33 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml @@ -0,0 +1,198 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/qcom,milos-pas.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Milos SoC Peripheral Authentication Service + +maintainers: + - Luca Weiss + +description: + Qualcomm Milos SoC Peripheral Authentication Service loads and boots firmware + on the Qualcomm DSP Hexagon cores. + +properties: + compatible: + enum: + - qcom,milos-adsp-pas + - qcom,milos-cdsp-pas + - qcom,milos-mpss-pas + - qcom,milos-wpss-pas + + reg: + maxItems: 1 + + clocks: + items: + - description: XO clock + + clock-names: + items: + - const: xo + + interrupts: + minItems: 6 + maxItems: 6 + + interrupt-names: + minItems: 6 + maxItems: 6 + + qcom,qmp: + $ref: /schemas/types.yaml#/definitions/phandle + description: Reference to the AOSS side-channel message RAM. + + smd-edge: false + + firmware-name: + minItems: 1 + items: + - description: Firmware name of the Hexagon core + - description: Firmware name of the Hexagon Devicetree + + memory-region: + minItems: 1 + items: + - description: Memory region for core Firmware authentication + - description: Memory region for Devicetree Firmware authentication + +required: + - compatible + - reg + - memory-region + +allOf: + - $ref: /schemas/remoteproc/qcom,pas-common.yaml# + - if: + properties: + compatible: + enum: + - qcom,milos-adsp-pas + - qcom,milos-cdsp-pas + then: + properties: + memory-region: + minItems: 2 + firmware-name: + minItems: 2 + else: + properties: + memory-region: + maxItems: 1 + firmware-name: + maxItems: 1 + + - if: + properties: + compatible: + contains: + enum: + - qcom,milos-adsp-pas + then: + properties: + power-domains: + items: + - description: LCX power domain + - description: LMX power domain + power-domain-names: + items: + - const: lcx + - const: lmx + + - if: + properties: + compatible: + enum: + - qcom,milos-cdsp-pas + - qcom,milos-wpss-pas + then: + properties: + power-domains: + items: + - description: CX power domain + - description: MX power domain + power-domain-names: + items: + - const: cx + - const: mx + + - if: + properties: + compatible: + enum: + - qcom,milos-mpss-pas + then: + properties: + power-domains: + items: + - description: CX power domain + - description: MSS power domain + power-domain-names: + items: + - const: cx + - const: mss + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + + remoteproc@3000000 { + compatible = "qcom,milos-adsp-pas"; + reg = <0x03000000 0x10000>; + + interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack", + "shutdown-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&rpmhpd RPMHPD_LCX>, + <&rpmhpd RPMHPD_LMX>; + power-domain-names = "lcx", + "lmx"; + + interconnects = <&lpass_ag_noc MASTER_LPASS_PROC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + + memory-region = <&adspslpi_mem>, <&q6_adsp_dtb_mem>; + + firmware-name = "qcom/milos/vendor/device/adsp.mbn", + "qcom/milos/vendor/device/adsp_dtb.mbn"; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&smp2p_adsp_out 0>; + qcom,smem-state-names = "stop"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "lpass"; + qcom,remote-pid = <2>; + + /* ... */ + }; + }; From ef575ff2054ceb2bd6701630db2f3d33f5c1a1cf Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 15 Sep 2025 13:15:19 +0200 Subject: [PATCH 24/29] remoteproc: qcom: pas: Add Milos remoteproc support Add the different remoteprocs found on the Milos SoC: ADSP, CDSP, MPSS and WPSS. Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20250915-sm7635-remoteprocs-v5-2-96526cac59c6@fairphone.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 02e29171cbbe..6fe5ae0a9eb1 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -1256,6 +1256,26 @@ static const struct qcom_pas_data sdx55_mpss_resource = { .ssctl_id = 0x22, }; +static const struct qcom_pas_data milos_cdsp_resource = { + .crash_reason_smem = 601, + .firmware_name = "cdsp.mbn", + .dtb_firmware_name = "cdsp_dtb.mbn", + .pas_id = 18, + .dtb_pas_id = 0x25, + .minidump_id = 7, + .auto_boot = true, + .proxy_pd_names = (char*[]){ + "cx", + "mx", + NULL + }, + .load_state = "cdsp", + .ssr_name = "cdsp", + .sysmon_name = "cdsp", + .ssctl_id = 0x17, + .smem_host_id = 5, +}; + static const struct qcom_pas_data sm8450_mpss_resource = { .crash_reason_smem = 421, .firmware_name = "modem.mdt", @@ -1430,6 +1450,10 @@ static const struct qcom_pas_data sm8750_mpss_resource = { }; static const struct of_device_id qcom_pas_of_match[] = { + { .compatible = "qcom,milos-adsp-pas", .data = &sm8550_adsp_resource}, + { .compatible = "qcom,milos-cdsp-pas", .data = &milos_cdsp_resource}, + { .compatible = "qcom,milos-mpss-pas", .data = &sm8450_mpss_resource}, + { .compatible = "qcom,milos-wpss-pas", .data = &sc7280_wpss_resource}, { .compatible = "qcom,msm8226-adsp-pil", .data = &msm8996_adsp_resource}, { .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource}, { .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init}, From 110be46f5afe27b66caa2d12473a84cd397b1925 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 20 Aug 2025 18:02:33 +0200 Subject: [PATCH 25/29] remoteproc: qcom: q6v5: Avoid disabling handover IRQ twice enable_irq() and disable_irq() are reference counted, so we must make sure that each enable_irq() is always paired with a single disable_irq(). If we call disable_irq() twice followed by just a single enable_irq(), the IRQ will remain disabled forever. For the error handling path in qcom_q6v5_wait_for_start(), disable_irq() will end up being called twice, because disable_irq() also happens in qcom_q6v5_unprepare() when rolling back the call to qcom_q6v5_prepare(). Fix this by dropping disable_irq() in qcom_q6v5_wait_for_start(). Since qcom_q6v5_prepare() is the function that calls enable_irq(), it makes more sense to have the rollback handled always by qcom_q6v5_unprepare(). Fixes: 3b415c8fb263 ("remoteproc: q6v5: Extract common resource handling") Reviewed-by: Dmitry Baryshkov Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20250820-rproc-qcom-q6v5-fixes-v2-1-910b1a3aff71@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index 4ee5e67a9f03..769c6d6d6a73 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -156,9 +156,6 @@ int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout) int ret; ret = wait_for_completion_timeout(&q6v5->start_done, timeout); - if (!ret) - disable_irq(q6v5->handover_irq); - return !ret ? -ETIMEDOUT : 0; } EXPORT_SYMBOL_GPL(qcom_q6v5_wait_for_start); From 54898664e1eb6b5b3e6cdd9343c6eb15da776153 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 20 Aug 2025 18:02:34 +0200 Subject: [PATCH 26/29] remoteproc: qcom: q6v5: Avoid handling handover twice A remoteproc could theoretically signal handover twice. This is unexpected and would break the reference counting for the handover resources (power domains, clocks, regulators, etc), so add a check to prevent that from happening. Reviewed-by: Dmitry Baryshkov Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20250820-rproc-qcom-q6v5-fixes-v2-2-910b1a3aff71@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index 769c6d6d6a73..58d5b85e58cd 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -164,6 +164,11 @@ static irqreturn_t q6v5_handover_interrupt(int irq, void *data) { struct qcom_q6v5 *q6v5 = data; + if (q6v5->handover_issued) { + dev_err(q6v5->dev, "Handover signaled, but it already happened\n"); + return IRQ_HANDLED; + } + if (q6v5->handover) q6v5->handover(q6v5); From 142964960c7c35de5c5f7bdd61c32699de693630 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 20 Aug 2025 18:02:35 +0200 Subject: [PATCH 27/29] remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E The ADSP firmware on X1E has separate firmware binaries for the main firmware and the DTB. The same applies for the "lite" firmware loaded by the boot firmware. When preparing to load the new ADSP firmware we shutdown the lite_pas_id for the main firmware, but we don't shutdown the corresponding lite pas_id for the DTB. The fact that we're leaving it "running" forever becomes obvious if you try to reuse (or just access) the memory region used by the "lite" firmware: The &adsp_boot_mem is accessible, but accessing the &adsp_boot_dtb_mem results in a crash. We don't support reusing the memory regions currently, but nevertheless we should not keep part of the lite firmware running. Fix this by adding the lite_dtb_pas_id and shutting it down as well. We don't have a way to detect if the lite firmware is actually running yet, so ignore the return status of qcom_scm_pas_shutdown() for now. This was already the case before, the assignment to "ret" is not used anywhere. Fixes: 62210f7509e1 ("remoteproc: qcom_q6v5_pas: Unload lite firmware on ADSP") Reviewed-by: Dmitry Baryshkov Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20250820-rproc-qcom-q6v5-fixes-v2-3-910b1a3aff71@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 6fe5ae0a9eb1..2799e7191876 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -42,6 +42,7 @@ struct qcom_pas_data { int pas_id; int dtb_pas_id; int lite_pas_id; + int lite_dtb_pas_id; unsigned int minidump_id; bool auto_boot; bool decrypt_shutdown; @@ -80,6 +81,7 @@ struct qcom_pas { int pas_id; int dtb_pas_id; int lite_pas_id; + int lite_dtb_pas_id; unsigned int minidump_id; int crash_reason_smem; unsigned int smem_host_id; @@ -226,6 +228,8 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) if (pas->lite_pas_id) ret = qcom_scm_pas_shutdown(pas->lite_pas_id); + if (pas->lite_dtb_pas_id) + qcom_scm_pas_shutdown(pas->lite_dtb_pas_id); if (pas->dtb_pas_id) { ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev); @@ -722,6 +726,7 @@ static int qcom_pas_probe(struct platform_device *pdev) pas->minidump_id = desc->minidump_id; pas->pas_id = desc->pas_id; pas->lite_pas_id = desc->lite_pas_id; + pas->lite_dtb_pas_id = desc->lite_dtb_pas_id; pas->info_name = desc->sysmon_name; pas->smem_host_id = desc->smem_host_id; pas->decrypt_shutdown = desc->decrypt_shutdown; @@ -1085,6 +1090,7 @@ static const struct qcom_pas_data x1e80100_adsp_resource = { .pas_id = 1, .dtb_pas_id = 0x24, .lite_pas_id = 0x1f, + .lite_dtb_pas_id = 0x29, .minidump_id = 5, .auto_boot = true, .proxy_pd_names = (char*[]){ From 1ae4e2dbf4cbf7c1ab2bdc89af1dc1a6af4106b3 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 20 Aug 2025 18:02:36 +0200 Subject: [PATCH 28/29] remoteproc: qcom: pas: Drop redundant assignment to ret We don't have a way to detect if the lite firmware is actually running yet, so we should ignore the return status of qcom_scm_pas_shutdown() for now. The assignment to "ret" is not used anywhere, so just drop it. Signed-off-by: Stephan Gerhold Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250820-rproc-qcom-q6v5-fixes-v2-4-910b1a3aff71@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 2799e7191876..e6fc1a6e3d9e 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -227,7 +227,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) pas->firmware = fw; if (pas->lite_pas_id) - ret = qcom_scm_pas_shutdown(pas->lite_pas_id); + qcom_scm_pas_shutdown(pas->lite_pas_id); if (pas->lite_dtb_pas_id) qcom_scm_pas_shutdown(pas->lite_dtb_pas_id); From d41e075b077142bb9ae5df40b9ddf9fd7821a811 Mon Sep 17 00:00:00 2001 From: Zhen Ni Date: Tue, 23 Sep 2025 19:21:09 +0800 Subject: [PATCH 29/29] remoteproc: pru: Fix potential NULL pointer dereference in pru_rproc_set_ctable() pru_rproc_set_ctable() accessed rproc->priv before the IS_ERR_OR_NULL check, which could lead to a null pointer dereference. Move the pru assignment, ensuring we never dereference a NULL rproc pointer. Fixes: 102853400321 ("remoteproc: pru: Add pru_rproc_set_ctable() function") Cc: stable@vger.kernel.org Signed-off-by: Zhen Ni Link: https://lore.kernel.org/r/20250923112109.1165126-1-zhen.ni@easystack.cn Signed-off-by: Mathieu Poirier --- drivers/remoteproc/pru_rproc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index 842e4b6cc5f9..5e3eb7b86a0e 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -340,7 +340,7 @@ EXPORT_SYMBOL_GPL(pru_rproc_put); */ int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr) { - struct pru_rproc *pru = rproc->priv; + struct pru_rproc *pru; unsigned int reg; u32 mask, set; u16 idx; @@ -352,6 +352,7 @@ int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr) if (!rproc->dev.parent || !is_pru_rproc(rproc->dev.parent)) return -ENODEV; + pru = rproc->priv; /* pointer is 16 bit and index is 8-bit so mask out the rest */ idx_mask = (c >= PRU_C28) ? 0xFFFF : 0xFF;