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 a2edd991597d217d04857c1c83ef2dde034e1720
Author: Ulaş Sertan Kemeç <[email protected]>
AuthorDate: Sat Sep 19 09:24:31 2026 +0300

    arch/arm/am67: Add rptun IPC with the Linux A53 (remoteproc/rpmsg).
    
    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ç <[email protected]>
---
 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 ++++++
 boards/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(-)

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
- ****************************************************************************/
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
+/* 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 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
+      }
+    },
 
-  .offset =
-  {
-    offsetof(struct rptun_rsc_s, rpmsg_vdev)
-  },
+    /* Offsets from the start of g_am67_rsc_table to each resource */
 
-  .log_trace =
-  {
-    RSC_TRACE, 0, 0
+    .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
+    }
   },
 
-  .rpmsg_vdev = /* SRTM virtio device entry */
+  /* 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.
+   */
+
+  .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 <nuttx/config.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <debug.h>
+
+#include <arch/barriers.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/nuttx.h>
+#include <nuttx/rptun/rptun.h>
+#include <nuttx/wqueue.h>
+
+#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 <nuttx/config.h>
+
+#ifdef CONFIG_RPTUN
+
+#include <nuttx/rptun/rptun.h>
+
+/****************************************************************************
+ * 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;
 }

Reply via email to