From: Peng Fan Date: Tue, 4 Nov 2025 10:05:51 +0000 (+0800) Subject: remoteproc: Add imx_rproc driver to support NXP i.MX8MP/N X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=640fc920e2b929cd16fe3637a32ba569ef0f6867;p=thirdparty%2Fu-boot.git remoteproc: Add imx_rproc driver to support NXP i.MX8MP/N 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 Signed-off-by: Peng Fan --- diff --git a/MAINTAINERS b/MAINTAINERS index 8c7d0e0ab2f..818a2d74fba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index e9f19a69433..8056f210abc 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -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 diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 47bd57c7890..7ea8023c50b 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -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 index 00000000000..1b2ef5005e3 --- /dev/null +++ b/drivers/remoteproc/imx_rproc.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 NXP + */ + +#include +#include +#include +#include +#include +#include +#include + +#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 index 00000000000..7a82dc4a195 --- /dev/null +++ b/drivers/remoteproc/imx_rproc.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017 Pengutronix, Oleksij Rempel + * 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 */