This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit bc44441f9d8af5c60771401a2e893828550f5adc Author: Lourens Naude <[email protected]> AuthorDate: Thu Sep 24 23:02:49 2026 +0100 arch/arm/src/imxrt: Add an RPTUN backend for the RT1170 CM4. The i.MX RT1176 pairs the Cortex-M7 with a Cortex-M4 that NuttX left in ROM-held reset. This backend lets NuttX on the CM7 run the CM4 as an RPTUN remote. The loader writes the CM4 ELF through the LMEM backdoor window, the boot vector goes into IOMUXC_LPSR_GPR0/1 as the backdoor alias of the code TCM (the CM4-native address does not boot, which NXP's MCMGR also assumes), and SRC releases the core. A released slice cannot be held in reset again: a software reset is a pulse after which the core restarts from the boot vector. Stop therefore parks the core in a wfi loop written over the start of its image, and the next start reloads the image. Virtqueue kicks travel on MU-A channel 0. A kick into a full mailbox is coalesced, because the remote rescans every virtqueue on any kick. SRC_SRMR is set so a CM4 lockup resets only the CM4 instead of the whole chip. The board supplies the remote name, the ELF path, the address environment, the boot vector and the autostart choice through imxrt_rptun_init(). Gated by IMXRT_HAVE_CM4, which only the MIMXRT1176 selects; selects DEV_SIMPLE_ADDRENV for libmetal. Assisted-by: Claude:claude-fable-5-1 Signed-off-by: Lourens Naude <[email protected]> --- arch/arm/src/imxrt/CMakeLists.txt | 4 + arch/arm/src/imxrt/Kconfig | 17 + arch/arm/src/imxrt/Make.defs | 4 + arch/arm/src/imxrt/hardware/rt117x/imxrt117x_mu.h | 92 +++++ arch/arm/src/imxrt/hardware/rt117x/imxrt117x_src.h | 84 +++++ arch/arm/src/imxrt/imxrt_periphclks.h | 8 + arch/arm/src/imxrt/imxrt_rptun.c | 411 +++++++++++++++++++++ arch/arm/src/imxrt/imxrt_rptun.h | 83 +++++ 8 files changed, 703 insertions(+) diff --git a/arch/arm/src/imxrt/CMakeLists.txt b/arch/arm/src/imxrt/CMakeLists.txt index 9a2a9aa4293..f7ecd7a1a2f 100644 --- a/arch/arm/src/imxrt/CMakeLists.txt +++ b/arch/arm/src/imxrt/CMakeLists.txt @@ -103,6 +103,10 @@ if(CONFIG_IMXRT_EDMA) endif() endif() +if(CONFIG_IMXRT_RPTUN) + list(APPEND SRCS imxrt_rptun.c) +endif() + if(CONFIG_IMXRT_USDHC) list(APPEND SRCS imxrt_usdhc.c) endif() diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig index b89db3dac00..ec58312062d 100644 --- a/arch/arm/src/imxrt/Kconfig +++ b/arch/arm/src/imxrt/Kconfig @@ -101,6 +101,7 @@ config ARCH_CHIP_MIMXRT1064CVL5A config ARCH_CHIP_MIMXRT1176DVMAA bool "MIMXRT1176DVMAA" select ARCH_FAMILY_IMXRT117x + select IMXRT_HAVE_CM4 select IMXRT_HAVE_LCD select IMXRT_HAVE_USBOTG1 select IMXRT_HAVE_USBOTG2 @@ -390,6 +391,10 @@ config IMXRT_HAVE_LCD bool default n +config IMXRT_HAVE_CM4 + bool + default n + config IMXRT_HAVE_USBOTG1 bool default n @@ -569,6 +574,18 @@ config IMXRT_WDOG default n depends on WATCHDOG +config IMXRT_RPTUN + bool "RPTUN transport to the CM4 core" + default n + depends on IMXRT_HAVE_CM4 && RPTUN + select RPTUN_LOADER + select DEV_SIMPLE_ADDRENV + ---help--- + rpmsg/virtio transport to the Cortex-M4 of the dual-core i.MX RT1170. + The CM7 loads the CM4 ELF, releases the core and signals it over the + MU-A mailbox. The board supplies the memory map and the ELF path + through imxrt_rptun_init(). + menu "FlexIO Peripherals" config IMXRT_FLEXIO1 diff --git a/arch/arm/src/imxrt/Make.defs b/arch/arm/src/imxrt/Make.defs index e7f037dbdf8..fd74819ee10 100644 --- a/arch/arm/src/imxrt/Make.defs +++ b/arch/arm/src/imxrt/Make.defs @@ -99,6 +99,10 @@ CHIP_CSRCS += imxrt_edma.c endif endif +ifeq ($(CONFIG_IMXRT_RPTUN),y) +CHIP_CSRCS += imxrt_rptun.c +endif + ifdef CONFIG_IMXRT_USDHC CHIP_CSRCS += imxrt_usdhc.c endif diff --git a/arch/arm/src/imxrt/hardware/rt117x/imxrt117x_mu.h b/arch/arm/src/imxrt/hardware/rt117x/imxrt117x_mu.h new file mode 100644 index 00000000000..f8368d48a12 --- /dev/null +++ b/arch/arm/src/imxrt/hardware/rt117x/imxrt117x_mu.h @@ -0,0 +1,92 @@ +/**************************************************************************** + * arch/arm/src/imxrt/hardware/rt117x/imxrt117x_mu.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMXRT_HARDWARE_RT117X_IMXRT117X_MU_H +#define __ARCH_ARM_SRC_IMXRT_HARDWARE_RT117X_IMXRT117X_MU_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include "hardware/imxrt_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The i.MX RT117x Messaging Unit is the "v1" MU: 4 transmit and 4 receive + * mailbox registers, one status and one control register per side. + * MU-A is the CM7 side, MU-B is the CM4 side. + */ + +#define IMXRT_MU_CHANNELS 4 + +/* Register Offsets *********************************************************/ + +#define IMXRT_MU_TR_OFFSET(n) (0x0000 + ((n) << 2)) /* Transmit n */ +#define IMXRT_MU_RR_OFFSET(n) (0x0010 + ((n) << 2)) /* Receive n */ +#define IMXRT_MU_SR_OFFSET 0x0020 /* Status */ +#define IMXRT_MU_CR_OFFSET 0x0024 /* Control */ + +/* Register Addresses (CM7 side, MU-A) **************************************/ + +#define IMXRT_MUA_TR(n) (IMXRT_MU_A + IMXRT_MU_TR_OFFSET(n)) +#define IMXRT_MUA_RR(n) (IMXRT_MU_A + IMXRT_MU_RR_OFFSET(n)) +#define IMXRT_MUA_SR (IMXRT_MU_A + IMXRT_MU_SR_OFFSET) +#define IMXRT_MUA_CR (IMXRT_MU_A + IMXRT_MU_CR_OFFSET) + +/* Status Register (SR) *****************************************************/ + +#define MU_SR_F_SHIFT (0) /* Bits 0-2: Other side flags */ +#define MU_SR_F_MASK (7 << MU_SR_F_SHIFT) +#define MU_SR_EP (1 << 4) /* Bit 4: Event pending */ +#define MU_SR_RS (1 << 7) /* Bit 7: Other side reset */ +#define MU_SR_TE_SHIFT (20) /* Bits 20-23: TEn, TE0 is bit 23 */ +#define MU_SR_TE(n) (1 << (23 - (n))) +#define MU_SR_TE_MASK (15 << MU_SR_TE_SHIFT) +#define MU_SR_RF_SHIFT (24) /* Bits 24-27: RFn, RF0 is bit 27 */ +#define MU_SR_RF(n) (1 << (27 - (n))) +#define MU_SR_RF_MASK (15 << MU_SR_RF_SHIFT) +#define MU_SR_GIP_SHIFT (28) /* Bits 28-31: GIP0 is bit 31 */ +#define MU_SR_GIP(n) (1 << (31 - (n))) +#define MU_SR_GIP_MASK (15 << MU_SR_GIP_SHIFT) + +/* Control Register (CR) ****************************************************/ + +#define MU_CR_F_SHIFT (0) /* Bits 0-2: Flags to other side */ +#define MU_CR_F_MASK (7 << MU_CR_F_SHIFT) +#define MU_CR_MUR (1 << 5) /* Bit 5: MU reset */ +#define MU_CR_GIR_SHIFT (16) /* Bits 16-19: GIR0 is bit 19 */ +#define MU_CR_GIR(n) (1 << (19 - (n))) +#define MU_CR_GIR_MASK (15 << MU_CR_GIR_SHIFT) +#define MU_CR_TIE_SHIFT (20) /* Bits 20-23: TIE0 is bit 23 */ +#define MU_CR_TIE(n) (1 << (23 - (n))) +#define MU_CR_TIE_MASK (15 << MU_CR_TIE_SHIFT) +#define MU_CR_RIE_SHIFT (24) /* Bits 24-27: RIE0 is bit 27 */ +#define MU_CR_RIE(n) (1 << (27 - (n))) +#define MU_CR_RIE_MASK (15 << MU_CR_RIE_SHIFT) +#define MU_CR_GIE_SHIFT (28) /* Bits 28-31: GIE0 is bit 31 */ +#define MU_CR_GIE(n) (1 << (31 - (n))) +#define MU_CR_GIE_MASK (15 << MU_CR_GIE_SHIFT) + +#endif /* __ARCH_ARM_SRC_IMXRT_HARDWARE_RT117X_IMXRT117X_MU_H */ diff --git a/arch/arm/src/imxrt/hardware/rt117x/imxrt117x_src.h b/arch/arm/src/imxrt/hardware/rt117x/imxrt117x_src.h new file mode 100644 index 00000000000..6f4483761e8 --- /dev/null +++ b/arch/arm/src/imxrt/hardware/rt117x/imxrt117x_src.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * arch/arm/src/imxrt/hardware/rt117x/imxrt117x_src.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMXRT_HARDWARE_RT117X_IMXRT117X_SRC_H +#define __ARCH_ARM_SRC_IMXRT_HARDWARE_RT117X_IMXRT117X_SRC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include "hardware/imxrt_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* System Reset Controller. Partial: the registers that boot, hold and + * diagnose the CM4 (RM chapter 25); the per-slice authentication and the + * other reset slices are not described yet. + */ + +#define IMXRT_SRC_SCR_OFFSET 0x0000 /* SRC Control */ +#define IMXRT_SRC_SRMR_OFFSET 0x0004 /* SRC Reset Mode */ +#define IMXRT_SRC_SRSR_OFFSET 0x0010 /* SRC Reset Status */ +#define IMXRT_SRC_CTRL_M4CORE_OFFSET 0x0284 /* M4 core slice control */ +#define IMXRT_SRC_STAT_M4CORE_OFFSET 0x0290 /* M4 core slice status */ + +#define IMXRT_SRC_SCR (IMXRT_SRC_BASE + IMXRT_SRC_SCR_OFFSET) +#define IMXRT_SRC_SRMR (IMXRT_SRC_BASE + IMXRT_SRC_SRMR_OFFSET) +#define IMXRT_SRC_SRSR (IMXRT_SRC_BASE + IMXRT_SRC_SRSR_OFFSET) +#define IMXRT_SRC_CTRL_M4CORE (IMXRT_SRC_BASE + IMXRT_SRC_CTRL_M4CORE_OFFSET) +#define IMXRT_SRC_STAT_M4CORE (IMXRT_SRC_BASE + IMXRT_SRC_STAT_M4CORE_OFFSET) + +#define SRC_SCR_BT_RELEASE_M4 (1 << 0) /* Release CM4 from reset */ + +/* Reset mode per source: 0 resets the system, 3 resets nothing. */ + +#define SRC_SRMR_M4LOCKUP_SHIFT (6) +#define SRC_SRMR_M4LOCKUP_MASK (3 << SRC_SRMR_M4LOCKUP_SHIFT) +#define SRC_SRMR_M4LOCKUP_NONE (3 << SRC_SRMR_M4LOCKUP_SHIFT) + +/* Reset status: sticky causes, write 1 to clear. */ + +#define SRC_SRSR_M7_LOCKUP (1 << 2) /* CM7 lockup */ +#define SRC_SRSR_WDOG (1 << 5) /* WDOG1 timeout */ +#define SRC_SRSR_M4_LOCKUP (1 << 12) /* CM4 lockup */ + +#define SRC_CTRL_M4CORE_SW_RESET (1 << 0) /* Software reset of CM4 slice */ +#define SRC_STAT_M4CORE_UNDER_RST (1 << 0) /* CM4 slice in reset */ + +/* IOMUXC LPSR GPR0/1 hold the CM4 initial vector table address. */ + +#define IMXRT_IOMUXC_LPSR_GPR_GPR0_OFFSET (0x0000) +#define IMXRT_IOMUXC_LPSR_GPR_GPR1_OFFSET (0x0004) + +#define IMXRT_IOMUXC_LPSR_GPR_GPR0 (IMXRT_IOMUXCLPSRGPR_BASE + IMXRT_IOMUXC_LPSR_GPR_GPR0_OFFSET) +#define IMXRT_IOMUXC_LPSR_GPR_GPR1 (IMXRT_IOMUXCLPSRGPR_BASE + IMXRT_IOMUXC_LPSR_GPR_GPR1_OFFSET) + +/* GPR0[15:3] holds VTOR[15:3], GPR1[15:0] holds VTOR[31:16]. */ + +#define GPR0_CM4_INIT_VTOR_LOW(vtor) ((vtor) & 0x0000fff8) +#define GPR1_CM4_INIT_VTOR_HIGH(vtor) (((vtor) >> 16) & 0x0000ffff) + +#endif /* __ARCH_ARM_SRC_IMXRT_HARDWARE_RT117X_IMXRT117X_SRC_H */ diff --git a/arch/arm/src/imxrt/imxrt_periphclks.h b/arch/arm/src/imxrt/imxrt_periphclks.h index b8d700a3e72..127432bb5ec 100644 --- a/arch/arm/src/imxrt/imxrt_periphclks.h +++ b/arch/arm/src/imxrt/imxrt_periphclks.h @@ -173,6 +173,10 @@ # define imxrt_clockoff_lpuart12() imxrt_periphclk_configure(CCM_CCGR_LPUART12, CCM_CG_OFF) #endif #define imxrt_clockoff_mqs() imxrt_periphclk_configure(CCM_CCGR_MQS, CCM_CG_OFF) +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x +# define imxrt_clockoff_mu_a() imxrt_periphclk_configure(CCM_CCGR_MU_A, CCM_CG_OFF) +# define imxrt_clockoff_mu_b() imxrt_periphclk_configure(CCM_CCGR_MU_B, CCM_CG_OFF) +#endif #define imxrt_clockoff_ocotp_ctrl() imxrt_periphclk_configure(CCM_CCGR_OCOTP_CTRL, CCM_CG_OFF) #define imxrt_clockoff_ocram() imxrt_periphclk_configure(CCM_CCGR_OCRAM, CCM_CG_OFF) #define imxrt_clockoff_pit() imxrt_periphclk_configure(CCM_CCGR_PIT, CCM_CG_OFF) @@ -513,6 +517,10 @@ # define imxrt_clockall_lpuart12() imxrt_periphclk_configure(CCM_CCGR_LPUART12, CCM_CG_ALL) #endif #define imxrt_clockall_mqs() imxrt_periphclk_configure(CCM_CCGR_MQS, CCM_CG_ALL) +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x +# define imxrt_clockall_mu_a() imxrt_periphclk_configure(CCM_CCGR_MU_A, CCM_CG_ALL) +# define imxrt_clockall_mu_b() imxrt_periphclk_configure(CCM_CCGR_MU_B, CCM_CG_ALL) +#endif #define imxrt_clockall_ocotp_ctrl() imxrt_periphclk_configure(CCM_CCGR_OCOTP_CTRL, CCM_CG_ALL) #define imxrt_clockall_ocram() imxrt_periphclk_configure(CCM_CCGR_OCRAM, CCM_CG_ALL) #define imxrt_clockall_pit() imxrt_periphclk_configure(CCM_CCGR_PIT, CCM_CG_ALL) diff --git a/arch/arm/src/imxrt/imxrt_rptun.c b/arch/arm/src/imxrt/imxrt_rptun.c new file mode 100644 index 00000000000..b34486bdc55 --- /dev/null +++ b/arch/arm/src/imxrt/imxrt_rptun.c @@ -0,0 +1,411 @@ +/**************************************************************************** + * arch/arm/src/imxrt/imxrt_rptun.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <errno.h> +#include <debug.h> +#include <inttypes.h> + +#include <nuttx/arch.h> +#include <nuttx/cache.h> +#include <nuttx/irq.h> +#include <nuttx/nuttx.h> +#include <nuttx/rptun/rptun.h> + +#include "arm_internal.h" +#include "imxrt_periphclks.h" +#include "imxrt_rptun.h" +#include "hardware/rt117x/imxrt117x_mu.h" +#include "hardware/rt117x/imxrt117x_src.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Kicks travel on MU channel 0 in both directions. The word carries no + * information: either side rescans every virtqueue on any kick. + */ + +#define IMXRT_RPTUN_MU_CHAN 0 +#define IMXRT_RPTUN_KICK 1 + +/* Wait for the M4 slice to leave reset: 1000 x 10 us. */ + +#define IMXRT_RPTUN_RESET_RETRIES 1000 +#define IMXRT_RPTUN_RESET_DELAY 10 + +/* Once released, the M4 slice cannot be held in reset again: a software + * reset is a pulse and the core restarts from CM4_INIT_VTOR. To stop the + * core we point its reset vector at a two-instruction park loop written + * over the start of its image, then pulse the reset. + * + * boot + 0: initial SP (top of the CM4 system TCM) + * boot + 4: reset handler (boot + 8, Thumb) + * boot + 8: wfi; b .-2 (0xBF30, 0xE7FD) + */ + +#define IMXRT_RPTUN_PARK_SP 0x20020000 +#define IMXRT_RPTUN_PARK_CODE 0xE7FDBF30 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct imxrt_rptun_dev_s +{ + struct rptun_dev_s rptun; + const struct imxrt_rptun_config_s *cfg; + rptun_callback_t callback; + void *arg; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static const char *imxrt_rptun_get_cpuname(struct rptun_dev_s *dev); +static const char *imxrt_rptun_get_firmware(struct rptun_dev_s *dev); +static const struct rptun_addrenv_s * +imxrt_rptun_get_addrenv(struct rptun_dev_s *dev); +static bool imxrt_rptun_is_autostart(struct rptun_dev_s *dev); +static bool imxrt_rptun_is_master(struct rptun_dev_s *dev); +static int imxrt_rptun_start(struct rptun_dev_s *dev); +static int imxrt_rptun_stop(struct rptun_dev_s *dev); +static int imxrt_rptun_notify(struct rptun_dev_s *dev, uint32_t vqid); +static int imxrt_rptun_register_callback(struct rptun_dev_s *dev, + rptun_callback_t callback, + void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct rptun_ops_s g_imxrt_rptun_ops = +{ + .get_cpuname = imxrt_rptun_get_cpuname, + .get_firmware = imxrt_rptun_get_firmware, + .get_addrenv = imxrt_rptun_get_addrenv, + .is_autostart = imxrt_rptun_is_autostart, + .is_master = imxrt_rptun_is_master, + .start = imxrt_rptun_start, + .stop = imxrt_rptun_stop, + .notify = imxrt_rptun_notify, + .register_callback = imxrt_rptun_register_callback, +}; + +static struct imxrt_rptun_dev_s g_imxrt_rptun; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static const char *imxrt_rptun_get_cpuname(struct rptun_dev_s *dev) +{ + struct imxrt_rptun_dev_s *priv = + container_of(dev, struct imxrt_rptun_dev_s, rptun); + + return priv->cfg->cpuname; +} + +static const char *imxrt_rptun_get_firmware(struct rptun_dev_s *dev) +{ + struct imxrt_rptun_dev_s *priv = + container_of(dev, struct imxrt_rptun_dev_s, rptun); + + return priv->cfg->firmware; +} + +static const struct rptun_addrenv_s * +imxrt_rptun_get_addrenv(struct rptun_dev_s *dev) +{ + struct imxrt_rptun_dev_s *priv = + container_of(dev, struct imxrt_rptun_dev_s, rptun); + + return priv->cfg->addrenv; +} + +static bool imxrt_rptun_is_autostart(struct rptun_dev_s *dev) +{ + struct imxrt_rptun_dev_s *priv = + container_of(dev, struct imxrt_rptun_dev_s, rptun); + + return priv->cfg->autostart; +} + +static bool imxrt_rptun_is_master(struct rptun_dev_s *dev) +{ + return true; +} + +/**************************************************************************** + * Name: imxrt_rptun_start + * + * Description: + * Called by rptun after the ELF is loaded and the virtio device is + * DRIVER_OK. Publish the boot vector and release the CM4. + * + ****************************************************************************/ + +static int imxrt_rptun_start(struct rptun_dev_s *dev) +{ + struct imxrt_rptun_dev_s *priv = + container_of(dev, struct imxrt_rptun_dev_s, rptun); + const struct rptun_addrenv_s *env; + uint32_t vtor; + int retries = IMXRT_RPTUN_RESET_RETRIES; + + /* The loader wrote the image through the (possibly cached) OCRAM_M4 + * alias; make sure the CM4 sees it before it starts fetching. + */ + + for (env = priv->cfg->addrenv; env != NULL && env->size != 0; env++) + { + up_clean_dcache(env->pa, env->pa + env->size); + } + + putreg32(GPR0_CM4_INIT_VTOR_LOW(priv->cfg->boot_addr), + IMXRT_IOMUXC_LPSR_GPR_GPR0); + putreg32(GPR1_CM4_INIT_VTOR_HIGH(priv->cfg->boot_addr), + IMXRT_IOMUXC_LPSR_GPR_GPR1); + + vtor = (getreg32(IMXRT_IOMUXC_LPSR_GPR_GPR1) & 0xffff) << 16 | + (getreg32(IMXRT_IOMUXC_LPSR_GPR_GPR0) & 0xfff8); + if (vtor != priv->cfg->boot_addr) + { + ipcerr("ERROR: CM4 VTOR readback %08" PRIx32 " != %08" PRIxPTR "\n", + vtor, priv->cfg->boot_addr); + return -EIO; + } + + /* The slice stays in reset until the first release, so only re-reset a + * core that is already running (restart, or released by a debugger). + */ + + if ((getreg32(IMXRT_SRC_SCR) & SRC_SCR_BT_RELEASE_M4) != 0) + { + putreg32(SRC_CTRL_M4CORE_SW_RESET, IMXRT_SRC_CTRL_M4CORE); + while ((getreg32(IMXRT_SRC_STAT_M4CORE) & + SRC_STAT_M4CORE_UNDER_RST) != 0) + { + if (--retries == 0) + { + ipcerr("ERROR: CM4 slice did not leave reset\n"); + return -ETIMEDOUT; + } + + up_udelay(IMXRT_RPTUN_RESET_DELAY); + } + } + + modifyreg32(IMXRT_SRC_SCR, 0, SRC_SCR_BT_RELEASE_M4); + + ipcinfo("CM4 released, VTOR=%08" PRIxPTR "\n", priv->cfg->boot_addr); + return OK; +} + +static int imxrt_rptun_stop(struct rptun_dev_s *dev) +{ + struct imxrt_rptun_dev_s *priv = + container_of(dev, struct imxrt_rptun_dev_s, rptun); + uintptr_t boot = priv->cfg->boot_addr; + + /* Park the core: write the loop over the image start, then reset the + * slice so it restarts into the loop. The next start reloads the image. + */ + + putreg32(IMXRT_RPTUN_PARK_SP, boot); + putreg32((boot + 8) | 1, boot + 4); + putreg32(IMXRT_RPTUN_PARK_CODE, boot + 8); + up_clean_dcache(boot, boot + 12); + + putreg32(SRC_CTRL_M4CORE_SW_RESET, IMXRT_SRC_CTRL_M4CORE); + return OK; +} + +/**************************************************************************** + * Name: imxrt_rptun_notify + * + * Description: + * Kick the CM4. TEn clears on write and returns once the CM4 has read + * RRn; a full mailbox means a kick is already pending and the CM4 rescans + * everything when it takes it, so coalesce rather than spin: rptun kicks + * before the CM4 is even released from reset. + * + ****************************************************************************/ + +static int imxrt_rptun_notify(struct rptun_dev_s *dev, uint32_t vqid) +{ + irqstate_t flags = enter_critical_section(); + + if ((getreg32(IMXRT_MUA_SR) & MU_SR_TE(IMXRT_RPTUN_MU_CHAN)) != 0) + { + putreg32(IMXRT_RPTUN_KICK, IMXRT_MUA_TR(IMXRT_RPTUN_MU_CHAN)); + } + + leave_critical_section(flags); + return OK; +} + +static int imxrt_rptun_register_callback(struct rptun_dev_s *dev, + rptun_callback_t callback, + void *arg) +{ + struct imxrt_rptun_dev_s *priv = + container_of(dev, struct imxrt_rptun_dev_s, rptun); + + priv->callback = callback; + priv->arg = arg; + return OK; +} + +/**************************************************************************** + * Name: imxrt_rptun_mu_interrupt + * + * Description: + * The CM4 kicked. Reading RRn clears RFn; rptun scans every virtqueue. + * + ****************************************************************************/ + +static int imxrt_rptun_mu_interrupt(int irq, void *context, void *arg) +{ + struct imxrt_rptun_dev_s *priv = arg; + uint32_t sr = getreg32(IMXRT_MUA_SR); + int chan; + + for (chan = 0; chan < IMXRT_MU_CHANNELS; chan++) + { + if ((sr & MU_SR_RF(chan)) != 0) + { + (void)getreg32(IMXRT_MUA_RR(chan)); + } + } + + if ((sr & MU_SR_GIP_MASK) != 0) + { + putreg32(sr & MU_SR_GIP_MASK, IMXRT_MUA_SR); + } + + if ((sr & MU_SR_RF(IMXRT_RPTUN_MU_CHAN)) != 0 && priv->callback != NULL) + { + priv->callback(priv->arg, RPTUN_NOTIFY_ALL); + } + + return OK; +} + +/**************************************************************************** + * Name: imxrt_rptun_mu_init + * + * Description: + * Bring up MU-A without resetting the unit (MUR also resets the CM4 + * side): clock both sides, drain the receive mailboxes, clear the + * general interrupt flags, then enable the channel 0 receive interrupt. + * + ****************************************************************************/ + +static int imxrt_rptun_mu_init(struct imxrt_rptun_dev_s *priv) +{ + int ret; + int chan; + + imxrt_clockall_mu_a(); + imxrt_clockall_mu_b(); + + putreg32(0, IMXRT_MUA_CR); + for (chan = 0; chan < IMXRT_MU_CHANNELS; chan++) + { + (void)getreg32(IMXRT_MUA_RR(chan)); + } + + putreg32(MU_SR_GIP_MASK, IMXRT_MUA_SR); + + ret = irq_attach(IMXRT_IRQ_MU, imxrt_rptun_mu_interrupt, priv); + if (ret < 0) + { + imxrt_clockoff_mu_b(); + imxrt_clockoff_mu_a(); + return ret; + } + + putreg32(MU_CR_RIE(IMXRT_RPTUN_MU_CHAN), IMXRT_MUA_CR); + up_enable_irq(IMXRT_IRQ_MU); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int imxrt_rptun_init(const struct imxrt_rptun_config_s *cfg) +{ + struct imxrt_rptun_dev_s *priv = &g_imxrt_rptun; + int ret; + + if (cfg == NULL || cfg->cpuname == NULL || cfg->firmware == NULL || + cfg->addrenv == NULL) + { + return -EINVAL; + } + + if (priv->cfg != NULL) + { + return -EBUSY; + } + + /* A CM4 lockup would otherwise reset the whole chip. The CM7 owns the + * remote (stop/start), so keep the reset local to the CM4. + */ + + modifyreg32(IMXRT_SRC_SRMR, SRC_SRMR_M4LOCKUP_MASK, + SRC_SRMR_M4LOCKUP_NONE); + + priv->cfg = cfg; + priv->rptun.ops = &g_imxrt_rptun_ops; + + ret = imxrt_rptun_mu_init(priv); + if (ret < 0) + { + goto errout; + } + + ret = rptun_initialize(&priv->rptun); + if (ret < 0) + { + ipcerr("ERROR: rptun_initialize failed: %d\n", ret); + up_disable_irq(IMXRT_IRQ_MU); + irq_detach(IMXRT_IRQ_MU); + imxrt_clockoff_mu_b(); + imxrt_clockoff_mu_a(); + goto errout; + } + + return OK; + +errout: + priv->cfg = NULL; + return ret; +} diff --git a/arch/arm/src/imxrt/imxrt_rptun.h b/arch/arm/src/imxrt/imxrt_rptun.h new file mode 100644 index 00000000000..61c63f8a43a --- /dev/null +++ b/arch/arm/src/imxrt/imxrt_rptun.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * arch/arm/src/imxrt/imxrt_rptun.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMXRT_IMXRT_RPTUN_H +#define __ARCH_ARM_SRC_IMXRT_IMXRT_RPTUN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include <nuttx/rptun/rptun.h> + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Board-supplied description of the CM4 remote. The CM7 is always the + * rptun master: it loads the CM4 ELF (whose .resource_table carries the + * vdev/vring description), fills in the vring addresses, then releases the + * CM4 from reset. Kicks are coalesced in the MU mailbox, so the remote + * must read MU-B RR0 before it scans its virtqueues; a kick that arrives + * while the mailbox is full is covered by that scan. + */ + +struct imxrt_rptun_config_s +{ + const char *cpuname; /* Remote name, e.g. "cm4" -> /dev/rptun/cm4 */ + const char *firmware; /* ELF path passed to the rptun loader */ + + /* CM4 device address -> CM7 physical address map, terminated by + * an entry with size 0. Must cover every ELF segment and the shared + * memory region. + */ + + const struct rptun_addrenv_s *addrenv; + + uintptr_t boot_addr; /* Value programmed into CM4_INIT_VTOR */ + bool autostart; /* Start the remote from rptun_initialize() */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imxrt_rptun_init + * + * Description: + * Register the CM4 as an rptun device. cfg must stay valid for the life + * of the system. The board maps the memory the CM4 writes (vrings, + * rpmsg buffers) as non-cacheable before calling this. The remote is + * not started; use RPTUNIOC_START on the character device or + * rptun_boot(cpuname). + * + ****************************************************************************/ + +int imxrt_rptun_init(const struct imxrt_rptun_config_s *cfg); + +#endif /* __ARCH_ARM_SRC_IMXRT_IMXRT_RPTUN_H */
