RPMSG Lite multiple channels/endpoints

Hi,
I am implementing RPMSG-Lite communication between M4 core and Linux where M4 core acquires data from an FPGA and sends it to the Linux . In order to distinguish between data and commands I would like to have two channels of the RPMSG.

I am new to this and I’m not sure whats the difference between multiple channels, multiple instances or multiple endpoints of the RPMSG, but I’m happy with any option that could solve my problem easily :slight_smile:

Unfortunatelly, I saw this forum post (Multiple endpoints using RPMsg RTOS Layer - NXP Community) that makes it sound like this isn’t possible. Did anything change in the past two years since this post? :slight_smile:

Thanks!

Hi @swiss,

I’ve never tested it myself, to be honest. Let me search for this topic and then I will get back to you if I have something.

Best Regards,
Hiago.

1 Like

Hi @swiss,

Well, since you moved to RRPMSG Lite, you may have as many /dev/ttyRPMSG’s as you wish, you may as weel implement some other RPMSG devices. Some modifications are required in device tree and M4 side.

It is not easy to come back to something non-trivial like subject to do it from scratch. Since it is working on my side, I may miss some details.

You need two or more VDEV’s with their own VDEV VRING’s. See on M4 rpmsg_platform.h, or perhaps some other h file. Starting from default VRING allocation for iMX7D, which was 0x8FFf0000, add next VRING at +64k:

#define VDEV0_VRING_BASE 0x8FFf0000
#define VDEV1_VRING_BASE 0x90000000

64k is hard coded in Linux imx_rpmsg driver.

In *.c files on M4 side you should have multiple calls to rpmsg_lite_remote_init() like

rpmsgtty0 = rpmsg_lite_remote_init((void *)RPMSG_0_VRING, RPMSG_0_LINK_ID, RL_NO_FLAGS);

There should be no mismatch betweem VRING and LINK_ID. LINK_ID for VRING0 is 0, LINK_ID for next VRING1 is 1 and so on. Thay can’t be flipped AFAIK.

Then for each rpmsgtty on M4 you call corresponding rpmsg_queue_create(), rpmsg_lite_create_ept() and rpmsg_ns_announce().
2nd argument to rpmsg_lite_create_ept() will match your /dev/ttyRPMSGx number on Linux.
3rd argument to rpmsg_ns_announce() is RPMSG announce string, which should be recognised by imx_rpmsg_tty.c driver. Only 3 strings are defined in that driver. So you would need to add there more for more /dev/ttyRPMSG devices

static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = {
	{ .name	= "rpmsg-virtual-tty-channel-1" },
	{ .name	= "rpmsg-virtual-tty-channel" },
	{ .name = "rpmsg-openamp-demo-channel" },
	{ },
}

In device tree you shoud change vdev-nums and reg of your rpmsg node. Taking first imx8 related dts file I found, changes could be like this:

&rpmsg1{
	/*
	 * 64K for one rpmsg instance:
	 */
        /* was 
	vdev-nums = <1>;
	reg = <0x0 0x90100000 0x0 0x10000>;
       */
	vdev-nums = <2>;
	reg = <0x0 0x90100000 0x0 0x20000>;
	status = "okay";
};

As well you need to check size of memory reserved for RPMSG in your DT. If only 64k are reserved, you need to resize it accordingly to N*64k.

Hope it helps
Edward

2 Likes

Hi @swiss,

@Edward did a very good job explaining this issue (thanks again @Edward !).

@swiss let me know if something is unclear or if you need any help with that.

Best Regards,
Hiago.

1 Like

Hi @Edward
Thanks for your detailed answer!
One beginner’s question though, probably more directed to @hfranco.tx :

How do I make changes to the imx_rpmsg.c driver on Linux side (using TorizonCore)?

Thanks!

Just to let you all know, I’m extremely interested in the answer on this question as well since the answer will probably be the same as for modifying “arm/mach-imx/imx_rpmsg.c” which I am supposed to change in order to change the buffer size of RPMSG.
Recompiling the device tree for Torizon is what I already do but as far as I’am aware, no other part of Torizon can be recompiled.

Sorry if this reply is considered as hijacking. In that case, feel free to remove it from the thread. I’ll be happy to start a new thread.

Best regards,
Jeroen

1 Like

Hi @swiss,

In this case, the imx_rpmsg_tty.c driver is actually a kernel module, so it is easier to build it with TorizonCore since it doesn’t require Yocto or kernel patches. You can use TorizonCore Builder.

Please check the following guides:

Basically you will need to edit the imx_rpmsg_tty.c file and add it with TorizonCore builder:

# Sample configuration file:
input:
  easy-installer:
    local: images/torizon-core-docker-colibri-imx6-Tezi_5.3.0+build.7.tar
# Sample customization: build hello-mod module into the image
customization:
  kernel:
    modules:
      - source-dir: hello-mod/
        autoload: no
output:
  easy-installer:
    local: torizon-core-docker-colibri-imx6-Tezi_5.3.0.CUSTOM

@ompie TorizonCore is intended to use without kernel patches or other related stuff since it’s intended to be easily used by our customers. However, it’s also possible to build TorizonCore with Yocto:

Usually, we don’t recommend it because you will need to build it again every time a new TorizonCore is released and also because this requires Yocto knowledge. TorizonCore was intended to use without Yocto.

As I said above, since this is a Kernel module, it’s easier to deal with that.

Guys let me know if something is not clear or if you have any questions about it. Also, let me know if this kernel module approach worked.

Best Regards,
Hiago.

Hi @hfranco.tx ,
Thanks for your answer!
A few questions:

  • The rpmsg git repo you linked is on a branch toradex_5.4-2.3.x-imx. I am building with 5.6 and as I just saw there is a 5.7 now available, but I guess the rpmsg is completely the same?

  • To customize the kernel module, I should basically copy the rpmsg folder into my tcbworkdir, change the .c file and add the source-dir: to the yaml file?

  • The device tree overlay for RPMSG on Verdin you already sent me in this topic has this additional reserved memory part that probably needs some changes too for two endpoints. I’ve changed &rpmsg1 according to @Edward 's suggestion but I’m not sure what to do with the reserved-memory part:

&{/} {

    reserved-memory {

		#address-cells = <2>;
		#size-cells = <2>;
		ranges;
        
        vdev0vring0: vdev0vring0@B8000000 {
			compatible = "shared-dma-pool";
			reg = <0 0xB8000000 0 0x8000>;
			no-map;
		};

		vdev0vring1: vdev0vring1@B8008000 {
			compatible = "shared-dma-pool";
			reg = <0 0xB8008000 0 0x8000>;
			no-map;
		};

		vdevbuffer: vdevbuffer@b8400000 {
			compatible = "shared-dma-pool";
			reg = <0 0xb8400000 0 0x100000>;
			no-map;
		};
        
        rsc_table: rsc_table@B80FF000 {
			reg = <0 0xb80ff000 0 0x1000>;
			no-map;
		};
    };
};

&rpmsg {
	/*
	 * 64K for one rpmsg instance:
	 * --0xb8000000~0xb800ffff: pingpong
	 */
	vdev-nums = <2>;
	reg = <0x0 0xb8000000 0x0 0x20000>;
	memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>;
    status = "okay";
};

Thanks in advance for any insights!

EDIT: I guess we need two more vrings for the tx and rx of the second endpoint, and one more buffer, but I’m not sure

Hi @hfranco.tx,

Thanks for your exhaustive reply.

Instead of going the Yocto way, I prefer staying with Torizon-builder and adding a new kernel module for the required shared memory transfer I need. I’ll give it a try in the next days and let you known.

Thanks,
Jeroen

Hi @swiss,

In your DT someone decided to split RX TX rings to separate 32k areas. It doesn’t make a lot of sense, since in imx_rpmsg driver rings follow each one without any gap. 64k vdev0 reserved memory could be enough. As well it doesn’t make a lot of sense to split it for separate devices, since imx_rpmsg assumes no gaps among rings and devices, 64k for first device, then immediately 64k for next device and so on. But following exising DT code you should define two more tx/rx rings like this

 reserved-memory {
      ...
        vdev1vring0: vdev1vring0@B8010000 {
			compatible = "shared-dma-pool";
			reg = <0 0xB8010000 0 0x8000>;
			no-map;
		};

		vdev1vring1: vdev1vring1@B8018000 {
			compatible = "shared-dma-pool";
			reg = <0 0xB8018000 0 0x18000>;
			no-map;
		};     
 ...
};

&rpmsg {
     ...
    memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>, 
                   <&vdev1vring0>, <&vdev1vring1>, 
                   <&rsc_table>;
    ...
};

Accordingly you should use on M4 these ring memory defines

#define VDEV0_VRING_BASE 0xB8000000
#define VDEV1_VRING_BASE 0xB8010000

2 Likes

Hi Edward, thanks once again, I will try this.

Just to make sure and also for the next person trying this, I guess the last number stays 0x8000 and that the 0x18000 was a typpo

Yes, sorry.

1 Like

Hi @swiss and @ompie,

Great, let me know if this worked or not.

5.6 and 5.7 uses the same Kernel version, toradex_5.4-2.3.x-imx. When the next release of 6 comes out, we will start using kernel toradex_5.15-2.1.x-imx, which is based on kernel 5.15. I believe there are no modifications to 5.4 and 5.15 related to rpmsg, I need to check.

Yes, this should be enough in your case. Maybe some libraries will have to be imported as well, but probably in the rpmsg case there is no need.

The DT overlay that I sent to you in this topic was based on the NXP DT file, that’s why I separated in two vrings. But as @Edward suggested, apparently it’s better to work with only one vring. I’ll have to check that myself as well.

@Edward thanks for your contribution!

Best Regards,
Hiago.

Two channels work!
I didn’t do much in depth testing but it seems to work properly.

For anyone trying to change the rpmsg driver: don’t forget to change the Makefile as explained in this tutorial for the torizoncore builder to work.

I need to change the buffer size to get higher transfer speed but I will start a new thread if any issues occur there.
@ompie Since we are facing similiar challenges concerning rpmsg, feel free to tag me in any threads concerning rpmsg speed/buffer size that you start :slight_smile:

Thank you for the detailed answers!

1 Like