ttyRPMSG0 from M4 an Verdin AM62

Hello everyone,

First up: In my Yocto build, my goal is to start a firmware on the M4 co-processor (on Verdin AM62) which then created the device /dev/ttyRPMSG0 in userspace, so my application (running on linux) can communicate with the firmware (running on the M4).

A year ago i tried more or less the same thing in TorizonOS (see How to communicate with M4 on the Verdin AM62 through ttyRPMSG)… in the end it worked.

Now I’m setting up a Yocto with the scarthgap-7.x.y BSP from Toradex with a custom image-recipe (based on the tdx-reference-minimal-image). I had to modify my DTO for the M4 a little (in comparison to the TorizonOS DTO), because in k3-am62-mcu.dtsi from the Yocto-BSP the mcu_m4fss note is disabled. So this is my DTO which is applied successfully at system startup:

/*
 * Description:
 * This overlay confugured the ipc (inter processor communication) between M4F, R5F and Linux.
 */

/dts-v1/;
/plugin/; //Indicates a Device Tree Overlay


/ {
    /* Set hardware compatibility */
    compatible = "toradex,verdin-am62-nonwifi-dev",
             "toradex,verdin-am62-nonwifi",
             "toradex,verdin-am62",
             "ti,am625";
};

&{/} {
    /* memory reservation for ipc mailbox system */
	reserved-memory {
		#address-cells = <2>;
		#size-cells = <2>;
		ranges;

		ramoops@9c700000 {
			compatible = "ramoops";
			reg = <0x00 0x9c700000 0x00 0x00100000>;
			record-size = <0x8000>;
			console-size = <0x8000>;
			ftrace-size = <0x00>;
			pmsg-size = <0x8000>;
		};

		/* global cma region */
		linux,cma {
			compatible = "shared-dma-pool";
			reusable;
			size = <0x00 0x8000000>;
			linux,cma-default;
		};

		rtos_ipc_memory_region: ipc-memories@9c800000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9c800000 0x00 0x00300000>;
			no-map;
		};

		mcu_m4fss_dma_memory_region: m4f-dma-memory@9cb00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9cb00000 0x00 0x100000>;
			no-map;
		};

		mcu_m4fss_memory_region: m4f-memory@9cc00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9cc00000 0x00 0xe00000>;
			no-map;
		};

		wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@9da00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9da00000 0x00 0x00100000>;
			no-map;
		};

		wkup_r5fss0_core0_memory_region: r5f-memory@9db00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9db00000 0x00 0x00c00000>;
			no-map;
		};

	};
};

/* inter-processor communication mailbox system configuration */
&mailbox0_cluster0 {
	status = "okay";
	
	mbox_m4_0: mbox-m4-0 {
		ti,mbox-rx = <0 0 0>;
		ti,mbox-tx = <1 0 0>;
	};

	mbox_r5_0: mbox-r5-0 {
		ti,mbox-rx = <2 0 0>;
		ti,mbox-tx = <3 0 0>;
	};

};

&mcu_m4fss {
	status = "okay";
	mboxes = <&mailbox0_cluster0 &mbox_m4_0>;
	mbox-names = "tx", "rx";
	memory-region = <&mcu_m4fss_dma_memory_region>,
			<&mcu_m4fss_memory_region>;
	firmware-name = "blub.out";
	wakeup-source;
};

&wkup_r5fss0_core0 {
	mboxes = <&mailbox0_cluster0 &mbox_r5_0>;
	memory-region = <&wkup_r5fss0_core0_dma_memory_region>,
			<&wkup_r5fss0_core0_memory_region>;
};

These sources are derived from here.

So the problem is, i can start the firmware but the /dev/ttyRPMSG0 isn’t created. Here are some outputs which may be informative.

root@verdin-am62-15479005:~# cat /sys/class/remoteproc/remoteproc0/state
offline


root@verdin-am62-15479005:~# modprobe rpmsg_tty
root@verdin-am62-15479005:~# lsmod |grep rpmsg
rpmsg_tty              16384  0
rpmsg_ctrl             12288  0
rpmsg_char             16384  1 rpmsg_ctrl
virtio_rpmsg_bus       20480  0
rpmsg_ns               16384  1 virtio_rpmsg_bus
rpmsg_core             12288  5 virtio_rpmsg_bus,rpmsg_char,rpmsg_ctrl,rpmsg_tty,rpmsg_ns

root@verdin-am62-15479005:~# dmesg | grep -i rpmsg
[    8.602715] virtio_rpmsg_bus virtio0: rpmsg host is online
[    8.603286] virtio_rpmsg_bus virtio0: creating channel ti.ipc4.ping-pong addr 0xd
[    8.616219] virtio_rpmsg_bus virtio0: creating channel rpmsg_chrdev addr 0xe


root@verdin-am62-15479005:~# cat /sys/module/firmware_class/parameters/path
/etc/company/m4f/
root@verdin-am62-15479005:~# cat /sys/class/remoteproc/remoteproc0/firmware
blub.out


root@verdin-am62-15479005:~# echo "start" > /sys/class/remoteproc/remoteproc0/state
[  272.429049] remoteproc remoteproc0: powering up 5000000.m4fss
[  272.449805] remoteproc remoteproc0: Booting fw image blub.out, size 484060
[  272.467205] rproc-virtio rproc-virtio.6.auto: assigned reserved memory node m4f-dma-memory@9cb00000
[  272.479756] virtio_rpmsg_bus virtio1: rpmsg host is online
[  272.485568] rproc-virtio rproc-virtio.6.auto: registered virtio1 (type 7)
[  272.492491] remoteproc remoteproc0: remote processor 5000000.m4fss is now up

root@verdin-am62-15479005:~# cat /sys/class/remoteproc/remoteproc0/state
running

root@verdin-am62-15479005:~# ls /sys/class/remoteproc/
remoteproc0  remoteproc1  remoteproc2  remoteproc3
root@verdin-am62-15479005:~# cat /sys/class/remoteproc/remoteproc0/name
5000000.m4fss
root@verdin-am62-15479005:~# ls /dev/ttyRPMSG0
ls: cannot access '/dev/ttyRPMSG0': No such file or directory

root@verdin-am62-15479005:~# dmesg | grep -i rpmsg
[    8.602715] virtio_rpmsg_bus virtio0: rpmsg host is online
[    8.603286] virtio_rpmsg_bus virtio0: creating channel ti.ipc4.ping-pong addr 0xd
[    8.616219] virtio_rpmsg_bus virtio0: creating channel rpmsg_chrdev addr 0xe
[  272.479756] virtio_rpmsg_bus virtio1: rpmsg host is online

As a comparison: If the firmware is started on the TorizonOS i receive the following output (note the last line):

[  230.446611] remoteproc remoteproc0: powering up 5000000.m4fss
[  230.447635] remoteproc remoteproc0: Booting fw image blub.out, size 484060
[  230.451652] rproc-virtio rproc-virtio.6.auto: assigned reserved memory node m4f-dma-memory@9cb00000
[  230.454073] virtio_rpmsg_bus virtio1: rpmsg host is online
[  230.454136] rproc-virtio rproc-virtio.6.auto: registered virtio1 (type 7)
[  230.454146] remoteproc remoteproc0: remote processor 5000000.m4fss is now up
[  230.459683] virtio_rpmsg_bus virtio1: creating channel rpmsg-tty addr 0xf

The firmware is the exact same firmware which is also used in the TorizonOS setup.

Here are some snippets from the firmware:

main.c

...
status = RPMessage_waitForLinuxReady(SystemP_WAIT_FOREVER);
DebugP_assert(status==SystemP_SUCCESS);

/* Register a callback for the RP_MBOX messages from the Linux remoteproc driver*/
IpcNotify_registerClient(IPC_NOTIFY_CLIENT_ID_RP_MBOX, &ipc_rp_mbox_callback, NULL);

v_ipcDLL_rpmsgCreateRecvEndpoints();
...

ipcDLL.c

...
void v_ipcDLL_rpmsgCreateRecvEndpoints()
{
    int32_t status;
    RPMessage_CreateParams createParams;

    RPMessage_CreateParams_init(&createParams);
    createParams.localEndPt = IPC_RPMESSAGE_ENDPT_SU;
    //createParams.recvCallback = &v_rpMessageRecCallback;
    status = RPMessage_construct(&gIpcRecvMsgObject[0], &createParams);
    DebugP_assert(status==SystemP_SUCCESS);


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

    DebugP_log("Announce RPmessage-endpoint \r\n");

    status = RPMessage_announce(CSL_CORE_ID_A53SS0_0, IPC_RPMESSAGE_ENDPT_SU, IPC_RPMESSAGE_SERVICE_SU);
    DebugP_assert(status==SystemP_SUCCESS);
}
...

with

  • #define IPC_RPMESSAGE_SERVICE_SU "rpmsg-tty"
  • #define IPC_RPMESSAGE_ENDPT_SU (15U)

I already tried a lot, searched the web and used some AI but can’t get it to work. So what am I missing?

Thanks in advance :slight_smile:

Kind Regards

Uwe

Hi, I’m the Toradex AI Assistant.

I might make mistakes. Our support team will step in if needed. If I answered your question, please tick the “Solution” checkbox. For follow-up questions to me, please use @ToradexAI in your post.

Did you like my answer? :+1: :-1:


Hello Uwe,

Thank you for your detailed description and configuration. Your approach and the outputs you provided are very helpful in pinpointing the issue.

Problem Explanation

The issue here is that your M4 firmware is announcing the RPMsg service with the service name “rpmsg-tty” and using endpoint 15:

#define IPC_RPMESSAGE_SERVICE_SU          "rpmsg-tty"
#define IPC_RPMESSAGE_ENDPT_SU            (15U)

However, the Linux-side rpmsg_tty driver on Verdin AM62 (and as per Toradex documentation) expects a specific, pre-defined service name and often a specific endpoint to create the /dev/ttyRPMSG0 device.

What the Linux Driver Expects

  • Service Name: "rpmsg-virtual-tty-channel-1"
  • Endpoint: 30 (usually defined as LOCAL_EPT_ADDR (30) in the reference MCUXpresso SDK/SDK examples)

From the Cortex-M RPMsg Guide:

For the TTY demo to work properly, the firmware should announce the service as “rpmsg-virtual-tty-channel-1”.
Example:
#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-virtual-tty-channel-1"

So, the rpmsg_tty kernel module will not create /dev/ttyRPMSG0 unless the firmware announces a service with the expected name.


Solution Steps

  1. Update the Service Name and Endpoint in Your Firmware

    In your firmware, change:

    #define IPC_RPMESSAGE_SERVICE_SU          "rpmsg-virtual-tty-channel-1"
    #define IPC_RPMESSAGE_ENDPT_SU            (30U)
    

    …and ensure that your RPMessage_announce and endpoint creation use these values.

  2. Device Tree Overlay

    If you are not already, consider testing with the official Toradex HMP overlay for Verdin AM62:

    verdin-am62_hmp_overlay.dtbo
    

    This can help rule out device tree/overlay issues.

  3. Reboot and Test

    • Re-flash your firmware with the changes above.
    • Reboot the system.
    • Start the M4 core as before.
    • Check for the creation of /dev/ttyRPMSG0.
    • Check dmesg | grep -i rpmsg for a line similar to:
      virtio_rpmsg_bus virtio1: creating channel rpmsg-virtual-tty-channel-1 addr 0x1e
      
    • If this line appears, /dev/ttyRPMSG0 should now be available.

Additional Notes

  • The rest of your device tree and mailbox configuration appears reasonable.
  • Since the firmware works in TorizonOS and not Yocto, it’s most likely not a firmware build issue, but a configuration/expectation mismatch.

References:


Summary:
Update your M4 service name to "rpmsg-virtual-tty-channel-1" and the endpoint to 30, as expected by the Linux rpmsg_tty driver. That should resolve the missing /dev/ttyRPMSG0 problem.

Let me know if you have any further questions or need clarification!

Best regards, Toradex AI Assistant.

@ToradexAI I don’t think updating the service name is the right way, because the the reference you give (Cortex-M RPMsg Guide) refers to an Verdin iMX8M Mini as example. Also as I stated the firmware works on the same SOM (Verdin AM62) with TorizonOS on it - but not with my Yocto-Linux.

Thanks for your response.

Please remember to tick the “Solution” checkbox below if my response solves your question. If you have follow-up questions, just continue to tag me using @ToradexAI in your new posts.

Did you like my answer? :+1: :-1:


Thank you for your feedback and for clarifying your observations.

You are correct that the reference specifically mentions Verdin iMX8M Mini, and that the same firmware works on Verdin AM62 with TorizonOS, but not with your Yocto Linux build. This strongly suggests that the issue is not with your firmware or the service name, but rather with differences between the kernel configuration or modules in TorizonOS and your Yocto build. The key is that TorizonOS and your Yocto build should behave the same if all kernel modules, drivers, and device tree settings are consistent.

Here are actionable steps you can take, focusing on your Yocto build:


1. Confirm Kernel Module and Driver Configuration

  • Did you enable the CONFIG_RPMSG_TTY kernel option in your Yocto configuration?
    Double-check your defconfig or run zcat /proc/config.gz | grep RPMSG to confirm that CONFIG_RPMSG_TTY, CONFIG_RPMSG_CHAR, CONFIG_RPMSG_CTRL, and CONFIG_VIRTIO_RPMSG_BUS are all enabled, either as built-in (=y) or modules (=m).
  • Are all expected modules loaded?
    Run lsmod | grep rpmsg before and after starting the remoteproc firmware. You should see the following:
    rpmsg_tty
    rpmsg_ctrl
    rpmsg_char
    virtio_rpmsg_bus
    rpmsg_ns
    rpmsg_core
    
    From your output, it looks like these are present, so this step seems OK.

2. Compare dmesg and Modules between Yocto and TorizonOS

On both images, after loading your firmware:

  • Run dmesg | grep -i rpmsg and compare the output.
    On TorizonOS, you see the line:

    virtio_rpmsg_bus virtio1: creating channel rpmsg-tty addr 0xf
    

    On Yocto, this line is missing. This implies that the kernel driver did not recognize your announced RPMsg service.

  • Run cat /proc/devices | grep rpmsg and ls /dev/ | grep rpmsg to check if the devices are created in both cases.


3. Check Kernel and Device Tree Patches

TorizonOS may have kernel patches or overlay device tree changes not present in your Yocto build.

  • Device Tree: Double-check your device tree overlays match those used in TorizonOS, or review Toradex’s evaluation overlays.
  • Kernel Version/Branch: Compare your kernel version and branch with the one used in TorizonOS. You may want to use the exact Toradex kernel branch for AM62 (e.g. toradex_ti-linux-6.6.y).

4. Confirm RPMsg Service Name Handling in Your Kernel

The difference could be that TorizonOS’s kernel has been patched or configured to recognize your custom service name (“rpmsg-tty”), while your Yocto kernel is stricter about the expected name (e.g., “rpmsg-virtual-tty-channel-1”).

  • Search for rpmsg_tty.c in your kernel source and check for the expected service name string(s).
  • If necessary, add your service name, or, for testing, change the firmware’s service name temporarily to the default expected by the kernel.

5. Short Checklist Recap

  • Double-check kernel configs, driver versions, and overlays match TorizonOS.
  • Compare TorizonOS and Yocto dmesg logs side-by-side.
  • If everything looks the same, try renaming your firmware’s service as a test. If this creates the device, then it’s a kernel driver expectation mismatch.

Links for Reference


Summary:
Since your firmware and device tree work under TorizonOS, focus on kernel configuration and driver details in your Yocto image. If you identify a difference, matching TorizonOS should resolve the /dev/ttyRPMSG0 issue.

Let me know what you find, or if you want more detailed step-by-step commands!

Best regards, Toradex AI Assistant.

@ToradexAI

So i checked the Kernel modules:

root@verdin-am62-15479005:~# zcat /proc/config.gz | grep RPMSG
CONFIG_RPMSG_TTY=m
CONFIG_SND_SOC_FSL_RPMSG=m
CONFIG_SND_SOC_IMX_AUDIO_RPMSG=m
CONFIG_SND_SOC_IMX_PCM_RPMSG=m
CONFIG_SND_SOC_IMX_RPMSG=m
CONFIG_RPMSG=m
CONFIG_RPMSG_CHAR=m
CONFIG_RPMSG_CTRL=m
CONFIG_RPMSG_NS=m
# CONFIG_RPMSG_QCOM_GLINK_RPM is not set
CONFIG_RPMSG_VIRTIO=m
CONFIG_RPMSG_PRU=m

Seems like CONFIG_VIRTIO_RPMSG_BUS is missing. I will investigate this further.


On both (Yocto and TorizonOs) the output is identical:

root@verdin-am62-15479005:~# cat /proc/devices | grep rpmsg
239 rpmsg_ctrl
240 rpmsg_char
root@verdin-am62-15479005:~# ls /dev/ | grep rpmsg
rpmsg0
rpmsg_ctrl0
rpmsg_ctrl1

I checked rpmsg_tty.c. Here is a snippet:

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2021 STMicroelectronics - All Rights Reserved
 *
 * The rpmsg tty driver implements serial communication on the RPMsg bus to makes
 * possible for user-space programs to send and receive rpmsg messages as a standard
 * tty protocol.
 *
 * The remote processor can instantiate a new tty by requesting a "rpmsg-tty" RPMsg service.
 * The "rpmsg-tty" service is directly used for data exchange. No flow control is implemented yet.
 */

#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/rpmsg.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
...

So the service name rpmsg-tty seems correct.

Thanks for your response.

Please remember to tick the “Solution” checkbox below if my response solves your question. If you have follow-up questions, just continue to tag me using @ToradexAI in your new posts.

Did you like my answer? :+1: :-1:


Thank you for your detailed feedback and investigation!

You’re absolutely right—the service name rpmsg-tty is correct for your kernel’s rpmsg_tty driver, and your firmware is announcing it properly. The rpmsg_tty.c code you found confirms this expectation, so updating the service name is unnecessary in your case.

The real problem seems clear now:
Your kernel is missing the CONFIG_VIRTIO_RPMSG_BUS configuration.


Why is CONFIG_VIRTIO_RPMSG_BUS Important?

  • In your kernel configuration output, you have:
    CONFIG_RPMSG_VIRTIO=m
    
    but no line for
    CONFIG_VIRTIO_RPMSG_BUS
    
  • This kernel option is responsible for instantiating the RPMsg bus and connecting virtio-based RPMsg devices, essential for creating RPMsg channels from the remote processor’s announcements (such as rpmsg-tty).
  • In TorizonOS, this option is correctly enabled, which is why /dev/ttyRPMSG0 appears there with no other difference in firmware.

What to Do Next

  1. Enable CONFIG_VIRTIO_RPMSG_BUS in Your Kernel

    • In your Yocto kernel configuration, ensure you have:
      CONFIG_VIRTIO_RPMSG_BUS=m
      
      (or =y, but =m is more common for modular drivers.)
  2. Rebuild the Kernel and Modules
    Rebuild your image and ensure the new module is installed on your root filesystem.

  3. Check Module Loading

    • After boot, check lsmod for the presence of virtio_rpmsg_bus.
    • If it is not loaded automatically, load it with:
      modprobe virtio_rpmsg_bus
      
    • You should then see the expected RPMsg device behavior upon starting your M4 firmware.
  4. Re-test Firmware Startup

    • Start the M4 firmware as before.
    • Examine dmesg for messages like:
      virtio_rpmsg_bus virtio1: creating channel rpmsg-tty addr ...
      
    • /dev/ttyRPMSG0 should now appear.

References


Summary:
The missing /dev/ttyRPMSG0 on your Yocto-based Linux is almost certainly due to the absence of CONFIG_VIRTIO_RPMSG_BUS. Add this option, rebuild, and your RPMsg TTY should work identically to TorizonOS.

Let me know if enabling this kernel config resolves your issue!

Best regards, Toradex AI Assistant.

@ToradexAI

So I checked the available Kernel modules via bitbake virtual/kernel -c menuconfig and searched for RPMSG. But there is no CONFIG_VIRTIO_RPMSG_BUS to enable.

I also check the output on my TorizonOS system, which also has no CONFIG_VIRTIO_RPMSG_BUS:

torizon@verdin-am62-15479036:~$ zcat /proc/config.gz | grep RPMSG
CONFIG_RPMSG_TTY=m
# CONFIG_SND_SOC_FSL_RPMSG is not set
CONFIG_RPMSG=y
CONFIG_RPMSG_CHAR=m
CONFIG_RPMSG_CTRL=m
CONFIG_RPMSG_NS=m
# CONFIG_RPMSG_QCOM_GLINK_RPM is not set
CONFIG_RPMSG_VIRTIO=m
CONFIG_RPMSG_PRU=m
CONFIG_RPMSG_KDRV=y
# CONFIG_RPMSG_KDRV_DEMO is not set
# CONFIG_RPMSG_KDRV_DISPLAY is not set
CONFIG_RPMSG_KDRV_ETH_SWITCH=y
CONFIG_SAMPLE_RPMSG_CLIENT=m

The only real difference I see is that the TorizonOS has CONFIG_SAMPLE_RPMSG_CLIENT=m

Thanks for your response.

Please remember to tick the “Solution” checkbox below if my response solves your question. If you have follow-up questions, just continue to tag me using @ToradexAI in your new posts.

Did you like my answer? :+1: :-1:


Thank you for investigating further and providing the kernel configuration outputs from both your Yocto build and TorizonOS.

You are absolutely right: There is no explicit CONFIG_VIRTIO_RPMSG_BUS kernel config on either system. The essential configuration option for RPMsg over virtio on TI platforms is CONFIG_RPMSG_VIRTIO, which you have as a module (=m) on both TorizonOS and Yocto.

However, I notice a more critical difference upon closer inspection:


Key Difference

Yocto:

CONFIG_RPMSG=m

TorizonOS:

CONFIG_RPMSG=y

This means:

  • In TorizonOS, the core RPMsg subsystem is built into the kernel (=y), available immediately at boot.
  • In your Yocto build, it’s a module (=m), which requires explicit loading order and may lead to missing functionality at the time the remote processor starts.

This detail is highly relevant for correct inter-processor operation, especially for dynamic device creation like /dev/ttyRPMSG0, which must happen as soon as the remote firmware comes up.


Steps to Fix

  1. Change CONFIG_RPMSG to built-in:

    • In your Yocto kernel configuration, set:
      CONFIG_RPMSG=y
      
    • This ensures the RPMsg core is always present when needed by the other rpmsg-related modules.
  2. Optionally match CONFIG_SAMPLE_RPMSG_CLIENT:

    • Enable the sample RPMsg client as:
      CONFIG_SAMPLE_RPMSG_CLIENT=m
      
      This is a minor difference but will fully align your kernel config with TorizonOS, though it’s not strictly necessary for RPMsg TTY to work.
  3. Rebuild and deploy your kernel and modules.

  4. Test again:

    • Boot the system, load related modules if modular, and start the MCU firmware.
    • /dev/ttyRPMSG0 should now appear as expected.

Additional Debugging (if the problem persists)

  • Ensure correct module loading order: rpmsg_core and virtio_rpmsg_bus should be loaded before the remoteproc firmware is started.
  • Double-check your device tree overlays match those used by TorizonOS.
  • Use the exact same kernel version and branch for consistency: linux-toradex.git toradex_ti-linux-6.6.y

Summary

The probable cause of the missing /dev/ttyRPMSG0 is that your Yocto build sets CONFIG_RPMSG=m (module), while TorizonOS uses CONFIG_RPMSG=y (built-in). Making this change will ensure the RPMsg infrastructure is always ready for use, matching TorizonOS behavior.

Let me know how this works out or if you have further questions!

Best regards, Toradex AI Assistant.


References:

I added CONFIG_SAMPLE_RPMSG_CLIENT=m. That didn’t resolve my problem.
I also tried to set CONFIG_RPMSG to =y, but since this is set to =m by default, I was not able to modify this (tried much, but didn’t get it to work).

Need some help here.
As I already said: I also tried to resolve my problem with several AI tools… but any tool told me more or less the same stuff (like ToradexAI) and it didn’t helped me :frowning:

Hello,

here some additional informations:

We debugged the firmware which runns in the M4. In the System_init()(among other things) the function Sciclient_pmModuleClkRequest() is called. At the end of this function it is checked if the flag TISCI_MSG_FLAG_ACK is set… it is NOT. So the system init fails and the firmware does not announce the rpmsg-tty. But we still don’t know why :frowning:

Here is the full Sciclient_pmModuleClkRequest() code:

Header

/**
*  \brief    Message to set the clock state:
*  This requests for finer control of hardware device's clocks. This allows
*  for configuration for hardware blocks that require customization of the
*  specific input clocks. NOTE: each of the clock IDs are relative to the
*  hardware block.
*
*  \n<b>Message</b>:    #TISCI_MSG_SET_CLOCK
*  \n<b>Request</b>:    #tisci_msg_set_clock_req
*  \n<b>Response</b>:   #tisci_msg_set_clock_resp
*
*  \param  moduleId        Module for which the state should be set.
*  \param  clockId         Clock Id for the module.
*  \param  state           Clock State requested.
*  \param  additionalFlag  Certain flags can also be set to alter the clock
*                          state.
*  \param  timeout         Gives a sense of how long to wait for the operation.
*  \return SystemP_SUCCESS on success, else failure
*/
int32_t Sciclient_pmModuleClkRequest(uint32_t moduleId,
                                     uint32_t clockId,
                                     uint32_t state,
                                     uint32_t additionalFlag,
                                     uint32_t timeout);

Source

int32_t Sciclient_pmModuleClkRequest(uint32_t moduleId,
                                     uint32_t clockId,
                                     uint32_t state,
                                     uint32_t additionalFlag,
                                     uint32_t timeout)
{
    int32_t retVal = SystemP_SUCCESS;
    struct tisci_msg_set_clock_req request ;
    request.device = (uint32_t) moduleId;
 
    if(clockId > (uint32_t)(255U))
    {
        request.clk = (uint8_t)(255U);
        request.clk32 = clockId;
    }
    else
    {
        request.clk    = (uint8_t)clockId;
    }
    request.state  = (uint8_t) state;
 
    Sciclient_ReqPrm_t reqParam ;
    reqParam.messageType    = (uint16_t) TISCI_MSG_SET_CLOCK;
    reqParam.flags          = (uint32_t) TISCI_MSG_FLAG_AOP | additionalFlag;
    reqParam.pReqPayload    = (const uint8_t *) &request;
    reqParam.reqPayloadSize = (uint32_t) sizeof (request);
    reqParam.timeout        = (uint32_t) timeout;
 
    Sciclient_RespPrm_t respParam ;
    respParam.flags           = (uint32_t) 0;   /* Populated by the API */
    respParam.pRespPayload    = (uint8_t *) NULL;
    respParam.respPayloadSize = (uint32_t) 0;
 
    retVal = Sciclient_service(&reqParam, &respParam);
    if((retVal != SystemP_SUCCESS) ||
        ((respParam.flags & TISCI_MSG_FLAG_ACK) != TISCI_MSG_FLAG_ACK))
    {
        retVal = SystemP_FAILURE;
    }
    return retVal;
}

After 7 days, I would like to ask politely if someone from Toradex can help?
Maybe @bruno.tx or someone else?

Kind Regards
Uwe

Hello @buw3,

Sorry for the delay on this topic.
I will ask for someone to look into this topic and get back to you.

Best Regards,
Bruno

Hi @buw3,

I did a small experiment on my side and I can share some results.

Currently we are working on adding the necessary nodes to Verdin AM62 device tree to make rpmsg and remoteproc work properly. You can check the patch that was sent to linux here: [PATCH 18/33] arm64: dts: ti: k3-am62-verdin: Add missing cfg for TI IPC Firmware.

These nodes can also be added to the overlay.

Next, I compiled the ipc_rpmsg_echo_linux demo from the TI MCU SDK. I had to change how the rpmsg announces itslef on the virtio bus to call the rpmsg tty correctly:

diff --git a/examples/drivers/ipc/ipc_rpmsg_echo_linux/ipc_rpmsg_echo.c b/examples/drivers/ipc/ipc_rpmsg_echo_linux/ipc_rpmsg_echo.c
index 15143d395dcd..096488c28a07 100644
--- a/examples/drivers/ipc/ipc_rpmsg_echo_linux/ipc_rpmsg_echo.c
+++ b/examples/drivers/ipc/ipc_rpmsg_echo_linux/ipc_rpmsg_echo.c
@@ -69,7 +69,7 @@
  * The service names MUST match what linux is expecting
  */
 /* This is used to run the echo test with linux kernel */
-#define IPC_RPMESSAGE_SERVICE_PING        "ti.ipc4.ping-pong"
+#define IPC_RPMESSAGE_SERVICE_PING        "rpmsg-tty"
 #define IPC_RPMESSAGE_ENDPT_PING          (13U)

 /* This is used to run the echo test with user space kernel */

With that, after calling the modprobe rpmsg_tty, I can see the device was created.

root@verdin-am62-15479173:~# ls /dev/ttyRPMSG0
/dev/ttyRPMSG0

And on the MCU side:

[IPC RPMSG ECHO] Version: REL.MCUSDK.K3.10.00.00.14+ (Aug 22 2025 15:36:24):
[IPC RPMSG ECHO] Remote Core waiting for messages at end point 13 ... !!!
[IPC RPMSG ECHO] Remote Core waiting for messages at end point 14 ... !!!

So the device was created, but I was not able to send messages because this demo is not prepared to display this tty messages. In you case you can check the MCU code to display the messages being send by rpmsg_tty, but I think the real trick here is to have all device tree nodes properly enabled and make sure the driver announces itself with the correct name.

I am not sure the reason TI calls the driver as “ti.ipc4.ping-pong”. I can see Zephyr does it correctly: zephyr/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c at db15de527442c4842c52e125e3d2e29b7b1f6e04 · zephyrproject-rtos/zephyr · GitHub

I will have to further investigate to check the reason behind this name, but I believe this should be sufficient to try on your side.

Best regards,
Hiago.

Hallo @hfranco.tx,
thank you for the reply. It’s good to hear, that you have got it to work - more or less :slight_smile:

I’ve checked the patch you mentioned. The patch does almost the same as my overlay I provided in my first post. The only thing my overlay didn’t do, was enabling the node &wkup_r5fss0 and &wkup_r5fss0_core0 with status = "okay";. So I updated my overlay. Here it is:

/*
 * Description:
 * This overlay configures the ipc (inter processor communication) between M4F, R5F and Linux.
 */

/dts-v1/;
/plugin/; //Indicates a Device Tree Overlay


/ {
    /* Set hardware compatibility */
    compatible = "toradex,verdin-am62-nonwifi-dev",
             "toradex,verdin-am62-nonwifi",
             "toradex,verdin-am62",
             "ti,am625";
};

&{/} {
    /* memory reservation for ipc mailbox system */
	reserved-memory {
		#address-cells = <2>;
		#size-cells = <2>;
		ranges;

		ramoops@9c700000 {
			compatible = "ramoops";
			reg = <0x00 0x9c700000 0x00 0x00100000>;
			record-size = <0x8000>;
			console-size = <0x8000>;
			ftrace-size = <0x00>;
			pmsg-size = <0x8000>;
		};

		/* global cma region */
		linux,cma {
			compatible = "shared-dma-pool";
			reusable;
			size = <0x00 0x8000000>;
			linux,cma-default;
		};

		rtos_ipc_memory_region: ipc-memories@9c800000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9c800000 0x00 0x00300000>;
			no-map;
		};

		mcu_m4fss_dma_memory_region: m4f-dma-memory@9cb00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9cb00000 0x00 0x100000>;
			no-map;
		};

		mcu_m4fss_memory_region: m4f-memory@9cc00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9cc00000 0x00 0xe00000>;
			no-map;
		};

		wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@9da00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9da00000 0x00 0x00100000>;
			no-map;
		};

		wkup_r5fss0_core0_memory_region: r5f-memory@9db00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9db00000 0x00 0x00c00000>;
			no-map;
		};

	};
};

/* inter-processor communication mailbox system configuration */
&mailbox0_cluster0 {
	status = "okay";
	
	mbox_m4_0: mbox-m4-0 {
		ti,mbox-rx = <0 0 0>;
		ti,mbox-tx = <1 0 0>;
	};

	mbox_r5_0: mbox-r5-0 {
		ti,mbox-rx = <2 0 0>;
		ti,mbox-tx = <3 0 0>;
	};

};

&mcu_m4fss {
	status = "okay";
	mboxes = <&mailbox0_cluster0 &mbox_m4_0>;
	memory-region = <&mcu_m4fss_dma_memory_region>,
			<&mcu_m4fss_memory_region>;
	firmware-name = "SmartUnited_HvacDaliMaster.out";
	wakeup-source;
};

&wkup_r5fss0 {
	status = "okay";
};

&wkup_r5fss0_core0 {
	mboxes = <&mailbox0_cluster0 &mbox_r5_0>;
	memory-region = <&wkup_r5fss0_core0_dma_memory_region>,
			<&wkup_r5fss0_core0_memory_region>;
	status = "okay";
};

Unfortunately this doesn’t solve my problem. The firmware does still not create /dev/ttyRPMSG0.

I think our firmware isn’t the problem. We already use rpmsg-tty to announce the rpmsg on the virtio bus and the firmware on TorizonOS works like a charm.

Is my newly modified overlay correct? Would you have written it differently?
When can we expect the adjustments you mentioned (regarding rpmsg and remoteproc to work properly) to go live?

Kind Regards,
Uwe

Hi @buw3,

Can you check if at least the rpmsg-tty channel is created on you side? You should see something like:

[  230.534715] virtio_rpmsg_bus virtio1: creating channel rpmsg-tty addr 0xd

I just tried on my side and it worked. I installed the latest BSP scarthgap-7.x.y quartely (7.3.0), toradex-reference-minimal-image. The I compiled your overlay:

/*
 * Description:
 * This overlay confugured the ipc (inter processor communication) between M4F, R5F and Linux.
 */

/dts-v1/;
/plugin/; //Indicates a Device Tree Overlay

/ {
	/* Set hardware compatibility */
	compatible = "toradex,verdin-am62-nonwifi-dev",
		     "toradex,verdin-am62-nonwifi",
		     "toradex,verdin-am62",
		     "ti,am625";
};

&{/} {
    /* memory reservation for ipc mailbox system */
	reserved-memory {
		#address-cells = <2>;
		#size-cells = <2>;

		ramoops@9c700000 {
			compatible = "ramoops";
			reg = <0x00 0x9c700000 0x00 0x00100000>;
			record-size = <0x8000>;
			console-size = <0x8000>;
			ftrace-size = <0x00>;
			pmsg-size = <0x8000>;
		};

		/* global cma region */
		linux,cma {
			compatible = "shared-dma-pool";
			reusable;
			size = <0x00 0x8000000>;
			linux,cma-default;
		};

		rtos_ipc_memory_region: ipc-memories@9c800000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9c800000 0x00 0x00300000>;
			no-map;
		};

		mcu_m4fss_dma_memory_region: m4f-dma-memory@9cb00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9cb00000 0x00 0x100000>;
			no-map;
		};

		mcu_m4fss_memory_region: m4f-memory@9cc00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9cc00000 0x00 0xe00000>;
			no-map;
		};

		wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@9da00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9da00000 0x00 0x00100000>;
			no-map;
		};

		wkup_r5fss0_core0_memory_region: r5f-memory@9db00000 {
			compatible = "shared-dma-pool";
			reg = <0x00 0x9db00000 0x00 0x00c00000>;
			no-map;
		};

	};
};

/* inter-processor communication mailbox system configuration */
&mailbox0_cluster0 {
	status = "okay";
	
	mbox_m4_0: mbox-m4-0 {
		ti,mbox-rx = <0 0 0>;
		ti,mbox-tx = <1 0 0>;
	};

	mbox_r5_0: mbox-r5-0 {
		ti,mbox-rx = <2 0 0>;
		ti,mbox-tx = <3 0 0>;
	};

};

&mcu_m4fss {
	status = "okay";
	mboxes = <&mailbox0_cluster0 &mbox_m4_0>;
	mbox-names = "tx", "rx";
	memory-region = <&mcu_m4fss_dma_memory_region>,
			<&mcu_m4fss_memory_region>;
	wakeup-source;
};

&wkup_r5fss0_core0 {
	mboxes = <&mailbox0_cluster0 &mbox_r5_0>;
	memory-region = <&wkup_r5fss0_core0_dma_memory_region>,
			<&wkup_r5fss0_core0_memory_region>;
};

&mcu_uart0 {
	status = "reserved";
};

(I just added the mcu_uart0 at the end so I could see the messages from the cortex-m4 side).

Next I loaded the overlay and loaded the ipc_rpmsg_echo_linux demo from TI and I can see the channel was created the /dev/ttyRPMSG0 was also created:

root@verdin-am62-15479173:~# cat /sys/class/remoteproc/remoteproc0/firmware
am62-mcu-m4f0_0-fw
root@verdin-am62-15479173:~# cp ipc_rpmsg_echo_linux.release.out /lib/firmware/am62-mcu-m4f0_0-fw
root@verdin-am62-15479173:~# echo start > /sys/class/remoteproc/remoteproc0/state
[  230.492399] remoteproc remoteproc0: powering up 5000000.m4fss
[  230.506681] remoteproc remoteproc0: Booting fw image am62-mcu-m4f0_0-fw, size 490524
[  230.520520] rproc-virtio rproc-virtio.6.auto: assigned reserved memory node m4f-dma-memory@9cb00000
[  230.533599] virtio_rpmsg_bus virtio1: rpmsg host is online
[  230.534715] virtio_rpmsg_bus virtio1: creating channel rpmsg-tty addr 0xd
[  230.539310] rproc-virtio rproc-virtio.6.auto: registered virtio1 (type 7)
[  230.546239] virtio_rpmsg_bus virtio1: creating channel rpmsg_chrdev addr 0xe
[  230.555711] remoteproc remoteproc0: remote processor 5000000.m4fss is now up
root@verdin-am62-15479173:~# ls /dev/ttyRPMSG0
/dev/ttyRPMSG0
> Is my newly modified overlay correct? Would you have written it differently?

I believe it is correct yes, the test on my side shows the m4 is working. If you do not want any IPC with the cortex-R5, you can remove the “wkup” and “r5” nodes. Please notice this core runs the DM firmware, so you can not load a custom firmware there without breaking anything related to the kernel. You should use cortex-M4 for custom firmware for AM62.

In addition, I see you are adding the “linux,cma” and “ramoops” nodes, this is fine but it is not related to the cortex-m4, so make sure you really need those nodes.

Best regards,
Hiago.

1 Like

Hello @hfranco.tx :slight_smile:

First things first: It’s working now! :tada:
But not with the 7.3.0 quarterly release, but with the current 7.4.0 monthly release.


Before it was working:

At first I did the same as you (build the toradex-reference-minimal-image). Normaly I had my own image recipe, which is based on the toradex-reference-minimal-image…

I was also already on scarthgap-7.x.y quartely (7.3.0). Then added only the overlay (as you did), removed anything other from my custom-layer. Did a clean build and flashed the image.

We then build the ipc_rpmsg_echo_linux demo from TI (with #define IPC_RPMESSAGE_SERVICE_PING "rpmsg-tty"). But the output after starting the firmware was the same as we get with our firmware:

root@verdin-am62-15479005:~# echo "start" > /sys/class/remoteproc/remoteproc0/state
[  630.368714] remoteproc remoteproc0: powering up 5000000.m4fss
[  630.386968] remoteproc remoteproc0: Booting fw image am62-mcu-m4f0_0-fw.out, size 489932
[  630.401986] rproc-virtio rproc-virtio.6.auto: assigned reserved memory node m4f-dma-memory@9cb00000
[  630.415822] virtio_rpmsg_bus virtio1: rpmsg host is online
[  630.429734] rproc-virtio rproc-virtio.6.auto: registered virtio1 (type 7)
[  630.436845] remoteproc remoteproc0: remote processor 5000000.m4fss is now up
root@verdin-am62-15479005:~# ls /dev/ttyRPMSG0
ls: /dev/ttyRPMSG0: No such file or directory

After it was working:

Then I did a repo sync and landed on the current 7.4.0 (commit:
960ab35b9ae9f1b603746480214f21bc1ed1bbbe
)
. With that I did several builds for testing (toradex-reference-minimal-image, my custom image) and everything was working.

So I’m back on my custom image recipe with the device-tree-overlay you posted in your previous post and all my other modifications (I had at the start of this thread) and it is still working!


So are you sure you were an BSP 7.3.0? not on 7.4.0?

scarthgap-7.x.y points to 7.4.0 now - see https://git.toradex.com

For me it seems that the BSP 7.4.0 does the trick. Does it has something to do with the ongoing modifications you mentioned?


I’m appreciating all your help! Thank you @hfranco.tx

Kind Regards,
Uwe

Hi @buw3,

I am glad it is working for you now. If my previous message solved your issue, can you mark it as solved? Thank you.

Interesting, are you sure on 7.3.0 you had everything expected to make this work? I checked and I was indeed using 7.3.0 build.8, minimal image, and I do not expect different changes from 7.3.0 to monthly 7.4.0 to make this work, as the changes I shared are not yet merged into our kernel.

Is it possible that before you repo sync the recipes were outdated?

Best regards,
Hiago.

Hi @hfranco.tx

I checked my versions.

Where it doesn’t worked, I was on commit 83a9921ee84e313eaa82c805db2fe3a39cf6ff5e (2025-06-04) - not on the quarterly release :man_facepalming:

So maybe that was the problem.
Something must have changed until the commit of the quarterly release 5413a515b32b61d3ed333445538c3e1dfd8cd3bc (2025-07-21).

Thank you again.

Kind Regards,
Uwe