mirror of
https://github.com/apache/nuttx.git
synced 2026-10-02 03:46:25 +00:00
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:
parent
e3dfc9875d
commit
a2edd99159
11 changed files with 711 additions and 61 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
****************************************************************************/
|
||||
|
|
|
|||
392
arch/arm/src/am67/am67_rptun.c
Normal file
392
arch/arm/src/am67/am67_rptun.c
Normal 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;
|
||||
}
|
||||
101
arch/arm/src/am67/am67_rptun.h
Normal file
101
arch/arm/src/am67/am67_rptun.h
Normal 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 */
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.*)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue