From a2edd991597d217d04857c1c83ef2dde034e1720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ula=C5=9F=20Sertan=20Keme=C3=A7?= Date: Sat, 19 Sep 2026 09:24:31 +0300 Subject: [PATCH] arch/arm/am67: Add rptun IPC with the Linux A53 (remoteproc/rpmsg). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Connects the R5F to Linux remoteproc over the NAVSS mailbox. The mailbox ISR only drains the FIFO and acknowledges; OpenAMP delivery is deferred to HPWORK, because the rpmsg rx path takes mutexes and allocates. The resource table publishes two vdevs, rpmsg and virtio-net, leaving every vring address FW_RSC_ADDR_ANY: Linux allocates them from the R5F DMA pool and rejects fixed addresses outside it. Shared IPC memory is mapped Non-cacheable, since the R5F is not coherent with the A53 and cached mappings leave NuttX reading stale vring state. Also drops the duplicate arm_mpu.c from CHIP_CSRCS. Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Ulaş Sertan Kemeç --- arch/arm/Kconfig | 1 + arch/arm/src/am67/CMakeLists.txt | 4 + arch/arm/src/am67/Make.defs | 4 +- arch/arm/src/am67/am67_boot.c | 192 ++++++--- arch/arm/src/am67/am67_mpuinit.c | 9 + arch/arm/src/am67/am67_mpuinit.h | 36 +- arch/arm/src/am67/am67_rptun.c | 392 ++++++++++++++++++ arch/arm/src/am67/am67_rptun.h | 101 +++++ .../arm/am67/t3-gem-o1/configs/nsh/defconfig | 4 +- boards/arm/am67/t3-gem-o1/scripts/sdram.ld | 9 +- boards/arm/am67/t3-gem-o1/src/am67_bringup.c | 20 + 11 files changed, 711 insertions(+), 61 deletions(-) create mode 100644 arch/arm/src/am67/am67_rptun.c create mode 100644 arch/arm/src/am67/am67_rptun.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index eeb8fee95dc..32f1327f33b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -88,6 +88,7 @@ config ARCH_CHIP_AM67 select ARCH_CORTEXR5 select ARCH_HAVE_LOWVECTORS select ARCH_HAVE_TICKLESS + select SCHED_HPWORK if RPTUN ---help--- TI AM67 family diff --git a/arch/arm/src/am67/CMakeLists.txt b/arch/arm/src/am67/CMakeLists.txt index 563fd01fefa..a7327584426 100644 --- a/arch/arm/src/am67/CMakeLists.txt +++ b/arch/arm/src/am67/CMakeLists.txt @@ -23,6 +23,10 @@ set(SRCS am67_boot.c am67_irq.c am67_mpuinit.c am67_pinmux.c am67_serial.c am67_timer.c) +if(CONFIG_RPTUN) + list(APPEND SRCS am67_rptun.c) +endif() + target_link_options(nuttx PRIVATE -Wl,--entry=_vector_start) target_sources(arch PRIVATE ${SRCS}) diff --git a/arch/arm/src/am67/Make.defs b/arch/arm/src/am67/Make.defs index 0ef8b2e80a2..ed55717cf0e 100644 --- a/arch/arm/src/am67/Make.defs +++ b/arch/arm/src/am67/Make.defs @@ -45,4 +45,6 @@ endif ifeq ($(CONFIG_AM67_I2C),y) CHIP_CSRCS += am67_i2c.c endif -CHIP_CSRCS += arm_mpu.c +ifeq ($(CONFIG_RPTUN),y) +CHIP_CSRCS += am67_rptun.c +endif diff --git a/arch/arm/src/am67/am67_boot.c b/arch/arm/src/am67/am67_boot.c index 76e3db760c2..7e20b15ed7f 100644 --- a/arch/arm/src/am67/am67_boot.c +++ b/arch/arm/src/am67/am67_boot.c @@ -31,6 +31,7 @@ #include "am67_mpuinit.h" #include "am67_pinmux.h" +#include "am67_rptun.h" #include "arm.h" /**************************************************************************** @@ -38,99 +39,161 @@ ****************************************************************************/ #define NUM_VRINGS (0x02) -#define RL_BUFFER_COUNT (0x200) +#define RL_BUFFER_COUNT (0x200) /* RPMsg vring buffer count (512) */ +#define NET_BUFFER_COUNT (0x100) /* virtio-net vring buffer count (256) */ #define VRING_ALIGN (0x1000) -#define VRING_SIZE (0x8000) -#define VDEV0_VRING_BASE (0xa2200000) #define RESOURCE_TABLE_BASE (0xa2100000) -#define NO_RESOURCE_ENTRIES (1) +/* Vring device addresses are NOT fixed by the firmware. Linux remoteproc + * allocates each vring as a carveout from the R5F DMA pool (DT reserved + * memory main-r5fss-dma-memory-region@a2000000, 1 MB) and cannot honor + * addresses outside that pool: a fixed da merely produces "Allocated + * carveout doesn't fit device address request" and the host uses its own + * allocation while the device stares at empty memory. FW_RSC_ADDR_ANY + * asks the host to allocate and WRITE THE CHOSEN ADDRESS BACK into this + * table before the R5F boots; rptun then reads the live table and attaches + * to the real rings. The DMA pool lies inside the non-cacheable MPU + * window (am67_mpuinit.h), so coherency is preserved. + */ + +#define FW_RSC_ADDR_ANY (0xffffffffu) + +/* Resource table has 2 entries: vdev[0]=RPMsg, vdev[1]=virtio-net */ +#define NO_RESOURCE_ENTRIES (2) #define RSC_VDEV_FEATURE_NS (1) /* Support name service announcement */ #define RSC_TABLE_VERSION (1) -/**************************************************************************** - * Private Types - ****************************************************************************/ +/* virtio device IDs (from virtio spec) */ +#define VIRTIO_ID_NET_DEV (1) /* VIRTIO_ID_NETWORK */ +#define VIRTIO_ID_RPMSG_DEV (7) /* VIRTIO_ID_RPMSG */ -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ +/* notifyid assignments (must be unique across all resources): + * rpmsg_vring0: 0 + * rpmsg_vring1: 1 + * rpmsg_vdev: 2 + * net_vring0: 3 + * net_vring1: 4 + * net_vdev: 5 + */ /**************************************************************************** * Public Data ****************************************************************************/ -/* Place resource table in special ELF section */ +/* Place extended resource table in special ELF section. + * Linux remoteproc reads this section from the R5F firmware binary to + * discover virtio devices and set up shared-memory vrings. + * + * Layout (all offsets from the start of this struct): + * [0] rpmsg_vdev — RPMsg transport (VIRTIO_ID_RPMSG=7) + * [1] net_vdev — virtio-net (VIRTIO_ID_NETWORK=1) + */ -__attribute__ ((section(".resource_table"))) -const struct rptun_rsc_s g_am67_rsc_table = +__attribute__((section(".resource_table"))) +const struct am67_rsc_s g_am67_rsc_table = { - .rsc_tbl_hdr = + .base = { - RSC_TABLE_VERSION, - NO_RESOURCE_ENTRIES, + .rsc_tbl_hdr = { - 0, 0 + RSC_TABLE_VERSION, + NO_RESOURCE_ENTRIES, + { + 0, 0 + } + }, + + /* Offsets from the start of g_am67_rsc_table to each resource */ + + .offset = + { + offsetof(struct am67_rsc_s, base.rpmsg_vdev), + offsetof(struct am67_rsc_s, net_vdev), + }, + + .log_trace = + { + RSC_TRACE, 0, 0 + }, + + .rpmsg_vdev = /* RPMsg virtio device entry */ + { + RSC_VDEV, + VIRTIO_ID_RPMSG_DEV, + 2, /* notifyid */ + RSC_VDEV_FEATURE_NS, + 0, /* gfeatures */ + 0, /* config_len */ + 0, /* status */ + NUM_VRINGS, + { + 0, 0 + } + }, + + .rpmsg_vring0 = + { + FW_RSC_ADDR_ANY, /* da: host allocates and writes back */ + VRING_ALIGN, + RL_BUFFER_COUNT, + 0, /* notifyid */ + 0 /* pa */ + }, + + .rpmsg_vring1 = + { + FW_RSC_ADDR_ANY, /* da: host allocates and writes back */ + VRING_ALIGN, + RL_BUFFER_COUNT, + 1, /* notifyid */ + 0 /* pa */ + }, + + .config = + { + 0 } }, - .offset = - { - offsetof(struct rptun_rsc_s, rpmsg_vdev) - }, + /* virtio-net vdev entry — Linux creates a virtual Ethernet interface + * backed by standard virtio_net.ko. NuttX's virtio-net driver + * (CONFIG_DRIVERS_VIRTIO_NET) handles the R5F side. + */ - .log_trace = - { - RSC_TRACE, 0, 0 - }, - - .rpmsg_vdev = /* SRTM virtio device entry */ + .net_vdev = { RSC_VDEV, - 7, - 2, - RSC_VDEV_FEATURE_NS, - 0, - 0, - 0, + VIRTIO_ID_NET_DEV, + 5, /* notifyid */ + 0, /* dfeatures: Linux negotiates */ + 0, /* gfeatures */ + 0, /* config_len: no MAC address config for now */ + 0, /* status */ NUM_VRINGS, { 0, 0 } }, - .rpmsg_vring0 = + .net_vring0 = { - VDEV0_VRING_BASE, + FW_RSC_ADDR_ANY, /* da: host allocates and writes back */ VRING_ALIGN, - RL_BUFFER_COUNT, - 0, - 0 + NET_BUFFER_COUNT, + 3, /* notifyid */ + 0 /* pa */ }, - .rpmsg_vring1 = + .net_vring1 = { - VDEV0_VRING_BASE + VRING_SIZE, + FW_RSC_ADDR_ANY, /* da: host allocates and writes back */ VRING_ALIGN, - RL_BUFFER_COUNT, - 1, - 0 + NET_BUFFER_COUNT, + 4, /* notifyid */ + 0 /* pa */ }, - - .config = - { - 0 - } }; -/**************************************************************************** - * Private Functions - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -176,3 +239,20 @@ void arm_boot(void) nx_start(); } + +/**************************************************************************** + * Name: up_addrenv_pa_to_va / up_addrenv_va_to_pa + * + * The R5F has no MMU (only MPU), so physical == virtual. + * OpenAMP / libmetal call these unconditionally; provide trivial stubs. + ****************************************************************************/ + +FAR void *up_addrenv_pa_to_va(uintptr_t pa) +{ + return (FAR void *)pa; +} + +uintptr_t up_addrenv_va_to_pa(FAR void *va) +{ + return (uintptr_t)va; +} diff --git a/arch/arm/src/am67/am67_mpuinit.c b/arch/arm/src/am67/am67_mpuinit.c index 94b28046cfc..c8073fff520 100644 --- a/arch/arm/src/am67/am67_mpuinit.c +++ b/arch/arm/src/am67/am67_mpuinit.c @@ -76,5 +76,14 @@ void am67_mpu_init(void) am67_mcu_msram_region(AM67_MCU_MSRAM_START_ADDR, AM67_MCU_MSRAM_SIZE); am67_ddr_region(AM67_DDR_START_ADDR, AM67_DDR_SIZE); + /* Non-cacheable overrides for the OpenAMP/rptun shared IPC memory. + * Configured last so they take priority over the (cacheable) DDR + * region for their ranges and make the R5F<->A53 shared structures + * coherent (see am67_mpuinit.h). + */ + + am67_ipc_shm_region(AM67_IPC_SHM0_START_ADDR, AM67_IPC_SHM0_SIZE); + am67_ipc_shm_region(AM67_IPC_SHM1_START_ADDR, AM67_IPC_SHM1_SIZE); + mpu_control(true); } diff --git a/arch/arm/src/am67/am67_mpuinit.h b/arch/arm/src/am67/am67_mpuinit.h index 9cf64c7ace4..49d28537a0d 100644 --- a/arch/arm/src/am67/am67_mpuinit.h +++ b/arch/arm/src/am67/am67_mpuinit.h @@ -37,7 +37,7 @@ * Pre-processor Definitions ****************************************************************************/ -#define AM67_NUM_OF_MPU_REGION (5) +#define AM67_NUM_OF_MPU_REGION (7) #define AM67_REGISTER_START_ADDR (0x0) #define AM67_TCMA_START_ADDR (0x0) @@ -52,6 +52,25 @@ #define AM67_DDR_SIZE (2ul * 1024 * 1024 * 1024) +/* Shared IPC memory (Non-cacheable). The R5F is NOT hardware-coherent + * with the A53, so the OpenAMP/rptun shared structures in DDR -- dma + * buffers, the + * resource table (vdev status incl. DRIVER_OK) and the virtio/rpmsg + * vrings -- + * must be Non-cacheable, or NuttX reads them from stale cache: it never sees + * the A53's DRIVER_OK/vring updates and the handshake hangs (no eth0, TX + * timeout). Two power-of-2, naturally-aligned regions cover 0xA2000000- + * 0xA223FFFF exactly; NuttX's own RAM (0xA2240000+) stays cacheable. These + * are + * configured AFTER the DDR region so they win the overlap (on the Cortex-R5 + * MPU the highest-numbered matching region takes priority). + */ + +#define AM67_IPC_SHM0_START_ADDR (0xa2000000) /* dma buffers + resource table */ +#define AM67_IPC_SHM0_SIZE (0x200000) /* 2 MB (0xa2000000-0xa21fffff) */ +#define AM67_IPC_SHM1_START_ADDR (0xa2200000) /* virtio/rpmsg vrings */ +#define AM67_IPC_SHM1_SIZE (0x40000) /* 256 KB (0xa2200000-0xa223ffff) */ + #define AM67_SCTLR_BG_REGION_EN (1 << 17) /* REGISTER_REGION @@ -116,6 +135,21 @@ MPU_RACR_B | \ MPU_RACR_AP_RWRW) +/* SHARED IPC REGION + * Normal memory, Outer & Inner Non-cacheable (TEX=0b001, C=0, B=0) + * Non-shareable + * P:RW U:RW + * + * For the R5F<->A53 OpenAMP shared memory. Non-cacheable means every R5F + * access + * goes straight to DDR, so it stays coherent with the (coherent) A53 with no + * cache maintenance. Kept Non-shareable so it does not hit the Cortex-R5 + * LDREX-on-Shareable external-monitor abort described on the DDR region. + */ +#define am67_ipc_shm_region(base, size) \ + mpu_configure_region(base, size, MPU_RACR_TEX(1) | \ + MPU_RACR_AP_RWRW) + /**************************************************************************** * Public Types ****************************************************************************/ diff --git a/arch/arm/src/am67/am67_rptun.c b/arch/arm/src/am67/am67_rptun.c new file mode 100644 index 00000000000..ce79df863e4 --- /dev/null +++ b/arch/arm/src/am67/am67_rptun.c @@ -0,0 +1,392 @@ +/**************************************************************************** + * arch/arm/src/am67/am67_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. + * + ****************************************************************************/ + +/* rptun driver for the AM67A (J722S) main-R5FSS0-0 Cortex-R5F core. + * + * The resource table (g_am67_rsc_table, defined in am67_boot.c and placed + * in the .resource_table ELF section) is read by Linux's remoteproc driver + * when it loads the R5F firmware. This driver registers the same table + * with NuttX's rptun/OpenAMP stack so that NuttX can also discover and + * use the virtio devices (RPMsg + virtio-net). + * + * Inter-processor notification (Linux <-> R5F): + * Uses mailbox0_cluster3 (base 0x29030000). + * R5F -> Linux: write vqid to FIFO 0 -> Linux GIC SPI 109 (user 0) + * Linux -> R5F: Linux writes to FIFO 1 -> R5F VIM IRQ 116 (user 3) + * Mailbox assignment confirmed from: + * k3-j722s-evm.dts (mbox_main_r5_0) and + * mcu_plus_sdk_j722s cslr_intr_r5fss0_core0.h (IRQ 116). + * + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "am67_rptun.h" +#include "arm_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* NAVSS mailbox0_cluster3 — the J722S EVM DTS assigns this cluster to + * main_r5fss0_core0: + * &mailbox0_cluster3 { mbox_main_r5_0: { ti,mbox-rx=<0 0 0>; + * ti,mbox-tx=<1 0 0>; }; } + * &main_r5fss0_core0 { mboxes = <&mailbox0_cluster3 &mbox_main_r5_0>; } + * + * From the perspective of each side: + * Linux TX -> R5F RX : write/read FIFO 1 (Linux sends, R5F receives) + * R5F TX -> Linux RX: write/read FIFO 0 (R5F sends, Linux receives) + * + * The NAVSS interrupt router wires cluster3 user-3 to R5FSS0 VIM 116 + * (CSLR_R5FSS0_CORE0_INTR_MAILBOX0_MAILBOX_CLUSTER_3 + * _MAILBOX_CLUSTER_PEND_3, from mcu_plus_sdk_j722s + * source/drivers/hw_include/j722s/cslr_intr_r5fss0_core0.h). + * Linux uses user-0 of the same cluster (GIC SPI 109). + */ + +#define AM67_MBOX_BASE (0x29030000ul) /* mailbox0_cluster3 */ + +/* FIFO assignments (from Linux DTS mbox_main_r5_0) */ + +#define AM67_MBOX_TX_FIFO (0U) /* R5F writes here -> Linux user-0 IRQ fires */ +#define AM67_MBOX_RX_FIFO (1U) /* Linux writes here -> R5F user-3 IRQ fires */ + +/* R5F uses mailbox user-3 (interrupt router wires cluster3/user3 -> VIM) */ + +#define AM67_MBOX_USER (3U) + +/* VIM IRQ number on MAIN_R5FSS0_0 for mailbox0_cluster3/user3 */ + +#ifndef CONFIG_AM67_RPTUN_IRQ +# define AM67_RPTUN_IRQ_EVENT (116) +#else +# define AM67_RPTUN_IRQ_EVENT CONFIG_AM67_RPTUN_IRQ +#endif + +/* Register offsets (OMAP4-style mailbox, ti,am64-mailbox compatible): + * MESSAGE(n) = base + 0x040 + 4*n (read/write FIFO n) + * MSG_STATUS(n) = base + 0x0C0 + 4*n (number of msgs in FIFO n) + * IRQSTATUS(u) = base + 0x104 + 16*u + * IRQENABLE(u) = base + 0x108 + 16*u + * IRQDISABLE(u) = base + 0x10C + 16*u + * EOI = base + 0x140 + * NEW_MSG_INT(n) = (1 << (2*n)) — bit to enable/clear new-message IRQ + */ + +#define AM67_MBOX_MESSAGE(fifo) (AM67_MBOX_BASE + 0x040u + 0x4u * (fifo)) +#define AM67_MBOX_MSG_STATUS(fifo) (AM67_MBOX_BASE + 0x0c0u + 0x4u * (fifo)) +#define AM67_MBOX_IRQSTATUS(usr) (AM67_MBOX_BASE + 0x104u + 0x10u * (usr)) +#define AM67_MBOX_IRQENABLE(usr) (AM67_MBOX_BASE + 0x108u + 0x10u * (usr)) +#define AM67_MBOX_IRQDISABLE(usr) (AM67_MBOX_BASE + 0x10cu + 0x10u * (usr)) +#define AM67_MBOX_EOI (AM67_MBOX_BASE + 0x140u) +#define AM67_MBOX_NEW_MSG_INT(n) (1u << ((n) * 2u)) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct am67_rptun_dev_s +{ + struct rptun_dev_s rptun; + rptun_callback_t callback; + void *arg; + struct work_s work; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static const char *am67_rptun_get_cpuname(struct rptun_dev_s *dev); +static const char *am67_rptun_get_firmware(struct rptun_dev_s *dev); +static const struct rptun_addrenv_s * +am67_rptun_get_addrenv(struct rptun_dev_s *dev); +static struct resource_table * +am67_rptun_get_resource(struct rptun_dev_s *dev); +static size_t am67_rptun_get_rsc_size(struct rptun_dev_s *dev); +static bool am67_rptun_is_autostart(struct rptun_dev_s *dev); +static bool am67_rptun_is_master(struct rptun_dev_s *dev); +static int am67_rptun_start(struct rptun_dev_s *dev); +static int am67_rptun_stop(struct rptun_dev_s *dev); +static int am67_rptun_notify(struct rptun_dev_s *dev, uint32_t vqid); +static int am67_rptun_register_callback(struct rptun_dev_s *dev, + rptun_callback_t callback, + void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct rptun_ops_s g_am67_rptun_ops = +{ + .get_cpuname = am67_rptun_get_cpuname, + .get_firmware = am67_rptun_get_firmware, + .get_addrenv = am67_rptun_get_addrenv, + .get_resource = am67_rptun_get_resource, + .get_rsc_size = am67_rptun_get_rsc_size, + .is_autostart = am67_rptun_is_autostart, + .is_master = am67_rptun_is_master, + .start = am67_rptun_start, + .stop = am67_rptun_stop, + .notify = am67_rptun_notify, + .register_callback = am67_rptun_register_callback, +}; + +static struct am67_rptun_dev_s g_am67_rptun_dev; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static const char *am67_rptun_get_cpuname(struct rptun_dev_s *dev) +{ + return AM67_RPTUN_CPUNAME; +} + +static const char *am67_rptun_get_firmware(struct rptun_dev_s *dev) +{ + return NULL; /* Linux is master; R5F does not load a firmware file */ +} + +static const struct rptun_addrenv_s * +am67_rptun_get_addrenv(struct rptun_dev_s *dev) +{ + return NULL; /* physical == virtual (no MMU on R5F) */ +} + +static struct resource_table * +am67_rptun_get_resource(struct rptun_dev_s *dev) +{ + /* The resource table is placed at a fixed address (0xA2100000) by the + * linker script (.resource_table section -> ddr_rsctable region). + * Linux remoteproc populates the vdev status/features fields in-place + * before kicking the R5F, so we return a non-const pointer. + */ + + return (struct resource_table *)&g_am67_rsc_table; +} + +static size_t am67_rptun_get_rsc_size(struct rptun_dev_s *dev) +{ + /* Return the real size of the extended resource table so that OpenAMP's + * remoteproc_set_rsc_table() can find both vdev entries (rptun.c would + * otherwise cap the visible region to sizeof(struct rptun_rsc_s)). + */ + + return sizeof(struct am67_rsc_s); +} + +static bool am67_rptun_is_autostart(struct rptun_dev_s *dev) +{ + return true; /* start rptun thread automatically */ +} + +static bool am67_rptun_is_master(struct rptun_dev_s *dev) +{ + return false; /* Linux A53 is the remoteproc master */ +} + +static int am67_rptun_start(struct rptun_dev_s *dev) +{ + return 0; /* nothing to do — Linux starts us */ +} + +static int am67_rptun_stop(struct rptun_dev_s *dev) +{ + return 0; +} + +static int am67_rptun_notify(struct rptun_dev_s *dev, uint32_t vqid) +{ + /* Kick Linux A53: write vqid into FIFO 0 of mailbox0_cluster3. + * Linux has user-0 new-message interrupt enabled on FIFO 0 + * (GIC SPI 109), so this fires rproc_vq_interrupt() on the A53. + */ + + putreg32(vqid, AM67_MBOX_MESSAGE(AM67_MBOX_TX_FIFO)); + UP_DSB(); + return 0; +} + +static int am67_rptun_register_callback(struct rptun_dev_s *dev, + rptun_callback_t callback, + void *arg) +{ + struct am67_rptun_dev_s *priv = + container_of(dev, struct am67_rptun_dev_s, rptun); + + priv->callback = callback; + priv->arg = arg; + + if (callback != NULL) + { + putreg32(AM67_MBOX_NEW_MSG_INT(AM67_MBOX_RX_FIFO), + AM67_MBOX_IRQENABLE(AM67_MBOX_USER)); + up_enable_irq(AM67_RPTUN_IRQ_EVENT); + } + else + { + up_disable_irq(AM67_RPTUN_IRQ_EVENT); + putreg32(AM67_MBOX_NEW_MSG_INT(AM67_MBOX_RX_FIFO), + AM67_MBOX_IRQDISABLE(AM67_MBOX_USER)); + } + + return 0; +} + +/**************************************************************************** + * Name: am67_rptun_notify_work + * + * Description: + * Deferred half of the mailbox interrupt: runs on the high-priority work + * queue and delivers the notification to the rptun/OpenAMP stack. The + * OpenAMP receive path takes mutexes and allocates memory, so it must + * not run in interrupt context; RPTUN_NOTIFY_ALL re-scans every + * virtqueue, so any number of coalesced mailbox kicks collapse safely + * into one pass. + * + ****************************************************************************/ + +static void am67_rptun_notify_work(void *arg) +{ + struct am67_rptun_dev_s *priv = (struct am67_rptun_dev_s *)arg; + + if (priv->callback != NULL) + { + priv->callback(priv->arg, RPTUN_NOTIFY_ALL); + } +} + +/**************************************************************************** + * Name: am67_rptun_interrupt + * + * Description: + * VIM IRQ 116 handler — fires when Linux A53 writes to mailbox0_cluster3 + * FIFO 1 (user-3 new-message interrupt). Drains the FIFO, clears the + * interrupt, and queues am67_rptun_notify_work() to process the + * virtqueues in thread context. + * + ****************************************************************************/ + +static int am67_rptun_interrupt(int irq, void *context, void *arg) +{ + struct am67_rptun_dev_s *priv = (struct am67_rptun_dev_s *)arg; + + /* Drain all messages Linux wrote into FIFO 1. Each read pops one + * entry; stop when MSG_STATUS reports 0 pending messages. + */ + + while (getreg32(AM67_MBOX_MSG_STATUS(AM67_MBOX_RX_FIFO)) != 0) + { + (void)getreg32(AM67_MBOX_MESSAGE(AM67_MBOX_RX_FIFO)); + } + + /* Clear the new-message interrupt status for user-3 / FIFO-1. + * Write the bit mask to the IRQSTATUS register (write-1-to-clear). + */ + + putreg32(AM67_MBOX_NEW_MSG_INT(AM67_MBOX_RX_FIFO), + AM67_MBOX_IRQSTATUS(AM67_MBOX_USER)); + + /* Acknowledge the interrupt to the mailbox EOI register so the + * controller can re-assert on the next incoming message. + */ + + putreg32(0, AM67_MBOX_EOI); + UP_DSB(); + + if (priv != NULL && priv->callback != NULL && + work_available(&priv->work)) + { + work_queue(HPWORK, &priv->work, am67_rptun_notify_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: am67_rptun_init + ****************************************************************************/ + +int am67_rptun_init(void) +{ + struct am67_rptun_dev_s *dev = &g_am67_rptun_dev; + int ret; + + memset(dev, 0, sizeof(*dev)); + dev->rptun.ops = &g_am67_rptun_ops; + + /* Enable the mailbox interrupt: R5F user-3, FIFO 1 (Linux->R5F). + * Linux enables its own user-0/FIFO-0 side independently. + * Disable first to start from a clean state, then clear any stale + * status before attaching the IRQ. + */ + + putreg32(AM67_MBOX_NEW_MSG_INT(AM67_MBOX_RX_FIFO), + AM67_MBOX_IRQDISABLE(AM67_MBOX_USER)); + putreg32(AM67_MBOX_NEW_MSG_INT(AM67_MBOX_RX_FIFO), + AM67_MBOX_IRQSTATUS(AM67_MBOX_USER)); + + ret = irq_attach(AM67_RPTUN_IRQ_EVENT, am67_rptun_interrupt, dev); + if (ret < 0) + { + ipcerr("ERROR: irq_attach failed: %d\n", ret); + return ret; + } + + /* Enable new-message interrupt for FIFO 1, user 3 */ + + putreg32(AM67_MBOX_NEW_MSG_INT(AM67_MBOX_RX_FIFO), + AM67_MBOX_IRQENABLE(AM67_MBOX_USER)); + + ret = rptun_initialize(&dev->rptun); + if (ret < 0) + { + irq_detach(AM67_RPTUN_IRQ_EVENT); + ipcerr("ERROR: rptun_initialize failed: %d\n", ret); + } + + return ret; +} diff --git a/arch/arm/src/am67/am67_rptun.h b/arch/arm/src/am67/am67_rptun.h new file mode 100644 index 00000000000..548eee34383 --- /dev/null +++ b/arch/arm/src/am67/am67_rptun.h @@ -0,0 +1,101 @@ +/**************************************************************************** + * arch/arm/src/am67/am67_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. + * + ****************************************************************************/ + +/* Extended resource table and rptun init for AM67A / J722S R5F. + * Declares struct am67_rsc_s (RPMsg vdev + virtio-net vdev) and + * am67_rptun_init(), which must be called from am67_bringup(). + * + */ + +#ifndef __ARCH_ARM_SRC_AM67_AM67_RPTUN_H +#define __ARCH_ARM_SRC_AM67_AM67_RPTUN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_RPTUN + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* CPU name that Linux remoteproc reports for this R5F core. + * Must match the rproc->name in the Linux ti_k3_r5_remoteproc driver + * (typically derived from DTS "label" or "compatible" + index). + * Override with CONFIG_AM67_RPTUN_CPUNAME if needed. + */ + +#ifndef AM67_RPTUN_CPUNAME +# define AM67_RPTUN_CPUNAME "r5f" +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Extended resource table: standard RPMsg vdev (id=7) at index 0 + + * virtio-net vdev (id=1) at index 1. The table is placed in the + * .resource_table ELF section at 0xA2100000 so Linux remoteproc can + * read it from the firmware binary. + */ + +struct aligned_data(8) am67_rsc_s +{ + struct rptun_rsc_s base; /* RPMsg vdev (index 0) */ + struct fw_rsc_vdev net_vdev; /* virtio-net vdev (index 1, id=1) */ + struct fw_rsc_vdev_vring net_vring0; /* net TX vring */ + struct fw_rsc_vdev_vring net_vring1; /* net RX vring */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Defined in am67_boot.c, placed in .resource_table section */ + +extern const struct am67_rsc_s g_am67_rsc_table; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: am67_rptun_init + * + * Description: + * Initialise the AM67 rptun device. Enables the NAVSS mailbox interrupt + * (mailbox0_cluster3/user-3/FIFO-1, VIM IRQ 116) and calls + * rptun_initialize(). Must be called from am67_bringup() after basic + * platform initialisation. + * + ****************************************************************************/ + +int am67_rptun_init(void); + +#endif /* CONFIG_RPTUN */ +#endif /* __ARCH_ARM_SRC_AM67_AM67_RPTUN_H */ diff --git a/boards/arm/am67/t3-gem-o1/configs/nsh/defconfig b/boards/arm/am67/t3-gem-o1/configs/nsh/defconfig index 600eef35360..dbc052bb23d 100644 --- a/boards/arm/am67/t3-gem-o1/configs/nsh/defconfig +++ b/boards/arm/am67/t3-gem-o1/configs/nsh/defconfig @@ -48,8 +48,8 @@ CONFIG_PSEUDOFS_ATTRIBUTES=y CONFIG_PSEUDOFS_FILE=y CONFIG_PWM=y CONFIG_PWM_NCHANNELS=2 -CONFIG_RAM_SIZE=14680064 -CONFIG_RAM_START=0xA2200000 +CONFIG_RAM_SIZE=14417920 +CONFIG_RAM_START=0xA2240000 CONFIG_READLINE_CMD_HISTORY=y CONFIG_RPTUN=y CONFIG_SCHED_CHILD_STATUS=y diff --git a/boards/arm/am67/t3-gem-o1/scripts/sdram.ld b/boards/arm/am67/t3-gem-o1/scripts/sdram.ld index 1dc765fa0c2..6de291e8425 100644 --- a/boards/arm/am67/t3-gem-o1/scripts/sdram.ld +++ b/boards/arm/am67/t3-gem-o1/scripts/sdram.ld @@ -25,7 +25,8 @@ MEMORY atcm (rwx): ORIGIN = 0x00000000, LENGTH = 32K /* Instruction TCM for vectors/boot code */ btcm (rwx): ORIGIN = 0x41010000, LENGTH = 32K /* Data TCM, ideal for stack */ ddr_rsctable (rwx): ORIGIN = 0xA2100000, LENGTH = 1K /* Resource Table for RemoteProc/IPC */ - ddr (rwx): ORIGIN = 0xA2200000, LENGTH = 0xE00000 /* Main DDR RAM */ + ddr_rsv (rwx): ORIGIN = 0xA2200000, LENGTH = 256K /* VRING + RPMsg (VDEV0_VRING_BASE) */ + ddr (rwx): ORIGIN = 0xA2240000, LENGTH = 0xDC0000 /* Main DDR RAM (~13.75 MB) */ } EXTERN(_vector_start) @@ -71,6 +72,12 @@ SECTIONS . = ALIGN(1024); } > ddr_rsctable + .ddr_rsv (NOLOAD) : + { + _vring_base = ABSOLUTE(.); + . = . + 256K; + } > ddr_rsv + .text : { *(.text .text.*) diff --git a/boards/arm/am67/t3-gem-o1/src/am67_bringup.c b/boards/arm/am67/t3-gem-o1/src/am67_bringup.c index 489a3869db9..5458a7d213a 100644 --- a/boards/arm/am67/t3-gem-o1/src/am67_bringup.c +++ b/boards/arm/am67/t3-gem-o1/src/am67_bringup.c @@ -48,6 +48,10 @@ #include "am67_ecap.h" #endif +#ifdef CONFIG_RPTUN +#include "am67_rptun.h" +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -99,5 +103,21 @@ int am67_bringup(void) } #endif +#ifdef CONFIG_RPTUN + /* Initialize the rptun device. This registers the resource table + * (RPMsg + virtio-net) with NuttX's OpenAMP stack and starts the + * rptun thread. Linux remoteproc must be running and must have + * already booted the R5F core (i.e. we arrive here after remoteproc + * has written the vdev status/features into the resource table). + * + */ + + ret = am67_rptun_init(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: am67_rptun_init failed: %d\n", ret); + } +#endif + return ret; }