]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
remoteproc: Add imx_rproc driver to support NXP i.MX8MP/N
authorPeng Fan <peng.fan@nxp.com>
Tue, 4 Nov 2025 10:05:51 +0000 (18:05 +0800)
committerFabio Estevam <festevam@nabladev.com>
Tue, 4 Nov 2025 15:45:30 +0000 (12:45 -0300)
Support i.MX8MP/N with start/stop/device_to_virt/is_running/load
implemented. The device static configuration is mostly reused from
Linux Kernel with adapation to U-Boot dm_rproc_ops.
The booting method:
 - load mmc 2:2 0x90000000 /lib/firmware/imx8mp_m7_DDR_rpmsg_lite_str_echo_
   rtos.elf
 - rproc load 0 0x90000000 ${filesize}
 - rproc start 0

Reviewed-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
MAINTAINERS
drivers/remoteproc/Kconfig
drivers/remoteproc/Makefile
drivers/remoteproc/imx_rproc.c [new file with mode: 0644]
drivers/remoteproc/imx_rproc.h [new file with mode: 0644]

index 8c7d0e0ab2f63bbba74c3edd2435fb3b9603e3fe..818a2d74fbad60f0425e3cebc24b6029c2623141 100644 (file)
@@ -319,6 +319,7 @@ F:  board/freescale/common/
 F:     common/spl/spl_imx_container.c
 F:     doc/imx/
 F:     drivers/mailbox/imx-mailbox.c
+F:     drivers/remoteproc/imx*
 F:     drivers/serial/serial_mxc.c
 F:     include/imx_container.h
 
index e9f19a694332bf255c0144467264193873dd6384..8056f210abc895ee0e4866679090cc47cce9e7ae 100644 (file)
@@ -33,6 +33,13 @@ config REMOTEPROC_ADI_SC5XX
          Say 'y' here to add support for loading code onto SHARC cores in
          an ADSP-SC5xx SoC from Analog Devices
 
+config REMOTEPROC_IMX
+       bool "Support for NXP i.MX remoteproc"
+       select REMOTEPROC
+       depends on DM && MACH_IMX && OF_CONTROL
+       help
+         Say 'y' here to add support for i.MX remoteproc.
+
 config REMOTEPROC_RENESAS_APMU
        bool "Support for Renesas R-Car Gen4 APMU start of CR52 processor"
        select REMOTEPROC
index 47bd57c7890d9b14cc53da59616ed59ea2eba47b..7ea8023c50bb8ca34cd142260a9cafa8040c5560 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_$(PHASE_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
 # Remote proc drivers - Please keep this list alphabetically sorted.
 obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
 obj-$(CONFIG_REMOTEPROC_ADI_SC5XX) += adi_sc5xx_rproc.o
+obj-$(CONFIG_REMOTEPROC_IMX) += imx_rproc.o
 obj-$(CONFIG_REMOTEPROC_RENESAS_APMU) += renesas_apmu.o
 obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
 obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
new file mode 100644 (file)
index 0000000..1b2ef50
--- /dev/null
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/device_compat.h>
+#include <linux/arm-smccc.h>
+#include <linux/types.h>
+#include <remoteproc.h>
+
+#include "imx_rproc.h"
+
+#define IMX_RPROC_MEM_MAX              32
+
+#define IMX_SIP_RPROC                  0xC2000005
+#define IMX_SIP_RPROC_START            0x00
+#define IMX_SIP_RPROC_STARTED          0x01
+#define IMX_SIP_RPROC_STOP             0x02
+
+struct imx_rproc {
+       const struct imx_rproc_dcfg     *dcfg;
+};
+
+/* att flags: lower 16 bits specifying core, higher 16 bits for flags  */
+/* M4 own area. Can be mapped at probe */
+#define ATT_OWN         BIT(31)
+#define ATT_IOMEM       BIT(30)
+
+static int imx_rproc_arm_smc_start(struct udevice *dev)
+{
+       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_start(struct udevice *dev)
+{
+       struct imx_rproc *priv = dev_get_priv(dev);
+       const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+       int ret;
+
+       if (!dcfg->ops || !dcfg->ops->start)
+               return -EOPNOTSUPP;
+
+       ret = dcfg->ops->start(dev);
+       if (ret)
+               dev_err(dev, "Failed to enable remote core!\n");
+
+       return ret;
+}
+
+static int imx_rproc_arm_smc_stop(struct udevice *dev)
+{
+       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(dev, "Not in wfi, force stopped\n");
+
+       return res.a0;
+}
+
+static int imx_rproc_stop(struct udevice *dev)
+{
+       struct imx_rproc *priv = dev_get_priv(dev);
+       const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+       int ret;
+
+       if (!dcfg->ops || !dcfg->ops->stop)
+               return -EOPNOTSUPP;
+
+       ret = dcfg->ops->stop(dev);
+       if (ret)
+               dev_err(dev, "Failed to stop remote core\n");
+
+       return ret;
+}
+
+static int imx_rproc_arm_smc_is_running(struct udevice *dev)
+{
+       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)
+               return 0;
+
+       return 1;
+}
+
+static int imx_rproc_is_running(struct udevice *dev)
+{
+       struct imx_rproc *priv = dev_get_priv(dev);
+       const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+       if (!dcfg->ops || !dcfg->ops->is_running)
+               return 0;
+
+       return dcfg->ops->is_running(dev);
+}
+
+static int imx_rproc_init(struct udevice *dev)
+{
+       return 0;
+}
+
+static int imx_rproc_da_to_sys(struct udevice *dev, u64 da, size_t len, u64 *sys, bool *is_iomem)
+{
+       struct imx_rproc *priv = dev_get_priv(dev);
+       const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+       int i;
+
+       /* parse address translation table */
+       for (i = 0; i < dcfg->att_size; i++) {
+               const struct imx_rproc_att *att = &dcfg->att[i];
+
+               if (da >= att->da && da + len < att->da + att->size) {
+                       unsigned int offset = da - att->da;
+
+                       *sys = att->sa + offset;
+
+                       if (is_iomem)
+                               *is_iomem = att->flags & ATT_IOMEM;
+
+                       return 0;
+               }
+       }
+
+       dev_err(dev, "Translation failed: da = 0x%llx len = 0x%zx\n", da, len);
+
+       return -ENOENT;
+}
+
+static void *imx_rproc_device_to_virt(struct udevice *dev, ulong da, ulong size, bool *is_iomem)
+{
+       u64 sys;
+
+       if (imx_rproc_da_to_sys(dev, da, size, &sys, is_iomem))
+               return NULL;
+
+       dev_dbg(dev, "da = 0x%lx len = 0x%lx sys = 0x%llx\n", da, size, sys);
+
+       return phys_to_virt(sys);
+}
+
+static int imx_rproc_load(struct udevice *dev, ulong addr, ulong size)
+{
+       return rproc_elf_load_image(dev, addr, size);
+}
+
+static const struct dm_rproc_ops imx_rproc_ops = {
+       .init = imx_rproc_init,
+       .start = imx_rproc_start,
+       .stop = imx_rproc_stop,
+       .load = imx_rproc_load,
+       .device_to_virt = imx_rproc_device_to_virt,
+       .is_running = imx_rproc_is_running,
+};
+
+static int imx_rproc_probe(struct udevice *dev)
+{
+       struct imx_rproc *priv = dev_get_priv(dev);
+       struct imx_rproc_dcfg *dcfg = (struct imx_rproc_dcfg *)dev_get_driver_data(dev);
+       ofnode node;
+
+       node = dev_ofnode(dev);
+
+       priv->dcfg = dcfg;
+
+       return 0;
+}
+
+static const struct imx_rproc_att imx_rproc_att_imx8mn[] = {
+       /* dev addr , sys addr  , size      , flags */
+       /* ITCM   */
+       { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN | ATT_IOMEM },
+       /* OCRAM_S */
+       { 0x00180000, 0x00180000, 0x00009000, 0 },
+       /* OCRAM */
+       { 0x00900000, 0x00900000, 0x00020000, 0 },
+       /* OCRAM */
+       { 0x00920000, 0x00920000, 0x00020000, 0 },
+       /* OCRAM */
+       { 0x00940000, 0x00940000, 0x00050000, 0 },
+       /* QSPI Code - alias */
+       { 0x08000000, 0x08000000, 0x08000000, 0 },
+       /* DDR (Code) - alias */
+       { 0x10000000, 0x40000000, 0x0FFE0000, 0 },
+       /* DTCM */
+       { 0x20000000, 0x00800000, 0x00020000, ATT_OWN | ATT_IOMEM },
+       /* OCRAM_S - alias */
+       { 0x20180000, 0x00180000, 0x00008000, ATT_OWN },
+       /* OCRAM */
+       { 0x20200000, 0x00900000, 0x00020000, ATT_OWN },
+       /* OCRAM */
+       { 0x20220000, 0x00920000, 0x00020000, ATT_OWN },
+       /* OCRAM */
+       { 0x20240000, 0x00940000, 0x00040000, ATT_OWN },
+       /* DDR (Data) */
+       { 0x40000000, 0x40000000, 0x80000000, 0 },
+};
+
+static const struct imx_rproc_plat_ops imx_rproc_ops_arm_smc = {
+       .start          = imx_rproc_arm_smc_start,
+       .stop           = imx_rproc_arm_smc_stop,
+       .is_running     = imx_rproc_arm_smc_is_running,
+};
+
+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 udevice_id imx_rproc_ids[] = {
+       { .compatible = "fsl,imx8mn-cm7", .data = (ulong)&imx_rproc_cfg_imx8mn, },
+       { .compatible = "fsl,imx8mp-cm7", .data = (ulong)&imx_rproc_cfg_imx8mn, },
+       {}
+};
+
+U_BOOT_DRIVER(imx_rproc) = {
+       .name = "imx_rproc",
+       .of_match = imx_rproc_ids,
+       .id = UCLASS_REMOTEPROC,
+       .ops = &imx_rproc_ops,
+       .probe = imx_rproc_probe,
+       .priv_auto = sizeof(struct imx_rproc),
+};
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
new file mode 100644 (file)
index 0000000..7a82dc4
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
+ * Copyright 2021 NXP
+ */
+
+#ifndef _IMX_RPROC_H
+#define _IMX_RPROC_H
+
+/* address translation table */
+struct imx_rproc_att {
+       u32 da; /* device address (From Cortex M4 view)*/
+       u32 sa; /* system bus address */
+       u32 size; /* size of reg range */
+       int flags;
+};
+
+/* Remote core start/stop method */
+enum imx_rproc_method {
+       IMX_RPROC_NONE,
+       /* Through syscon regmap */
+       IMX_RPROC_MMIO,
+       /* Through ARM SMCCC */
+       IMX_RPROC_SMC,
+       /* Through System Control Unit API */
+       IMX_RPROC_SCU_API,
+       /* Through Reset Controller API */
+       IMX_RPROC_RESET_CONTROLLER,
+       /* Through System Manager */
+       IMX_RPROC_SM,
+};
+
+/* dcfg flags */
+#define IMX_RPROC_NEED_SYSTEM_OFF      BIT(0)
+
+struct imx_rproc_plat_ops {
+       int (*start)(struct udevice *dev);
+       int (*stop)(struct udevice *dev);
+       int (*is_running)(struct udevice *dev);
+};
+
+struct imx_rproc_dcfg {
+       u32                             src_reg;
+       u32                             src_mask;
+       u32                             src_start;
+       u32                             src_stop;
+       u32                             gpr_reg;
+       u32                             gpr_wait;
+       const struct imx_rproc_att      *att;
+       size_t                          att_size;
+       enum imx_rproc_method           method;
+       u32                             flags;
+       const struct imx_rproc_plat_ops *ops;
+};
+
+#endif /* _IMX_RPROC_H */