AM62x MCU+ SDK  09.02.00
IPC RPMessage

Note
These APIs are to be used from NORTOS/RTOS. When working with Linux on A53 refer to Linux documentation for Linux side APIs.

Features Supported

  • RP Message + VRING protocol implementation
  • Uses IPC Notify underneath for interrupts and uses shared memory (VRING) for message buffers
  • Uses 'IPC Notify' underneath for interrupts and uses shared memory (VRING) for message buffers
  • Supports message passing between NORTOS, FreeRTOS and Linux based CPUs
  • Logical communication channels can be created using unique "end points". This allows multiple tasks on a CPU to talk to multiple tasks on another CPU using the same underlying HW mailbox and shared memory.
  • Between NORTOS and RTOS, below can be configured in RP Message to control the shared memory size,
    • Max message size, default is 128 bytes
    • Number of buffers in a VRING, default is 8 messages
    • VRING shared memory buffer address can be configured, can be DDR or internal memory address.
  • Between Linux and NORTOS/RTOS, the VRING parameters are fixed as below
    • Max message is 512B
    • NUmber of messages in a VRING is 256
    • VRING shared memory address is determined by value in Linux device tree and is placed in DDR.
  • APIs to send and receive messages to user specified end points
  • Blocking, as well as non-blocking APIs with time out based blocking.
  • APIs to announce a created end point, needed when talking to Linux
  • API to sync and wait for LInux to be ready, needed when talking to Linux
  • APIs to use callback to receive message notifications instead of blocking, see RPMessage_CreateParams for more details.
  • APIs to use callback to receive and handle messages in callback itself, see RPMessage_CreateParams for more details.
  • Logging to Linux shared memory when IPC with Linux is enabled. Allows to view logs from RTOS/NORTOS on Linux using Linux debugfs.

SysConfig Features

Note
It is strongly recommend to use SysConfig where it is available instead of using direct SW API calls. This will help simplify the SW application and also catch common mistakes early in the development cycle.
  • Enable/Disable IPC RPMessage between different CPUs
  • Enable IPC RPMessage between NORTOS/RTOS and Linux. When enabled, SysConfig generates the resource table that is needed to talk with Linux.
  • Select RP Message max message size, number of buffer in a VRING
  • Enable IPC RPMessage between NORTOS/RTOS and Linux. When enabled, SysConfig generates the resource table that is needed to talk with Linux.

Features NOT Supported

NA

Important Usage Guidelines

Note
It is strongly recommended to refer to the IPC examples examples/drivers/ipc to understand the linker command file setup for IPC applications.
  • When Linux runs along side RTOS/NORTOS, do below to make sure NORTOS/RTOS can talk to Linux.
    • Make sure to call RPMessage_waitForLinuxReady() before starting communication with Linux.
    • Also for any RPMessage point created on NORTOS/RTOS, make sure to announce it to Linux using RPMessage_announce()
    • Make sure to assign the shared memory used for VRING between Linux and this CPU as mentioned in the Linux device tree. Also make sure to mark this section as non-cached
    • If the CPU code will run out of DDR, make sure to setup a MPU entry for the code/data section in DDR. This can be marked as cached.
    • Again refer to Linux device tree to find out the space in DDR and MSMC where the NORTOS/RTOS applications can execute from.
  • Make sure to assign the shared memory used for VRINGs between NORTOS/RTOS in a common memory section in each CPUs linker command file and make sure to mark this section as non-cached in the R5F MPU.
  • Maximum Message size is limited to 1152 Bytes in Syscfg and the maximum number of buffers is limited to 16. The recommended approach is to keep the number of buffers and message size within this limit.
  • If larger messages need to be passed, the data should be kept in a shared memory and a pointer to the same should be passed via IPC.

Example Usage

Include the below files to access the APIs

#include <stdio.h>
#include <string.h>

Define the following macros

/* This is used to run the echo test with user space kernel */
#define IPC_RPMESSAGE_SERVICE_CHRDEV "rpmsg_chrdev"
#define IPC_RPMESSAGE_ENDPT_CHRDEV_PING (14U)
/* maximum size that message can have in this example */
#define IPC_RPMESSAGE_MAX_MSG_SIZE (96u)

Setup resource table to be used by Linux, this snippet is for reference and is generated by SysConfig when SysConfig is used for IPC.

/* Buffer used for trace, address and size of this buffer is put in the resource table so that Linux can read it */
char gDebugMemLog[DebugP_MEM_LOG_SIZE] __attribute__ ((section (".bss.debug_mem_trace_buf"), aligned (128)));
uint32_t gDebugMemLogSize = DebugP_MEM_LOG_SIZE;
const RPMessage_ResourceTable gRPMessage_linuxResourceTable __attribute__ ((section (".resource_table"), aligned (4096))) =
{
{
1U, /* we're the first version that implements this */
2U, /* number of entries, MUST be 2 */
{ 0U, 0U, } /* reserved, must be zero */
},
/* offsets to the entries */
{
offsetof(RPMessage_ResourceTable, vdev),
offsetof(RPMessage_ResourceTable, trace),
},
/* vdev entry */
{
RPMESSAGE_RSC_TYPE_VDEV, RPMESSAGE_RSC_VIRTIO_ID_RPMSG,
0U, 1U, 0U, 0U, 0U, 2U, { 0U, 0U },
},
/* the two vrings */
{ RPMESSAGE_RSC_VRING_ADDR_ANY, 4096U, 256U, 1U, 0U },
{ RPMESSAGE_RSC_VRING_ADDR_ANY, 4096U, 256U, 2U, 0U },
{
(RPMESSAGE_RSC_TRACE_INTS_VER0 | RPMESSAGE_RSC_TYPE_TRACE),
(uint32_t)gDebugMemLog, DebugP_MEM_LOG_SIZE,
0, "trace:m4fss0_0",
},
};

Initialize IPC RPMessage, this snippet is for reference and is generated by SysConfig when SysConfig is used for IPC.

/* Below code is for reference, recommened to use SysCfg to generate this code */
/* IMPORTANT:
* - Make sure IPC Notify is enabled before enabling IPC RPMessage
*/
RPMessage_Params rpmsgParams;
int32_t status;
/* initialize parameters to default */
RPMessage_Params_init(&rpmsgParams);
rpmsgParams.linuxResourceTable = &gRPMessage_linuxResourceTable;
/* initialize the IPC RP Message module */
status = RPMessage_init(&rpmsgParams);
/* This API MUST be called by applications when its ready to talk to Linux */

Define RPMessage_Object objects for receive endpoints,

/* IMPORTANT:
* - Below code is for Core 1
* - All RPMessage_Object MUST be global
*/
RPMessage_Object gRecvMsgObject;

Create RPMessage end points for receive endpoints,

/* IMPORTANT:
* - Below code is for Core 0
*/
RPMessage_CreateParams createParams;
int32_t status;
createParams.localEndPt = IPC_RPMESSAGE_ENDPT_CHRDEV_PING;
status = RPMessage_construct(&gRecvMsgObject, &createParams);
/* We need to "announce" to Linux client else Linux does not know a service exists on this CPU
* This is not mandatory to do for RTOS clients
*/
status = RPMessage_announce(CSL_CORE_ID_A53SS0_0, IPC_RPMESSAGE_ENDPT_CHRDEV_PING, IPC_RPMESSAGE_SERVICE_CHRDEV);

Receive message at MCU core from A53 Linux and send ack to A53 Linux,

/* IMPORTANT:
* - Below code is for Core 1
*/
while(1)
{
char recvMsg[IPC_RPMESSAGE_MAX_MSG_SIZE + 1];
char replyMsg[IPC_RPMESSAGE_MAX_MSG_SIZE + 1];
uint16_t recvMsgSize, remoteCoreId;
uint32_t remoteCoreEndPt;
/* wait for messages forever in a loop */
/* set 'recvMsgSize' to size of recv buffer,
* after return `recvMsgSize` contains actual size of valid data in recv buffer
*/
recvMsgSize = sizeof(recvMsg);
RPMessage_recv(&gRecvMsgObject,
recvMsg, &recvMsgSize,
&remoteCoreId, &remoteCoreEndPt,
/* echo the message string as reply, we know this is null terminating string
* so strcpy is safe to use.
*/
strcpy(replyMsg, recvMsg);
/* send ack to sender CPU at the sender end point */
replyMsg, strlen(replyMsg),
remoteCoreId, remoteCoreEndPt,
RPMessage_getLocalEndPt(&gRecvMsgObject),
}

API

APIs for IPC RPMessage

CSL_CORE_ID_A53SS0_0
#define CSL_CORE_ID_A53SS0_0
Definition: cslr_soc_defines.h:73
RPMessage_Object
Opaque RPMessage object used with the RPMessage APIs.
Definition: ipc_rpmsg.h:110
RPMessage_CreateParams::localEndPt
uint16_t localEndPt
Definition: ipc_rpmsg.h:182
RPMessage_construct
int32_t RPMessage_construct(RPMessage_Object *obj, const RPMessage_CreateParams *createParams)
Create a RPMessage object to receive messages at a specified end-point.
RPMessage_waitForLinuxReady
int32_t RPMessage_waitForLinuxReady(uint32_t timeout)
Wait for linux side RPMessage to be ready.
SystemP_WAIT_FOREVER
#define SystemP_WAIT_FOREVER
Value to use when needing a timeout of infinity or wait forver until resource is available.
Definition: SystemP.h:83
RPMessage_init
int32_t RPMessage_init(const RPMessage_Params *params)
Initialize RPMessage module.
RPMessage_getLocalEndPt
uint16_t RPMessage_getLocalEndPt(const RPMessage_Object *obj)
Return local end point of a RPMessage_Object.
RPMessage_Params::linuxResourceTable
const RPMessage_ResourceTable * linuxResourceTable
Definition: ipc_rpmsg.h:206
RPMessage_Params_init
void RPMessage_Params_init(RPMessage_Params *params)
Set default values to RPMessage_Params.
RPMessage_announce
int32_t RPMessage_announce(uint16_t remoteProcId, uint16_t localEndPt, const char *name)
Announce a local end point at which a service is created to a remote core.
SystemP_SUCCESS
#define SystemP_SUCCESS
Return status when the API execution was successful.
Definition: SystemP.h:56
RPMessage_Params::linuxCoreId
uint16_t linuxCoreId
Definition: ipc_rpmsg.h:211
RPMessage_CreateParams_init
void RPMessage_CreateParams_init(RPMessage_CreateParams *params)
Set default values to RPMessage_CreateParams.
__attribute__
void __attribute__((__noreturn__))(*Bootloader_SelfCoreJump)(void)
Function pointer to jump a self core to specific code location in AM62x SOC.
Definition: bootloader_soc.h:67
DebugP.h
DebugP_MEM_LOG_SIZE
#define DebugP_MEM_LOG_SIZE
size of memory log for a CPU
Definition: DebugP.h:84
RPMessage_Params
Parameters passed to RPMessage_init, these are generated via SysCfg.
Definition: ipc_rpmsg.h:200
ipc_rpmsg.h
DebugP_assert
#define DebugP_assert(expression)
Function to call for assert check.
Definition: DebugP.h:175
RPMessage_CreateParams
Parameters passed to RPMessage_construct.
Definition: ipc_rpmsg.h:181
RPMessage_recv
int32_t RPMessage_recv(RPMessage_Object *obj, void *data, uint16_t *dataLen, uint16_t *remoteCoreId, uint32_t *remoteEndPt, uint32_t timeout)
Blocking API to wait till a message is received from any CPU at the specified local end point.
RPMessage_send
int32_t RPMessage_send(void *data, uint16_t dataLen, uint16_t remoteCoreId, uint16_t remoteEndPt, uint16_t localEndPt, uint32_t timeout)
Send a message to a remote core at a specified remote end point.