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ç <sertan.usk@gmail.com>
This commit is contained in:
Ulaş Sertan Kemeç 2026-09-19 09:24:31 +03:00 • committed by Xiang Xiao
parent e3dfc9875d
commit a2edd99159
11 changed files with 711 additions and 61 deletions

View file

@ -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

View file

@ -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})

View file

@ -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

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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
****************************************************************************/

View file

@ -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;
}

View file

@ -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 */

View file

@ -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

View file

@ -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.*)

View file

@ -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;
}