Interrupts not fired on M7 when Torizon OS is running

I have a Verdin iMX8M-Plus SoM and I use both Torizon OS on A-cores and a custom firmware on M7 core.
M7 firmware runs properly when A-cores are stopped inside u-boot.
But when Torizon OS is running, the peripheral interrupts (i.e., the interrupts coming from GPIOs) are not fired anymore in M7.
I suspect they’re routed to Torizon OS.
How can I have them routed to M7 only?
Is this a .dts change?

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:


When running a custom firmware on the M7 core of a Verdin iMX8M Plus System on Module (SoM) alongside Torizon OS on the A-cores, and facing issues with peripheral interrupts not being fired on the M7 when Torizon OS is running, it’s likely an issue related to the configuration of the interrupt controller and how the interrupts are being routed between the cores.

To ensure that peripheral interrupts are routed to the M7 core only, you will indeed need to make adjustments in the Device Tree Source (.dts) files. The Device Tree controls how resources are allocated and managed between the cores, including the routing of interrupts.

Here are the steps you should consider:

  1. Modify the Device Tree: You’ll need to adjust the interrupt controller settings in the Device Tree to ensure that interrupts from the peripherals you’re interested in are directed to the M7 core. This involves specifying the interrupt parent and the interrupts properties for the device nodes of the peripherals you’re using.

  2. Specify Interrupts for M7 Core: In the Device Tree, ensure that the peripherals’ interrupt lines are explicitly routed to the M7 core. This might involve setting the interrupt-parent property to the interrupt controller that is responsible for the M7 core and configuring the interrupts property to match the interrupt numbers and types (level or edge triggered) that the M7 core should handle.

  3. Recompile and Deploy the Device Tree: After making the necessary changes to the .dts files, recompile them to generate updated Device Tree Blob (.dtb) files. Then, deploy these updated .dtb files to your Verdin iMX8M Plus SoM and reboot the system to apply the changes.

  4. Verify Interrupt Routing: Once the system is up and running with the updated Device Tree configuration, verify that the interrupts are being correctly routed to the M7 core. You can use debugging tools and logs to confirm that the M7 core is receiving and handling the interrupts as expected.

  5. Check the FreeRTOS Configuration: Since you’re running FreeRTOS on the M7 core, ensure that its configuration is set up to properly handle the interrupts. This includes setting up the interrupt handlers in your FreeRTOS application and configuring the FreeRTOS kernel to support interrupt handling.

By carefully adjusting the Device Tree configuration and ensuring that your FreeRTOS application on the M7 core is correctly set up to handle interrupts, you should be able to resolve the issue of peripheral interrupts not being fired on

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

Cortex-M and Memory Areas on Toradex SoMs | Toradex Developer Center.

Disabling all the gpioX nodes in the dts is not an option because some Linux peripherals need some of them (ethernet, USB, …)

Modify the Device Tree: You’ll need to adjust the interrupt controller settings in the Device Tree to ensure that interrupts from the peripherals you’re interested in are directed to the M7 core. This involves specifying the interrupt parent and the interrupts properties for the device nodes of the peripherals you’re using.

How should I modify this?
Which is the proper interrupt parent?
I think NVIC for M7 core, but I don’t find any nvic node in the supplied dts or overlays.
I would expect a nvic defined in verdin-imx8mp_hmp_overlay.dts.
Is this right?

My issue seems the same as IMX8MP GPIO interrupts for M7 but it’s not clear to me how it has been solved.
I did additional test and I can say I can drive a general purpose output from M7, and so I think that the issue is that the interrupt is not routed to the NVIC (but only to GIC).
Am I right?

I’ve just receive an answer from NXP, confirming that It’s mandatory assigining one GPIO bank to one core only.
It’s not a matter of interrupt only, but there are other addiitonal points to be considered.
The important and general advece from NXP at the very beginning of schematics design is:

Decide which GPIO bank(s) should be assigned to Cortex-A and which one(s) to Cortex-M

At this point I need an answer from Toradex:
which GPIO bank(s) are not used by Torizon OS at all?

Hello @vix,

As you already figured out, NVIC provides the interrupt controller that is tightly coupled to
Cortex-M based processor cores. You need to ensure that your M7 firmware is correctly handling the interrupts. The firmware should be configured to use the NVIC (Nested Vectored Interrupt Controller) for interrupt handling on the M7 core.

So to begin with, as you found out from NXP forum, you need to decide which GPIO bank(s) should be assigned to Cortex-M. Currently, Torizon is using GPIO banks starting from 1 to 5 for different interfaces on the verdin i.MX8MP SOM. You can look through the device tree files for the SOM to understand what interfaces are using which GPIO banks and you need to disable the GPIOs that you don’t need. You can do that in the HMP overlay file.

After that you need to modify your M7 firmware files as follows (this is an example where we had to use an encoder):

uint8_t tdxenc_new_enc(
          GPIO_Type *gpio_a_base,
    const uint32_t   gpio_a_pin,
    const IRQn_Type  gpio_a_irqn,
          GPIO_Type *gpio_b_base,
    const uint32_t   gpio_b_pin,
    const IRQn_Type  gpio_b_irqn,
    const bool       reverse
) {
    const gpio_pin_config_t gpio_config = {
        .direction     = kGPIO_DigitalInput,
        .outputLogic   = 0,
        .interruptMode = kGPIO_IntRisingOrFallingEdge,
    // Init GPIOs as input with rising edge and falling edge interrupts
    GPIO_PinInit(gpio_a_base, gpio_a_pin, &gpio_config);
    GPIO_PinInit(gpio_b_base, gpio_b_pin, &gpio_config);
    GPIO_PortEnableInterrupts(gpio_a_base, 1 << gpio_a_pin);
    GPIO_PortEnableInterrupts(gpio_b_base, 1 << gpio_b_pin);
   // rest of the code
   return enc_index;

void GPIO1_INT0_IRQHandler() {
    // Handler Code

encoder_1 = tdxenc_new_enc(
        GPIO1, 0, GPIO1_INT0_IRQn,
        GPIO1, 1, GPIO1_INT1_IRQn,

In the above code, I assumed that you disabled GPIO1 and are using pin 0. You will need to write your own handler and will have to tweak the code as per your needs. Let us know if this helps.

Hi @rudhi.tx,
thanks for your answer.

This is what I did, and here is what I found.
Please, correct me if I’m wrong: Torizon Os on iMX8M-Plus doesn’t use GPIO3 and GPIO5 at all.
And so I can reserve them for M7.
GPIO1 has some IO used for some PMIC (power management) on the SoM itself and so it can’t be disabled on Linux side.
GPIO2 and GPIO4 are used by some peripherals either inside the SoM or exposed to the SoM connector. And so they can be reserved to M7 only (and if only) these peripherals are not needed.

Can you confirm the above please?
And, really important, GPIO3 and GPIO5 will be marked as M7-reserved for the future too.
I really appreciate the huge effort by Toradex, but honestly speaking, I think that the usage on GPIO pins on the SoM clould have been more consistent (i.e., use only pins on one or two banks well documented, leaving the other banks to the customer - Cortex-A or Cortex-M).

If you like, we can setup a call to discuss this important topic in detail.

Hello @vix,

From a quick walk through the device tree files, I see that GPIO5 is not used by Torizon at all. However, GPIO3 is used for HDMI which is by default disabled in our device tree. This means, if you are using the HDMI display you can’t disable GPIO3 that easily. Regarding the other GPIOS: they are of course used by some other interfaces or peripherals on the SOM. So you will have to decide what you need and free up based on your use case. I am also checking with one of my team-mates who has more experience on this topic and I will give you more information as soon as possible.

Thanks @rudhi.tx,
I’m waiting for additional info from your side.

In the manwhile, here is what I found in my investigation:

  • some pins multiplexed with GPIO3 are used for HDMI, but they’re used as perpheral HDMI functions (HDMI_SDA, HDMI_SCL, HDMI_HPD, HDMI_CEC), not as general GPIO functions. For this reason I can disable GPIO3 bank from Linux DTS and having HDMI working. I tested it.

  • some pins from GPIO1, GPIO2 and GPIO4 are used by Torizon OS. Some of them are inside the SoM itself, not exposed on the connector. But this means that the whole banks GPIO1, GPIO2 and GPIO4 must be reserved for A53 core (Torizon OS).
    A better design would have grouped all these “Torizon-needed” pins into one single bank, leaving the others free for the customer (on A53 or M7 side).
    The ideal bank for the customer would be GPIO1 because it has the individual IRQs together with the cumulative 0_15 and 16_31 (see “i.MX 8M Plus Applications Processor Reference Manual” - chapter “8.3 General Purpose Input/Output (GPIO)”).
    At a quick sight, the change to “release” GPIO1 could be possible in a next revison of the SoM, since it requires switching some GPIO pins that are not exposed to the Verdin connector (and so they’re transparent for the customer - if Torizon can handle different SoM release)

  • GPIO5 should be free… but (there is a big BUT :worried:) if I disable it in Linux dts the ethernet 0 (the one with Ethernet PHY on the module) stops working. I don’t understand why. You can test it using a Verdin iMX8M-Plus on a Verdin Development Board. If GPIO5 is enabled in Torizon OS, two ethernet interfaces are seen, with the names ethernet0 and ethernet1 in Torizon OS. If you disable GPIO5, only one ethernet is seen (the one with the PHY on the carrier) and its name is eth0 (no more the long name ethernet0)

Can you confirm this behavior?
Do you know why this happens?

Hi @vix
When I have the same issue I tried all possible combination - changes in DTS to enable/disable pins, diff configuration of interrupts on M7 side, ATF - and found only one working variant:

  • if you need to provide some inerrupt for M7 you will need to disable the WHOLE gpio bank for A53.

My guess is that GPIO interrupt management is a shared resource for the entire port. And if you want to use it for the M7, then for the A53 you must disable not just a single pin, but the entire bank of lines.

In our project, we allocated GPIO3 exclusively for the lines that are necessary for M7 interrupts and traced the PCB accordingly for it, exclude lines that can be need for A53 on GPIO3.

I couldn’t solve this problem any other way.

1 Like

Also I confirm that disabling GPIO3 will not affect the operation of HDMI in this case - I have tested this many times on the Verdin platform.

1 Like

Hello @Stan88,

Thanks for helping here! Does your HDMI hot-plug also work after you disabled the bank GPIO3?

Hello @vix,

Thanks for providing us with your test results. I could reproduce the ethernet issue by disabling gpio5. Means, I also found that the ethernet interfaces (both ethernet0 and ethernet1 on verdin development board) stop working. On further investigation we found that this is because the i2c nodes get affected by disabling gpio5. We solved it by applying the following patch:

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
index f8f428233f4a0..6eda7b2eccfd8 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
@@ -513,8 +513,6 @@ &i2c1 {
 	pinctrl-names = "default", "gpio";
 	pinctrl-0 = <&pinctrl_i2c1>;
 	pinctrl-1 = <&pinctrl_i2c1_gpio>;
-	scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
-	sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 	status = "okay";
 	pca9450: pmic@25 {
@@ -706,8 +704,6 @@ &i2c2 {
 	pinctrl-names = "default", "gpio";
 	pinctrl-0 = <&pinctrl_i2c2>;
 	pinctrl-1 = <&pinctrl_i2c2_gpio>;
-	scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
-	sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 	atmel_mxt_ts_mezzanine: touch-mezzanine@4a {
 		compatible = "atmel,maxtouch";
@@ -729,8 +725,6 @@ &i2c3 {
 	pinctrl-names = "default", "gpio";
 	pinctrl-0 = <&pinctrl_i2c3>;
 	pinctrl-1 = <&pinctrl_i2c3_gpio>;
-	scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
-	sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 /* Verdin I2C_1 */
@@ -739,8 +733,6 @@ &i2c4 {
 	pinctrl-names = "default", "gpio";
 	pinctrl-0 = <&pinctrl_i2c4>;
 	pinctrl-1 = <&pinctrl_i2c4_gpio>;
-	scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
-	sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 	gpio_expander_21: gpio-expander@21 {
 		compatible = "nxp,pcal6416";

Basically, we re-compiled the imx8mp-verdin.dtsi file and replaced the files imx8mp-verdin-nonwifi-dev.dtb and imx8mp-verdin-wifi-dev.dtb on the module (in /boot/ostree/torizon<hash>/dtb/). Also, we had the overlay with the gpio5 node disabled.
With these changes, we found that the ethernet interfaces work fine. Now, I have not tested if the interrupt work. Please give it a try and let me know how that goes. Technically it should work because if gpio5 is disabled then Interrupt 72 and 73 should be free so that the M7 can use it.

Otherwise, you can also try disabling gpio3 as @Stan88 advised. I did a quick test and can confirm that the HDMI hotplug (with native HDMI) works even with gpio3 disabled.

1 Like

Hi @rudhi.tx
thank you very much.
Your suggested patch to imx8mp-verdin.dtsi works.
Now I’m curious:

  • what is/was the reason for the scl-gpios and sda-gpios items? Are they a mistake, or they’re used in other scenarios?
  • why not deleting "gpio" from pinctrl-names and pinctrl-1 (that refer to pinctrl_xxxx_gpio) too?

If Toradex is not going to change the default imx8mp-verdin.dtsi, is it possible for me deleting the items scl-gpios and sda-gpios from another .dtsi that includes this one (like my carrier board .dtsi)?
So that the solution is much more clear and easily maintenable in the future.

Hello @vix,

  • what is/was the reason for the scl-gpios and sda-gpios items? Are they a mistake, or they’re used in other scenarios?

These are used for I2C recovery mode. So you should be aware that by removing scl-gpios and sda-gpios you are losing this functionality.

  • why not deleting "gpio" from pinctrl-names and pinctrl-1 (that refer to pinctrl_xxxx_gpio) too?

You can do that also. It should not break anything theoretically.

If Toradex is not going to change the default imx8mp-verdin.dtsi , is it possible for me deleting the items scl-gpios and sda-gpios from another .dtsi that includes this one (like my carrier board .dtsi )?

We don’t have any concrete plans at the moment to delete these properties from the default imx8mp-verdin.dtsi file. However, a cleaner solution for you would be to delete these properties from your custom carrier board dts file as in the following example:

&i2c1 {
    /delete-property/ scl-gpios;
    /delete-property/ sda-gpios;

what is I2C recovery mode?
The “usual” recovery mode of the Yavia works withtou any issue.


Hi @vix,

I2C recovery is a method used to recover an I2C bus that has become stuck or locked. Basically you would use it to reset your I2C devices using techniques such as sending a series of clock pulses (bus reset sequence), clock stretching, power cycling etc. It has nothing to do with the recovery mode of the SOM itself.

Thanks @rudhi.tx
is this method used in some way by Torizon OS on Verdin iMX8M-Plus?
And so I will loose something if I disable it?

Hi @vix,

It is not used on the SOM itself. Usually, it is used on the application side by the user/developer to reset the I2C slave devices as I mentioned. If you are not doing that already you should be good to go.

1 Like