RPMsg char driver not sending data on iMX8MM

Hi @hfranco.tx,

Are you testing with the imx_rpmsg_pingpong kernel module or the rpmsg_char one? I’m trying to get the latter to work. My kernel version is 5.4.193, just in case.

I’ve tried loading your DTO, but this seems to not start up the RPMsg driver correctly. At the moment I’m using the one you posted here.

Here is the source code I’m testing with for both the A53 and M4:

M4:

/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2020 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

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

#include "rpmsg_lite.h"
#include "rpmsg_queue.h"
#include "rpmsg_ns.h"

#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"
#include "fsl_debug_console.h"

#include "FreeRTOS.h"
#include "task.h"

#include "fsl_uart.h"
#include "rsc_table.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define RPMSG_LITE_LINK_ID            (RL_PLATFORM_IMX8MM_M4_USER_LINK_ID)
#define RPMSG_LITE_SHMEM_BASE         (VDEV0_VRING_BASE)
#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-openamp-demo-channel"
#define RPMSG_LITE_MASTER_IS_LINUX

#define APP_DEBUG_UART_BAUDRATE (115200U) /* Debug console baud rate. */
#define APP_TASK_STACK_SIZE (256U)
#ifndef LOCAL_EPT_ADDR
#define LOCAL_EPT_ADDR (30U)
#endif
#define APP_RPMSG_READY_EVENT_DATA (1U)

#define RPMSG_DATA_SIZE 256

typedef struct {
    char data[RPMSG_DATA_SIZE];
} msg_data_t;

static volatile msg_data_t msg = {};
#ifdef RPMSG_LITE_MASTER_IS_LINUX
static char helloMsg[13];
#endif /* RPMSG_LITE_MASTER_IS_LINUX */

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Code
 ******************************************************************************/
static TaskHandle_t app_task_handle = NULL;

static struct rpmsg_lite_instance *volatile my_rpmsg = NULL;

static struct rpmsg_lite_endpoint *volatile my_ept = NULL;
static volatile rpmsg_queue_handle my_queue        = NULL;

void app_destroy_task(void)
{
    if (app_task_handle)
    {
        vTaskDelete(app_task_handle);
        app_task_handle = NULL;
    }

    if (my_ept)
    {
        rpmsg_lite_destroy_ept(my_rpmsg, my_ept);
        my_ept = NULL;
    }

    if (my_queue)
    {
        rpmsg_queue_destroy(my_rpmsg, my_queue);
        my_queue = NULL;
    }

    if (my_rpmsg)
    {
        rpmsg_lite_deinit(my_rpmsg);
        my_rpmsg = NULL;
    }
}

static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data)
{
}

#ifdef MCMGR_USED
/*!
 * @brief Application-specific implementation of the SystemInitHook() weak function.
 */
void SystemInitHook(void)
{
    /* Initialize MCMGR - low level multicore management library. Call this
       function as close to the reset entry as possible to allow CoreUp event
       triggering. The SystemInitHook() weak function overloading is used in this
       application. */
    (void)MCMGR_EarlyInit();
}
#endif /* MCMGR_USED */

static void app_task(void *param)
{
    volatile uint32_t remote_addr;
    volatile rpmsg_ns_handle ns_handle;

    /* Print the initial banner */
    (void)PRINTF("\r\nRPMSG Echo FreeRTOS RTOS API Demo...\r\n");

#ifdef MCMGR_USED
    uint32_t startupData;
    mcmgr_status_t status;

    /* Get the startup data */
    do
    {
        status = MCMGR_GetStartupData(&startupData);
    } while (status != kStatus_MCMGR_Success);

    my_rpmsg = rpmsg_lite_remote_init((void *)(char *)startupData, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);

    /* Signal the other core we are ready by triggering the event and passing the APP_RPMSG_READY_EVENT_DATA */
    (void)MCMGR_TriggerEvent(kMCMGR_RemoteApplicationEvent, APP_RPMSG_READY_EVENT_DATA);
#else
    (void)PRINTF("RPMSG Share Base Addr is 0x%x\r\n", RPMSG_LITE_SHMEM_BASE);
    my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
#endif /* MCMGR_USED */
    rpmsg_lite_wait_for_link_up(my_rpmsg);
    (void)PRINTF("Link is up!\r\n");

    my_queue  = rpmsg_queue_create(my_rpmsg);
    my_ept    = rpmsg_lite_create_ept(my_rpmsg, LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, my_queue);
    ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, ((void *)0));
    /* Introduce some delay to avoid NS announce message not being captured by the master side.
       This could happen when the remote side execution is too fast and the NS announce message is triggered
       before the nameservice_isr_cb is registered on the master side. */
    SDK_DelayAtLeastUs(1000000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
    (void)rpmsg_ns_announce(my_rpmsg, my_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE);
    (void)PRINTF("Nameservice announce sent.\r\n");

#ifdef RPMSG_LITE_MASTER_IS_LINUX
    /* Wait Hello handshake message from Remote Core. */
    (void)rpmsg_queue_recv(my_rpmsg, my_queue, (uint32_t *)&remote_addr, helloMsg, sizeof(helloMsg), ((void *)0),
                           RL_BLOCK);
#endif /* RPMSG_LITE_MASTER_IS_LINUX */

    while (true) {
        (void)PRINTF("Waiting for data...\r\n");
        (void)rpmsg_queue_recv(
            my_rpmsg, my_queue,
            (uint32_t *)&remote_addr,
            (char *)&msg,
            sizeof(msg_data_t),
            ((void *)0), RL_BLOCK
        );

        (void)PRINTF("A53: %s\r\n", msg.data);

        (void)PRINTF("Sending echo...\r\n");
        (void)rpmsg_lite_send(
            my_rpmsg,
            my_ept,
            remote_addr,
            (char *)&msg,
            sizeof(msg_data_t),
            RL_BLOCK
        );
    }

    (void)rpmsg_lite_destroy_ept(my_rpmsg, my_ept);
    my_ept = ((void *)0);

    (void)rpmsg_queue_destroy(my_rpmsg, my_queue);
    my_queue = ((void *)0);

    (void)rpmsg_ns_unbind(my_rpmsg, ns_handle);

    (void)rpmsg_lite_deinit(my_rpmsg);
    my_rpmsg = ((void *)0);

    (void)PRINTF("Looping forever...\r\n");

    /* End of the example */
    for (;;)
        ;
}

void app_create_task(void)
{
    if (xTaskCreate(app_task, "APP_TASK", APP_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, &app_task_handle) != pdPASS)
    {
        PRINTF("\r\nFailed to create application task\r\n");
        for (;;)
            ;
    }
}

/*!
 * @brief Main function
 */
int main(void)
{
    /* Initialize standard SDK demo application pins */
    /* Board specific RDC settings */
    BOARD_RdcInit();

    BOARD_InitBootPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();
    BOARD_InitMemory();

    copyResourceTable();

#ifdef MCMGR_USED
    /* Initialize MCMGR before calling its API */
    (void)MCMGR_Init();
#endif /* MCMGR_USED */

    app_create_task();
    vTaskStartScheduler();

    (void)PRINTF("Failed to start FreeRTOS on core0.\r\n");
    for (;;)
        ;
}

A53:

#include <linux/rpmsg.h>

#include <sys/ioctl.h>

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define RPMSG_DATA_SIZE 256

typedef struct {
    char data[RPMSG_DATA_SIZE];
} msg_data_t;

int main(void)
{
    msg_data_t data_buf = {
        "Hello World!"
    };

    fprintf(stderr, "==========================\n");
    fprintf(stderr, "* RPMsg Hello World demo *\n");
    fprintf(stderr, "==========================\n");

    fprintf(stderr, "Creating endpoint...\n");
    struct rpmsg_endpoint_info ept_info = {"rpmsg-openamp-demo-channel", 0x2, 0x1e};
    int fd = open("/dev/rpmsg_ctrl0", O_RDWR);
    fprintf(stderr, "File descriptor created '%d'\n", fd);
    fprintf(stderr, "Channel info: '%s' [ '%x' --> '%x' ]\n", ept_info.name, ept_info.src, ept_info.dst);

    /* create endpoint interface */
    ioctl(fd, RPMSG_CREATE_EPT_IOCTL, &ept_info);  // /dev/rpmsg0 is created
    fprintf(stderr, "Endpoint created\n");

    /* create endpoint */
    int fd_ept = open("/dev/rpmsg0", O_RDWR); // backend creates endpoint
    fprintf(stderr, "Endpoint file descriptor created '%d'\n", fd_ept);

    /* send data to remote device */
    fprintf(stderr, "Sending...\n");
    write(fd_ept, &data_buf, sizeof(data_buf));

    /* receive data from remote device */
    // fprintf(stderr, "Receiving...\n");
    // read(fd_ept, &data_buf, sizeof(data_buf));

    /* destroy endpoint */
    fprintf(stderr, "Destroying endpoint...\n");
    ioctl(fd_ept, RPMSG_DESTROY_EPT_IOCTL);
    fprintf(stderr, "Endpoint destroyed\n");

    close(fd_ept);
    close(fd);

    return 0;
}

Maybe you see what I’m doing wrong here. I suspect I’m creating my endpoint incorrectly through the /dev/rpmsg_ctrl0 control device in the A53 core, but I could be completely wrong :sweat_smile:

Best regards,
Nick