summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-14 11:17:54 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-14 11:17:54 -0800
commit2bfc50c6e6e67b08770c6ef46660c3ee9c6a1519 (patch)
tree7ca6fabb929c1ab36d348d006407aafefcb9b0db /drivers
parentf0a475aedd190db95cf92914ca7760c06fbdb704 (diff)
parent26aa5295010ffaebcf8f1991c53fa7cf2ee1b20d (diff)
Merge tag 'rproc-v7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux
Pull remoteproc updates from Bjorn Andersson: - Fix a memory remapping issue and make a few life-cycle improvements in the i.MX HiFi remoteproc driver - Add support the System Manager CPU and LMM APIs and use this to support i.MX95 - Rework the handling of the Mediatek SCP clock to avoid a potential circular deadlock in the clock providers - Refactor the Qualcomm secure-world helpers and add support in the Qualcomm PAS remoteproc driver for reading a resource-table from secure world. Use this to configure the IOMMU on newer targets where Linux runs in EL2 * tag 'rproc-v7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: remoteproc: imx_rproc: Fix invalid loaded resource table detection remoteproc: mediatek: Break lock dependency to `prepare_lock` remoteproc: imx_rproc: Add support for i.MX95 remoteproc: imx_rproc: Add support for System Manager CPU API remoteproc: imx_rproc: Add support for System Manager LMM API remoteproc: imx_rproc: Introduce prepare ops for imx_rproc_dcfg remoteproc: imx_rproc: Add runtime ops copy to support dynamic behavior dt-bindings: remoteproc: fsl,imx-rproc: Add support for i.MX95 dt-bindings: remoteproc: Add HSM M4F core on TI K3 SoCs remoteproc: xlnx_r5: Simplify with scoped for each OF child loop remoteproc: mtk_scp: Simplify with scoped for each OF child loop remoteproc: imx_dsp_rproc: Only reset carveout memory at RPROC_OFFLINE state dt-bindings: remoteproc: qcom,sm8550-pas: Drop SM8750 ADSP from if-branch dt-bindings: remoteproc: qcom,adsp: Allow cx-supply on qcom,sdm845-slpi-pas remoteproc: imx_dsp_rproc: Fix multiple start/stop operations remoteproc: imx_rproc: Use strstarts for "rsc-table" check remoteproc: imx_dsp_rproc: Wait for suspend ACK only if WAIT_FW_CONFIRMATION is set remoteproc: imx_dsp_rproc: Rename macro to reflect multiple contexts remoteproc: imx_dsp_rproc: Skip RP_MBOX_SUSPEND_SYSTEM when mailbox TX channel is uninitialized dt-bindings: remoteproc: Fix dead link to Keystone DSP GPIO binding
Diffstat (limited to 'drivers')
-rw-r--r--drivers/remoteproc/Kconfig2
-rw-r--r--drivers/remoteproc/imx_dsp_rproc.c95
-rw-r--r--drivers/remoteproc/imx_rproc.c255
-rw-r--r--drivers/remoteproc/imx_rproc.h4
-rw-r--r--drivers/remoteproc/mtk_scp.c46
-rw-r--r--drivers/remoteproc/mtk_scp_ipi.c4
-rw-r--r--drivers/remoteproc/xlnx_r5_remoteproc.c9
7 files changed, 344 insertions, 71 deletions
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_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index 5130a35214c9..008741af9f11 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;
@@ -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;
@@ -984,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);
@@ -1131,8 +1149,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;
@@ -1242,6 +1260,21 @@ 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;
+ }
+
+ /* 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 */
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 3be8790c14a2..f5f916d67905 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/firmware/imx/sci.h>
+#include <linux/firmware/imx/sm.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mailbox_client.h>
@@ -22,6 +23,7 @@
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/remoteproc.h>
+#include <linux/scmi_imx_protocol.h>
#include <linux/workqueue.h>
#include "imx_rproc.h"
@@ -92,9 +94,16 @@ 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;
+static const struct imx_rproc_plat_ops imx_rproc_ops_sm_cpu;
+
struct imx_rproc {
struct device *dev;
struct regmap *regmap;
@@ -116,6 +125,24 @@ 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;
+ /*
+ * 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_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[] = {
@@ -312,21 +339,62 @@ 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_start(struct rproc *rproc)
+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;
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;
+ struct device *dev = priv->dev;
+ int ret;
+
ret = imx_rproc_xtr_mbox_init(rproc, true);
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");
@@ -369,17 +437,35 @@ 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_stop(struct rproc *rproc)
+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;
+ 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;
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
@@ -486,6 +572,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;
@@ -528,6 +644,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)
@@ -584,12 +705,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)
@@ -609,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;
@@ -694,7 +818,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++;
}
@@ -977,20 +1101,97 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc)
return 0;
}
-static int imx_rproc_detect_mode(struct imx_rproc *priv)
+/* 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) {
+ priv->ops = &imx_rproc_ops_sm_cpu;
+ dev_info(dev, "Using CPU Protocol OPS\n");
+ return 0;
+ }
+
+ 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)
+{
+ /*
* 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 +1241,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) {
@@ -1151,6 +1355,19 @@ 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_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,
@@ -1234,6 +1451,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 },
@@ -1248,6 +1474,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);
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
index 1b2d9f4d6d19..d37e6f90548c 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 {
@@ -37,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 */
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
index db8fd045468d..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,
@@ -1287,7 +1304,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 +1312,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 +1323,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 +1331,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;
}
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;
}
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++;
}