AM263Px MCU+ SDK: IPC RPMessage

| AM263Px MCU+ SDK 26.00.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
- 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.
  IPC Examples should be build as System Projects. Single core build will fail since IPC code generation dependends on all core contexts in the application.

- 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/Disable SafeIPC. If Enabled, the Shared memory is organized in a way that allows Firewalling. Only Sender and Receiver core will have access to the VRING. Firewall configuration is not part of IPC SysCfg module. It has to be done separately. The SysCfg generated code has comments on the Start and End addresses and the involved cores. This can be used during the firewall configuration. Data Integrity Check has to be handled in application. CRC can be sent as a part of Payload and decoded in the receiver end.
- Enable/Disable CRC. If Enabled, Data Integrity Check is enabled for IPC RPMsg Data. The calculated CRC is sent as a part of VRING Header and decoded in the receiver end. Application has to define a hook function which will be used by driver for CRC calculation. 16 Bit CRC is used by IPC RPMsg.

# 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>
#include <drivers/ipc_rpmsg.h>
#include <kernel/dpl/DebugP.h>

Setup VRING shared memory for 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 */
/* Below is common code for all the CPUs participating in this IPC */
#define NUM_CPUS (2u) /* R5FSS0-0 and R5FSS0-1 in this example */
#define VRING_NUM (NUM_CPUS*(NUM_CPUS-1))
#define VRING_NUM_BUF (8u)
#define VRING_MAX_MSG_SIZE (128u)
/* Size of each VRING is
* number of buffers x ( size of each buffer + space for data structures of one buffer (32B) )
*/
#define VRING_SIZE RPMESSAGE_VRING_SIZE(VRING_NUM_BUF, VRING_MAX_MSG_SIZE)
/* Make sure of below,
* - The section defined below should be placed at the exact same location in memory for all the CPUs
* - the memory should be marked as non-cached for all the CPUs
* - the section should be marked as NOLOAD in all the CPUs linker command file
*/
uint8_t gVringMem[VRING_NUM][VRING_SIZE] __attribute__((aligned(128), section(".bss.sharedmemory")));

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:
* - Below code is for Core 0
* - Make sure IPC Notify is enabled before enabling IPC RPMessage
*/
int32_t status;
RPMessage_Params initParams;
RPMessage_Params_init(&initParams);
initParams.vringTxBaseAddr[CSL_CORE_ID_R5FSS0_1] = (uintptr_t)gVringMem[0];
initParams.vringRxBaseAddr[CSL_CORE_ID_R5FSS0_1] = (uintptr_t)gVringMem[1];
initParams.vringNumBuf = VRING_NUM_BUF;
initParams.vringMsgSize = VRING_MAX_MSG_SIZE;
initParams.vringSize = VRING_SIZE;
status = RPMessage_init(&initParams);
DebugP_assert(status==SystemP_SUCCESS);
/* Below code is for reference, recommened to use SysCfg to generate this code */
/* IMPORTANT:
* - Below code is for Core 1
* - Make sure IPC Notify is enabled before enabling IPC RPMessage
*/
int32_t status;
RPMessage_Params initParams;
RPMessage_Params_init(&initParams);
initParams.vringTxBaseAddr[CSL_CORE_ID_R5FSS0_0] = (uintptr_t)gVringMem[1];
initParams.vringRxBaseAddr[CSL_CORE_ID_R5FSS0_0] = (uintptr_t)gVringMem[0];
initParams.vringNumBuf = VRING_NUM_BUF;
initParams.vringMsgSize = VRING_MAX_MSG_SIZE;
initParams.vringSize = VRING_SIZE;
status = RPMessage_init(&initParams);
DebugP_assert(status==SystemP_SUCCESS);

Define RPMessage_Object objects for receive and ack endpoints,

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

Create RPMessage end points for receive and ack endpoints,

/* IMPORTANT:
* - Below code is for Core 0
*/
RPMessage_CreateParams createParams;
RPMessage_CreateParams_init(&createParams);
createParams.localEndPt = 12; /* pick any unique value on that core between 0..RPMESSAGE_MAX_LOCAL_ENDPT-1
* the value need not be unique across cores
*/
RPMessage_construct(&gAckReplyMsgObject, &createParams);
/* IMPORTANT:
* - Below code is for Core 1
*/
RPMessage_CreateParams createParams;
RPMessage_CreateParams_init(&createParams);
createParams.localEndPt = 13; /* pick any unique value on that core between 0..RPMESSAGE_MAX_LOCAL_ENDPT-1
* the value need not be unique across cores
*/
RPMessage_construct(&gRecvMsgObject, &createParams);

Send message from Core 0 to Core 1 and wait for reply from Core 1,

/* IMPORTANT:
* - Below code is for Core 0
*/
char sendMsg[64] = "hello, world!!!";
char replyMsg[64];
uint16_t replyMsgSize, remoteCoreId, remoteCoreEndPt;
RPMessage_send(
sendMsg, strlen(sendMsg),
CSL_CORE_ID_R5FSS0_1, 13,
RPMessage_getLocalEndPt(&gAckReplyMsgObject),
SystemP_WAIT_FOREVER);
/* set 'replyMsgSize' to size of recv buffer,
* after return `replyMsgSize` contains actual size of valid data in recv buffer
*/
replyMsgSize = sizeof(replyMsg); /* */
RPMessage_recv(&gAckReplyMsgObject,
replyMsg, &replyMsgSize,
&remoteCoreId, &remoteCoreEndPt,
SystemP_WAIT_FOREVER);

Receive message at Core 1 from Core 0 and send ack to Core 0,

/* IMPORTANT:
* - Below code is for Core 1
*/
while(1)
{
char recvMsg[64];
char replyMsg[64];
uint16_t recvMsgSize, remoteCoreId, 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,
SystemP_WAIT_FOREVER);
/* 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 */
RPMessage_send(
replyMsg, strlen(replyMsg),
remoteCoreId, remoteCoreEndPt,
RPMessage_getLocalEndPt(&gRecvMsgObject),
SystemP_WAIT_FOREVER);
}

# API

APIs for IPC RPMessage

RPMessage_recv
int32_t RPMessage_recv(RPMessage_Object *obj, void *data, uint16_t *dataLen, uint16_t *remoteCoreId, uint16_t *remoteEndPt, uint32_t timeout)
Blocking API to wait till a message is received from any CPU at the specified local end point.
RPMessage_Params::vringTxBaseAddr
uintptr_t vringTxBaseAddr[CSL_CORE_ID_MAX]
Definition: ipc_rpmsg.h:217
RPMessage_Object
Definition: ipc_rpmsg.h:172
RPMessage_Params::vringSize
uint32_t vringSize
Definition: ipc_rpmsg.h:219
RPMessage_CreateParams::localEndPt
uint16_t localEndPt
Definition: ipc_rpmsg.h:198
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.
CSL_CORE_ID_R5FSS0_0
#define CSL_CORE_ID_R5FSS0_0
Definition: cslr_soc_defines.h:146
RPMessage_Params::vringMsgSize
uint16_t vringMsgSize
Definition: ipc_rpmsg.h:221
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_init
void RPMessage_Params_init(RPMessage_Params *params)
Set default values to RPMessage_Params.
__attribute__
struct lld_sockaddr __attribute__
This is the SecureBoot Stream type which holds the data for a specific bootloader to HSM call....
SystemP_SUCCESS
#define SystemP_SUCCESS
Return status when the API execution was successful.
Definition: SystemP.h:56
RPMessage_CreateParams_init
void RPMessage_CreateParams_init(RPMessage_CreateParams *params)
Set default values to RPMessage_CreateParams.
RPMessage_Params::vringRxBaseAddr
uintptr_t vringRxBaseAddr[CSL_CORE_ID_MAX]
Definition: ipc_rpmsg.h:218
DebugP.h
RPMessage_Params::vringNumBuf
uint16_t vringNumBuf
Definition: ipc_rpmsg.h:220
RPMessage_Params
Parameters passed to RPMessage_init, these are generated via SysCfg.
Definition: ipc_rpmsg.h:216
CSL_CORE_ID_R5FSS0_1
#define CSL_CORE_ID_R5FSS0_1
Definition: cslr_soc_defines.h:147
ipc_rpmsg.h
DebugP_assert
#define DebugP_assert(expression)
Function to call for assert check.
Definition: DebugP.h:187
RPMessage_CreateParams
Parameters passed to RPMessage_construct.
Definition: ipc_rpmsg.h:197
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.