My device tree overlay enables a GPIO but breaks UART_B and UART_C

I’m using Torizon on a Colibri iMX6DL. SODIMM pin 190 is not available as a GPIO in the default device tree, but I need to use it as a GPIO to support a custom carrier board. I wrote a device tree overlay a while ago which does enable pin 190 as a GPIO but I just discovered that a side-effect of my device tree overlay is that UART_B and UART_C stop working. There must be something wrong with either my device tree overlay source code, or with the way I am deploying it onto the device. Can you review my file and my method?

The problem happens the same way with Torizon 6.7.0, 6.8.0 and 7.0.0. I’ll document the steps with 7.0.0 here as that is currently the most recent release. The reply from tdx-info on my module is:

Software summary
------------------------------------------------------------
Bootloader:               U-Boot
Kernel version:           6.6.53-7.0.0-00029-g68da80fb0462 #1-Torizon SMP PREEMPT Mon Jun 17 16:49:11 UTC 2024
Kernel command line:      enable_wait_mode=off galcore.contiguousSize=50331648 root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 ostree=/ostree/boot.1/torizon/be872468b7b697020ed89215ad325489e49742b825240eef396819058c8d8f10/0
Distro name:              NAME="Torizon OS Upstream"
Distro version:           VERSION_ID=7.0.0-build.1
Hostname:                 colibri-imx6-10634753
------------------------------------------------------------

Hardware info
------------------------------------------------------------
HW model:                 Toradex Colibri iMX6DL/S on Colibri Evaluation Board V3
Toradex version:          0015 V1.1A
Serial number:            10634753
Processor arch:           armv7l
------------------------------------------------------------

The source code for my device tree overlay is in a file I called HeartbeatLed.dts. It disables the SD card interface and adds pin 190 as a GPIO:

/dts-v1/;
/plugin/;

#include "linux/arch/arm/boot/dts/nxp/imx/imx6dl-pinfunc.h"

/ {
    compatible = "toradex,colibri_imx6dl";
};

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_test>;

	colibri-imx6dl {
		pinctrl_test: gpiomuxgrp {
        		fsl,pins = <
          			MX6QDL_PAD_SD1_CMD__GPIO1_IO18         0x1b0b0  /* SODIMM 190 */
	        	>;
   		};
	};
};

&usdhc1 {
    status = "disabled";
};

I added a tcbuild.yaml file to refer to my device tree overlay:

input:
  easy-installer:
    local: torizon-docker-colibri-imx6-Tezi_7.0.0+build.1.tar
customization:
  device-tree:
    include-dirs:
      - linux/include/
    custom: linux/arch/arm/boot/dts/nxp/imx/imx6dl-colibri-eval-v3.dts
    overlays:
      add:
        - HeartbeatLed.dts
output:
  easy-installer:
    local: torizon-docker-colibri-imx6-Tezi_7.0.0.CUSTOM

I downloaded the TEZI image to match my module using these commands:

wget https://tezi.toradex.com/artifactory/torizoncore-oe-prod-frankfurt/scarthgap-7.x.y/release/1/colibri-imx6/torizon-upstream/torizon-docker/oedeploy/torizon-docker-colibri-imx6-Tezi_7.0.0+build.1.tar
torizoncore-builder images unpack torizon-docker-colibri-imx6-Tezi_7.0.0+build.1.tar

Then I cloned the kernel source code using these commands:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
cd linux
git checkout tags/v6.6.53
cd ..
git clone -b master git://git.toradex.com/device-tree-overlays.git device-trees

Then I built and deployed my device tree overlay using these commands:

torizoncore-builder build
torizoncore-builder images unpack torizon-docker-colibri-imx6-Tezi_7.0.0.CUSTOM
torizoncore-builder deploy --remote-host 192.168.86.47 --remote-username torizon --remote-password xxxx --reboot

These commands did all appear to succeed normally and the result was that I did get access to pin 190 as a GPIO. But when the module boots the output from UART_A includes multiple error messages like this:

imx6dl-pinctrl 20e0000.pinctrl: invalid function pinctrl in map table

And although pin 190 works as intended, UART_B and UART_C no longer work.

Hi, I’m the Toradex AI Assistant. The Toradex Support team will follow up with you shortly!

Did you like my answer?

:+1: :-1:


Hello,

It sounds like you’re encountering a conflict in your device tree overlay that affects UART_B and UART_C when enabling SODIMM pin 190 as a GPIO. Let’s go through some steps to help you resolve this issue:

  1. Review Pin Assignments: Double-check the Colibri iMX6DL datasheet to ensure that SODIMM pin 190, which you are configuring as a GPIO, does not conflict with any pins used by UART_B and UART_C. It’s crucial to verify that these UARTs are not using the same pins or have overlapping configurations.

  2. Check Pin Control Settings: The error message invalid function pinctrl in map table indicates a potential misconfiguration. Ensure that the fsl,pins property in your overlay is correctly set and does not interfere with the pins assigned to UART_B and UART_C. You might need to adjust the pin control settings to avoid conflicts.

  3. Minimal Changes Testing: Temporarily comment out the GPIO configuration for pin 190 in your overlay and reboot the system to see if UART_B and UART_C functionality is restored. This step can help confirm whether the GPIO configuration is causing the issue.

  4. Consult Documentation: Review the Toradex documentation for device tree overlays and the Colibri iMX6DL module. Pay special attention to sections on pin multiplexing and potential conflicts to ensure your configurations align with recommended practices.

  5. Debugging: Consider using debugging tools to trace the pin control settings during boot. This can help identify where the configuration might be failing or conflicting with UART settings.

By carefully reviewing and adjusting your device tree overlay, you should be able to resolve the conflicts and restore UART functionality while maintaining the GPIO configuration for pin 190.

If you have any further questions or need additional assistance, feel free to reach out.

Best regards,
Toradex AI Assistant

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

https://community.nxp.com/t5/i-MX-Processors/i-MX6-how-to-use-RTS-CTS-properly-using-UART-DTE-DCE/m-p/460022

Tdx-reference-multimedia-image stop device tree overlay(s).

Hey @MikeS,

What sticks out to me is when you modify your &iomuxc node, you only have your new pinctrl-0 group referenced. the pinctrl-0 property allows these pins to be used in userspace. If you look here, and look at this property you’ll see:

&iomuxc {    pinctrl-names = "default";    pinctrl-0 = <&pinctrl-originally-in-device-tree>, <&pinctrl_my_pins>;  // D) OPTION #1: Pin group available in userspace i.e. as GPIO

So you need to include the “<&pinctrl-originally-in-device-tree>”. You can most likely find a reference to this in your carrier board dts file.

-Eric

Thanks for replying @eric.tx , I really wanted your suggestion to be the solution as it seemed so logical but despite trying it multiple times with a few variations I continued to have the same problem.

I am using a Colibri iMX6DL with a Colibri evaluation board v3 so I looked at this file:
linux\arch\arm\boot\dts\nxp\imx\imx6dl-colibri-eval-v3.dts

That file contains this section:

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <
		&pinctrl_weim_gpio_1 &pinctrl_weim_gpio_2
		&pinctrl_weim_gpio_3 &pinctrl_weim_gpio_4
		&pinctrl_weim_gpio_5 &pinctrl_weim_gpio_6
		&pinctrl_usbh_oc_1 &pinctrl_usbc_id_1
	>;
};

So I tried modifying my overlay file to look like this following the suggestion on the page you linked to:

/dts-v1/;
/plugin/;

#include "linux/arch/arm/boot/dts/nxp/imx/imx6dl-pinfunc.h"

/ {
    compatible = "toradex,colibri_imx6dl";
};

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <
		&pinctrl_weim_gpio_1 &pinctrl_weim_gpio_2
		&pinctrl_weim_gpio_3 &pinctrl_weim_gpio_4
		&pinctrl_weim_gpio_5 &pinctrl_weim_gpio_6
		&pinctrl_usbh_oc_1 &pinctrl_usbc_id_1
        >,
        <&pinctrl_test>;

	colibri-imx6dl {
		pinctrl_test: gpiomuxgrp {
        		fsl,pins = <
          			MX6QDL_PAD_SD1_CMD__GPIO1_IO18         0x1b0b0  /* SODIMM 190 */
	        	>;
   		};
	};
};

&usdhc1 {
    status = "disabled";
};

But unfortunately, that behaves the same as before: it breaks UART_B and UART_C and while booting it causes lots of debug output like this:

imx6dl-pinctrl 20e0000.pinctrl: invalid function pinctrl in map table

I also tried doing it this way, but the result was the same:

/dts-v1/;
/plugin/;

#include "linux/arch/arm/boot/dts/nxp/imx/imx6dl-pinfunc.h"

/ {
    compatible = "toradex,colibri_imx6dl";
};

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <
		&pinctrl_weim_gpio_1 &pinctrl_weim_gpio_2
		&pinctrl_weim_gpio_3 &pinctrl_weim_gpio_4
		&pinctrl_weim_gpio_5 &pinctrl_weim_gpio_6
		&pinctrl_usbh_oc_1 &pinctrl_usbc_id_1
        &pinctrl_test
        >;

	colibri-imx6dl {
		pinctrl_test: gpiomuxgrp {
        		fsl,pins = <
          			MX6QDL_PAD_SD1_CMD__GPIO1_IO18         0x1b0b0  /* SODIMM 190 */
	        	>;
   		};
	};
};

&usdhc1 {
    status = "disabled";
};

And I tried changing the compatible line to this, but with no effect:

compatible = "toradex,colibri_imx6dl-eval-v3";

Did I use the right source file for the existing device tree which I am modifying, and I did I extract the right section of that file?

Hey @MikeS,

If you remove the device tree overlay, does the image work as intended?

-Eric

Hi @eric.tx,

Yes, I’ve been adding and removing the device tree overlay while doing these experiments. Each time I remove the device tree overlay I confirm that the UARTs do work again, then I add the device tree overlay and test the UARTs again. But each time I try to enable the pin as a GPIO in the device tree overlay it stops the UARTs from working, and it causes the kernel to produce error messages while booting.

One interesting test that I did was to deploy only the part of my device tree overlay which disables the SD card interface (As shown below). This device tree overlay allows the kernel to boot cleanly with no error messages, the UARTs still work, but of course my GPIO pin does not work with this overlay. I think this is a useful experiment as it shows that I can deploy a device tree overlay successfully, and I can disable the SD card interface without any problems. The problem comes from adding a pin to the GPIO mux.

/dts-v1/;
/plugin/;

#include "linux/arch/arm/boot/dts/nxp/imx/imx6dl-pinfunc.h"

/ {
    compatible = "toradex,colibri_imx6dl";
};


&usdhc1 {
    status = "disabled";
};

Hey @MikeS,

Thanks for the update. It’s not immediately obvious what might be the issue. It might be a slight syntax error in the device tree. Can you remove the subnode “colibri-imx6dl” surrounding the pinctrl group. Looking at other &iomuxc nodes in imx6qdl-colibri it is not standard to reference named node.

-Eric

Thanks @eric.tx, that was it! I was also able to simplify my overlay by list listing the one pin I want to add without duplicating the list of pins from the base copy of the device tree. Thanks for sticking with me till we solved this. It’s interesting that the problematic version of the overlay does build without any syntax errors, but doesn’t work when deployed. The device tree overlay which works is:

/dts-v1/;
/plugin/;

#include "linux/arch/arm/boot/dts/nxp/imx/imx6dl-pinfunc.h"

/ {
    compatible = "toradex,colibri_imx6dl-eval-v3";
};

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_my_pins>;

	pinctrl_my_pins: my_muxgrp {
        	fsl,pins = <
        		MX6QDL_PAD_SD1_CMD__GPIO1_IO18         0x1b0b0
	       	>;
   	};
};

&usdhc1 {
    status = "disabled";
};