iMX7D Launching M4 Firmware with remoteproc

I’m working on the same issue as @Edward described in this post:

I can launch my M4 firmware without any issues from u-boot with the bootaux command.
Now I try to switch launching the firmware form our Linux host.

  • With my modifications shown bottom, I’m able to launch the M4 firmware form linux as many times I need it
  • But when I load my linux kernel module insmod imx_rpmsg_tty.ko no RPMSG device is enumerated under /dev/
  • If I initially launch the M4 firmware from u-boot I’m also able to reprogramm the firmware with remoteproc and the insmod imx_rpmsg_tty.ko enumerates the required device as /dev/ttyRPMSG0

My Setup:

The relevant parts of my top level devicetree

/ {
...
	reserved-memory {
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;

		cm4tcmcode: cm4tcmcode@0x7f8000 {
			compatible = "shared-dma-pool";
			reg = <0x007f8000 0x8000>;
			no-map;
		};

		cm4sramcode: cm4sramcode@0x900000 {
			compatible = "shared-dma-pool";
			reg = <0x00900000 0x40000>;
			no-map;
		};
	};
	imx7d-cm4 {
		status = "okay";
		compatible = "fsl,imx7d-cm4", "syscon";
		clocks = <&clks IMX7D_ARM_M4_ROOT_CLK>;
		syscon = <&src>; 
		nombox = "true"; // Extension making mailboxes optional in drivers/remoteproc/imx_rproc.c
		// Mailboxes for rproc have a resource conflict with mailboxes from imx_rpmsg, we can not use both
		//mbox-names = "tx", "rx", "rxdb";
		//mboxes = <&mu 0 1 &mu 1 1 &mu 3 1>;
		memory-region = <&cm4sramcode>, <&cm4tcmcode>;
	};
};
...
&mu {
	status = "okay";
};

&rpmsg {
	status = "okay";
	memory-region = <&rpmsg_reserved>;
	reg = <0x8fff0000 0x10000>;
};
..

My imx_rproc.c patch

 drivers/remoteproc/imx_rproc.c | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 4a4324fb5975..d9336b807350 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -1164,6 +1164,7 @@ static int imx_rproc_probe(struct platform_device *pdev)
 	const char *fw_name = NULL;
 	int ret;
 	int i __maybe_unused;
+	bool nombox;
 
 	regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
 	if (IS_ERR(regmap)) {
@@ -1212,10 +1213,14 @@ static int imx_rproc_probe(struct platform_device *pdev)
 
 	INIT_DELAYED_WORK(&(priv->rproc_work), imx_rproc_vq_work);
 
-	ret = imx_rproc_xtr_mbox_init(rproc);
-	if (ret) {
-		if (ret == -EPROBE_DEFER)
-			goto err_put_rproc;
+	nombox = of_property_read_bool(np, "nombox");
+
+	if(!nombox) {
+		ret = imx_rproc_xtr_mbox_init(rproc);
+		if (ret) {
+			if (ret == -EPROBE_DEFER)
+				goto err_put_rproc;
+		}
 	}
 
 	priv->clk = devm_clk_get_optional(dev, NULL);
@@ -1235,9 +1240,11 @@ static int imx_rproc_probe(struct platform_device *pdev)
 		goto err_put_rproc;
 	}
 
-	ret = imx_rproc_db_channel_init(rproc);
-	if (ret)
-		goto err_put_mbox;
+	if(!nombox) {
+		ret = imx_rproc_db_channel_init(rproc);
+		if (ret)
+			goto err_put_mbox;
+	}
 
 #ifdef CONFIG_IMX_SCU
 	priv->proc_nb.notifier_call = imx_rproc_partition_notify;
@@ -1352,10 +1359,12 @@ static int imx_rproc_probe(struct platform_device *pdev)
 	if (!priv->early_boot)
 		clk_disable_unprepare(priv->clk);
 err_put_mbox:
-	if (!IS_ERR(priv->tx_ch))
-		mbox_free_channel(priv->tx_ch);
-	if (!IS_ERR(priv->rx_ch))
-		mbox_free_channel(priv->rx_ch);
+	if(!nombox) {
+		if (!IS_ERR(priv->tx_ch))
+			mbox_free_channel(priv->tx_ch);
+		if (!IS_ERR(priv->rx_ch))
+			mbox_free_channel(priv->rx_ch);
+	}
 err_put_rproc:
 	rproc_free(rproc);
 
-- 
GitLab


I patched the u-boot as follows:

--- a/board/toradex/colibri_imx7/colibri_imx7.c
+++ b/board/toradex/colibri_imx7/colibri_imx7.c
@@ -284,11 +284,15 @@ int checkboard(void)
 #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
 int ft_board_setup(void *blob, bd_t *bd)
 {
 #if defined(CONFIG_IMX_BOOTAUX) && defined(CONFIG_ARCH_FIXUP_FDT_MEMORY)
 	int up;
-	up = arch_auxiliary_core_check_up(0);
-	if (up) {
+	// up = arch_auxiliary_core_check_up(0);
+	// if (up) {
 		int ret;
 		int areas = 1;
 		u64 start[2], size[2];
@@ -312,14 +316,17 @@ int ft_board_setup(void *blob, bd_t *bd)
 			eprintf("Cannot set usable memory\n");
 			return ret;
 		}
-	} else {
+	// } else {
 		int off;
 
 		off = fdt_node_offset_by_compatible(blob, -1,
 						    "fsl,imx7d-rpmsg");
-		if (off > 0)
-			fdt_status_disabled(blob, off);
-	}
+		fdt_status_okay(blob,off);
+	// }
#endif

I enabled some debug messages within the relevant kernel drivers.

If I launch the firmware form u-boot the kernel log output looks like this

dmesg | grep 'mu\|rpmsg'
[    0.001470] arch_timer: multiple nodes in dt, skipping
[    0.001775] pid_max: default: 32768 minimum: 301
[    0.048969] hw-breakpoint: maximum watchpoint size is 8 bytes.
[    0.049395] imx7d-pinctrl 302c0000.iomuxc-lpsr: initialized IMX pinctrl driver
[    0.050079] imx7d-pinctrl 30330000.iomuxc: initialized IMX pinctrl driver
[    0.051097] imx mu driver is registered.
[    0.051557] imx-rpmsg 8fff0000.rpmsg: dev doesn't have specific DMA pool.
[    0.051569] imx-rpmsg 8fff0000.rpmsg: imx_rpmsg_probe rpdev vdev1: vring0 0x8fff0000, vring1 0x8fff8000
[    0.051596] virtio virtio0: imx_rpmsg_set_status new status: 1
[    0.051835] imx rpmsg driver is registered.
[    0.052969] MU is ready for cross core communication!
[    0.081737] virtio_rpmsg_bus virtio0: imx_rpmsg_set_status new status: 2
[    0.081791] imx-rpmsg 8fff0000.rpmsg: vring0: phys 0x8fff0000, virt 0x(ptrval)
[    0.081834] imx-rpmsg 8fff0000.rpmsg: vring1: phys 0x8fff8000, virt 0x(ptrval)
[    0.082114] virtio_rpmsg_bus virtio0: buffers: va (ptrval), dma 0x92040000
[    0.082354] virtio_rpmsg_bus virtio0: imx_rpmsg_set_status new status: 4
[    0.082386] imx_mu 30aa0000.mu: isr: status: 00f00200 ctrl: 4c400000
[    0.082406] imx_mu 30aa0000.mu: isr: status: 00f00200 ctrl: 4c000000
[    0.082416] imx_mu 30aa0000.mu: isr: status: 04f00200 ctrl: 4c000000
[    0.082431] imx_mu 30aa0000.mu: isr: status: 04f00200 ctrl: 4c000000
[    0.082440] imx_mu 30aa0000.mu: isr: status: 04f00200 ctrl: 4c000000
[    0.082457] imx_mu 30aa0000.mu: isr: status: 00f00200 ctrl: 4c000000
[    0.082475] imx-rpmsg 8fff0000.rpmsg: rpmsg_work_handler msg: 0x0
[    0.082491] virtio_rpmsg_bus virtio0: From: 0x0, To: 0x35, Len: 40, Flags: 0, Reserved: 0
[    0.082504] rpmsg_virtio RX: 00 00 00 00 35 00 00 00 00 00 00 00 28 00 00 00  ....5.......(...
[    0.082514] rpmsg_virtio RX: 72 70 6d 73 67 2d 6f 70 65 6e 61 6d 70 2d 64 65  rpmsg-openamp-de
[    0.082524] rpmsg_virtio RX: 6d 6f 2d 63 68 61 6e 6e 65 6c 00 00 00 00 00 00  mo-channel......
[    0.082531] rpmsg_virtio RX: 00 00 00 00 00 00 00 00                          ........
[    0.082543] NS announcement: 72 70 6d 73 67 2d 6f 70 65 6e 61 6d 70 2d 64 65  rpmsg-openamp-de
[    0.082572] virtio_rpmsg_bus virtio0: creating channel rpmsg-openamp-demo-channel addr 0x0
[    0.082700] virtio_rpmsg_bus virtio0: Received 1 messages
[    0.082725] imx_mu 30aa0000.mu: isr: status: 00f00200 ctrl: 4c400000
[    0.082736] imx_mu 30aa0000.mu: isr: status: 00f00200 ctrl: 4c000000
[    0.082745] imx_mu 30aa0000.mu: isr: status: 00f00200 ctrl: 4c000000
[    0.082757] virtio_rpmsg_bus virtio0: rpmsg host is online
[    0.082769] virtio_rpmsg_bus virtio0: imx_rpmsg_set_status new status: 4

cat /sys/firmware/devicetree/base/soc/aips-bus@30800000/rpmsg/status
okay

cat /proc/interrupts | grep imx_mu
53:          3          0     GPCV2  88 Edge      imx_mu_chan[0-1], imx_mu_chan[1-1], imx_mu_chan[3-1], imx-mu-lp

after insmod imx_rpmsg_tty.ko

dmesg | grep 'mu\|rpmsg'
...
[  132.349130] imx_rpmsg_tty virtio0.rpmsg-openamp-demo-channel.-1.0: new channel: 0x400 -> 0x0!
[  132.349358] Install rpmsg tty driver!
[  132.349376] imx_rpmsg_tty virtio0.rpmsg-openamp-demo-channel.-1.0: TX From 0x400, To 0x0, Len 12, Flags 0, Reserved 0
[  132.349391] rpmsg_virtio TX: 00 04 00 00 00 00 00 00 00 00 00 00 0c 00 00 00  ................
[  132.349400] rpmsg_virtio TX: 68 65 6c 6c 6f 20 77 6f 72 6c 64 21              hello world!
[  132.349432] imx_mu 30aa0000.mu: isr: status: 00700200 ctrl: 4c400001
[  132.349448] imx_mu 30aa0000.mu: isr: status: 00700200 ctrl: 4c000001
[  132.349458] imx_mu 30aa0000.mu: isr: status: 00700200 ctrl: 4c000001

cat /proc/interrupts | grep imx_mu
53:          4          0     GPCV2  88 Edge      imx_mu_chan[0-1], imx_mu_chan[1-1], imx_mu_chan[3-1], imx-mu-lp
ls /dev/ | grep RPMSG
ttyRPMSG0

The RPMSG tty device is enumerated

If I launch the firmware from linux with remoteproc

dmesg | grep 'mu\|rpmsg'
[    0.001474] arch_timer: multiple nodes in dt, skipping
[    0.001777] pid_max: default: 32768 minimum: 301
[    0.048755] hw-breakpoint: maximum watchpoint size is 8 bytes.
[    0.049181] imx7d-pinctrl 302c0000.iomuxc-lpsr: initialized IMX pinctrl driver
[    0.049817] imx7d-pinctrl 30330000.iomuxc: initialized IMX pinctrl driver
[    0.050883] imx mu driver is registered.
[    0.051340] imx-rpmsg 8fff0000.rpmsg: dev doesn't have specific DMA pool.
[    0.051352] imx-rpmsg 8fff0000.rpmsg: imx_rpmsg_probe rpdev vdev1: vring0 0x8fff0000, vring1 0x8fff8000
[    0.051380] virtio virtio0: imx_rpmsg_set_status new status: 1
[    0.051614] imx rpmsg driver is registered.
[    0.052745] MU is ready for cross core communication!
[    0.081576] virtio_rpmsg_bus virtio0: imx_rpmsg_set_status new status: 2
[    0.081631] imx-rpmsg 8fff0000.rpmsg: vring0: phys 0x8fff0000, virt 0x(ptrval)
[    0.081676] imx-rpmsg 8fff0000.rpmsg: vring1: phys 0x8fff8000, virt 0x(ptrval)
[    0.081954] virtio_rpmsg_bus virtio0: buffers: va (ptrval), dma 0x92040000
[    0.082194] virtio_rpmsg_bus virtio0: imx_rpmsg_set_status new status: 4
[    0.110175] virtio_rpmsg_bus virtio0: rpmsg host is online
[    0.110191] virtio_rpmsg_bus virtio0: imx_rpmsg_set_status new status: 4
cat /sys/firmware/devicetree/base/soc/aips-bus@30800000/rpmsg/status
okay

cat /proc/interrupts | grep imx_mu
 53:          0          0     GPCV2  88 Edge      imx_mu_chan[0-1], imx_mu_chan[1-1], imx_mu_chan[3-1], imx-mu-lp

after:

  • programming the m4 firmware through sysfs /sys/class/remoteproc/remoteproc0/firmware
  • insmod imx_rpmsg_tty.ko
ls /dev/ | grep RPMSG

no RPMSG device is enumerated

further kernel logs after module insert

dmesg | grep 'mu\|rpmsg'
[   73.994006] imx_mu 30aa0000.mu: isr: status: 00700200 ctrl: 4c400001
[   73.994019] imx_mu 30aa0000.mu: isr: status: 00700200 ctrl: 4c000001
[   73.994027] imx_mu 30aa0000.mu: isr: status: 00700200 ctrl: 4c000001
[   73.994037] imx_mu 30aa0000.mu: isr: status: 04700200 ctrl: 4c000001
[   73.994045] imx_mu 30aa0000.mu: isr: status: 04700200 ctrl: 4c000001
[   73.994056] imx_mu 30aa0000.mu: isr: status: 00700200 ctrl: 4c000001
[   74.017431] imx-rpmsg 8fff0000.rpmsg: rpmsg_work_handler msg: 0x0

cat /proc/interrupts | grep imx_mu
 53:          2          0     GPCV2  88 Edge      imx_mu_chan[0-1], imx_mu_chan[1-1], imx_mu_chan[3-1], imx-mu-lp

I hope I provided enugh information and somone can point me to the right direction
Thanks in advice

Hi, I’m the Toradex AI Assistant. I’m in early beta, and I would appreciate your feedback.
The Toradex Support team will follow up with you shortly!

Did you like my answer?

:+1: :-1:


Greetings,

Based on the detailed information you’ve provided, it seems that the issue you’re encountering with the RPMSG device not being enumerated under /dev/ when launching the M4 firmware from Linux using remoteproc, as opposed to launching it from U-Boot, is related to the initialization sequence and the communication setup between the A7 and M4 cores.

When launching the M4 firmware from U-Boot using the bootaux command, the initialization and setup for RPMSG communication are likely being handled in a manner that is immediately recognizable by the Linux kernel once it boots. This seamless transition ensures that the RPMSG device is enumerated correctly under /dev/.

However, when launching the M4 firmware from Linux using remoteproc, it’s crucial to ensure that the RPMSG framework is correctly initialized and that the communication channels between the A7 and M4 cores are properly established. The issue you’re experiencing could be due to several factors, including but not limited to:

  1. Device Tree Configuration: Ensure that the device tree entries for remoteproc and RPMSG are correctly configured to match the expectations of the Linux kernel and the M4 firmware. This includes the reserved memory regions, the RPMSG vring buffers, and any necessary flags or properties that might influence the initialization sequence.

  2. Firmware Compatibility: Verify that the M4 firmware is designed to communicate using the RPMSG framework in a way that is compatible with the Linux kernel’s expectations. This includes the use of the correct RPMSG channels, message formats, and synchronization mechanisms.

  3. Kernel Configuration: Ensure that the Linux kernel is configured with the necessary options to support remoteproc and RPMSG. This includes the CONFIG_REMOTEPROC, CONFIG_RPMSG, and any platform-specific configurations that might be required for the iMX7D.

  4. Synchronization Timing: There might be timing issues related to when the M4 firmware is launched and when the RPMSG channels are expected to be available. Ensuring that the M4 firmware is fully initialized and ready to communicate before attempting to load the imx_rpmsg_tty.ko module might help.

  5. Debugging Output: Increase the verbosity of the debugging output for both the remoteproc and RPMSG subsystems to gain more insight into where the initialization process might be failing. This can help identify specific areas where the configuration might need adjustment.

Given the modifications you’ve made to the device tree and the kernel patch for imx_rproc.c, it

Please, also check if these links can help you solve your problem:

Running FreeRTOS on the Cortex-M7 of a Verdin iMX8M Plus | Toradex Developer Center.

I don’t remember, does kernel config allow to compile imx_rpmsg as module or not, perhaps some Kconfig prevents it? I had to blacklist imx_rpmsg module, then modprobing it after M4 is launched. Udev rule below launches script to launch M4 FW and then modprobe imx_rpmsg.

KERNEL=="imx_rproc", ACTION=="add", RUN+="/usr/local/bin/rproc_added.sh"
#!/bin/sh

echo start > /sys/class/remoteproc/remoteproc0/state
modprobe imx_rpmsg

Perhaps there’s a secret way to bind/unbind some virtio bus driver, but I don’t know how.

Thank you for your answer Edward,

The kernel does not allow to compile the imx_rpmsg as module, but I was thinking about to change it. Not sure it is even possible.
I came also to the conclusion that the issue may resists in the virtiobus driver.

I’ll keep working on it after my holiday. If I made some progress I will post the results.

Thanks again!

It is not hard to turn imx_rpmsg into module. If you search through Kconfig files, you’ll find in drivers/rpmsg/Kconfig

config HAVE_IMX_RPMSG
	bool "IMX RPMSG driver on the AMP SOCs"

Changing bool to tristate should do the trick. This should allow choosing =m or =y. For 64bit i.MX8 this should be enough. For i.MX7 your search should point as well to arch/arm/mach-imx/Kconfig, where HAVE_IMX_RPMSG is additionally forced to =y with these lines

config HAVE_IMX_RPMSG
	bool

Just remove these two or suppress them with #.

Hello @msommer,

I apologize for the delay on this topic.

Is this a valid workaround for you?
Or do you need to only start the Cortex-M4 firmware from Linux?

Best Regards,
Bruno

Hello @Edward

Thank you for your answer.
I was able to make loadable modules and it seems to work. I will do some further tests.

Best Regards

1 Like