How to enable pins as GPIO

I’m trying to set the pin 67 to a gpio.

  • I downloaded torizon
  • Installed it
  • Downloaded and started the docker image for devs
  • Used dtconf to check the available overlays

Now I tried to make my own, but no matter what I put into the pinctrl-0 section, the overlay fails to compile. If I leave it empty, it compiles fine.

My overlay:

/dts-v1/;
/plugin/;

/ {
	compatible = "toradex";
	fragment@0 {
		target = <&iomuxc>;
		__overlay__ {
			pinctrl-names = "default";
			pinctrl-0 = <
				&pinctrl_additionalgpio	
			>;
		};
	};

	pinctrl_additionalgpio: additionalgpios {
  		fsl,pins = <
			MX6QDL_PAD_EIM_A24__GPIO5_IO04      0x1b0b0
		>;
	};
};

I’ve also tried compiling the version from here, but it complained about node not existing again, which is fair, as I haven’t set the &pinctrl_my_gpios anywhere, but even after I change it to &pinctrl_gpio1, which does exist in the imx6ull-colibri.dtsi, it still doesn’t compile, even if I include the file.

The error I’ve been talking about all along was this

# dtconf activate enable_gpio_colibri_imx6.dts
Device is colibri imx6(0014)
Building enable_gpio_colibri_imx6.dts
Successfully built device tree
Validating ./enable_gpio_colibri_imx6.dts.dtbo
Error running fdtdump.
FDT_ERR_NOTFOUND: The requested node or property does not exist.
Failed to apply ./enable_gpio_colibri_imx6.dts.dtbo (-1)

Invalid overlay

Greetings @MGlolenstine,

First of all the proper syntax would have your new pinctrl node under the iomuxc node for example like here:

/dts-v1/;
/plugin/;

#include "imx6dl-pinfunc.h"

/ {
	fragment@6 {
		target = <&iomuxc>;
		__overlay__ {
			pinctrl-names = "default";
			pinctrl-0 = <&pinctrl_test>;

			pinctrl_test: gpiomuxgrp {
				fsl,pins = <
					MX6QDL_PAD_EIM_D18__GPIO3_IO18 	0x1b0b0
					MX6QDL_PAD_EIM_WAIT__GPIO5_IO00	0x1b0b0
					MX6QDL_PAD_EIM_A19__GPIO2_IO19 	0x1b0b0
					MX6QDL_PAD_EIM_RW__GPIO2_IO26 	0x1b0b0
					MX6QDL_PAD_EIM_A25__GPIO5_IO02 	0x1b0b0
					MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x1b0b0
				>;
			};
		};
	};
};

Also note the include statement at the top as you have to include the relevant pinfunc file as that is where the pins are defined. These pinfunc files should be included as part of the overlay container. Finally make sure when you compile your overlay that the overlay file is in the same directory as the pinfunc file.

but even after I change it to
&pinctrl_gpio1, which does exist in
the imx6ull-colibri.dtsi, it still
doesn’t compile, even if I include the
file.

As for this issue here, I’m confused you reference the i.MX6ULL but your environment states you’re working on the i.MX6. In which case you’d need to look at the iomuxc/pinctrl nodes in the i.MX6 device tree source.

Best Regards,
Jeremias

I was reffering to the imx6ull-colibri.dtsi because it was the only file, that had the &pinctrl_gpio1 in it. Thanks for your answer, I’ll be testing it out now

I have a few questions, as I didn’t quite grasp the docs on this one…

  • Where do I find gpiomuxgrp?
  • Is pinctrl_test just a variable name and can it be anything?
  • Do we have to use fragment#6 here, or can we start with the fragment#0?
  • Aren’t there issues with the initialization if you skip fragment numbers?

I need to set the following pins as GPIOs 19, 21, 23, 25, 29, 31, 37, 47, 49 and 51. Do you think maybe some of them are unable to be set as GPIO and that’s the reason for the inability to boot?

Upon adding the following overlay to my iMX6, the device refuses to boot.

 /dts-v1/;
 /plugin/;
 
 #include "imx6dl-pinfunc.h"
 
 / {
     fragment@0 {
         target = <&iomuxc>;
         __overlay__ {
             pinctrl-names = "default";
             pinctrl-0 = <&pinctrl_test>;
 
             pinctrl_test: gpiomuxgrp {
                 fsl,pins = <
			MX6QDL_PAD_EIM_ADDR21__GPIO2_IO17	0x1b0b0
			MX6QDL_PAD_EIM_DATA24__GPIO3_IO24	0x1b0b0
			MX6QDL_PAD_SD4_CLK__GPIO7_IO10		0x1b0b0
			MX6QDL_PAD_EIM_DATA20__GPIO3_IO20	0x1b0b0
			MX6QDL_PAD_SD4_CMD__GPIO7_IO09		0x1b0b0
			MX6QDL_PAD_SD1_DATA2__GPIO1_IO19	0x1b0b0
			MX6QDL_PAD_EIM_DATA19__GPIO3_IO19	0x1b0b0
			MX6QDL_PAD_EIM_DATA23__GPIO3_IO23	0x1b0b0
			/*MX6QDL_PAD_NAND_DATA07__GPIO2_IO07	0x1b0b0*/
			MX6QDL_PAD_SD1_DATA1__GPIO1_IO17	0x1b0b0
			MX6QDL_PAD_SD1_CLK__GPIO1_IO20		0x1b0b0
			MX6QDL_PAD_EIM_DATA25__GPIO3_IO25	0x1b0b0
                 >;
             };
         };
     };
 };

Furthermore, uncommenting of the commented pin causes parse errors and that’s probably because it’s defined as

#define MX6QDL_PAD_NANDF_D7__NAND_DATA07            0x2a0 0x688 0x000 0x0 0x0

in the imx6dl-pinfunc.h, and I think that this means I’d need to call it MX6QDL_PAD_NANDF_D7, even tho it’s named differently in the datasheet.

Where do I find gpiomuxgrp?

Is pinctrl_test just a variable name
and can it be anything?

These are just arbitrary names, more information on general device tree syntax can be read here.

Do we have to use fragment#6 here, or
can we start with the fragment#0?
Aren’t there issues with the initialization if you skip fragment numbers?

You should start from 0 this was just an snippet from an example overlay I had.

in the imx6dl-pinfunc.h, and I think that this means I’d need to call it MX6QDL_PAD_NANDF_D7, even tho it’s named differently in the datasheet.

Yes the pins names in the device tree are defined via the respective pinfunc file. The pin names from the datasheet while similar have no meaning in the context of the device tree. Make sure to always check names when referencing hardware in software as the datasheet is in the context of hardware not software.

Finally as for your overall boot issues. You need to be cautious when assigning pins as GPIOs as these pins may already be pinmuxed as some other default. The default pinmuxings for the i.MX6 can be found here, the iomuxc node is towards the bottom. Not resolving such pinmuxing conflicts can lead to unpredictable issues such as failure to boot. In order to resolve these issues the most straightforward way would be to disable the nodes in the device tree (or an overlay) that use the pins you want to set as GPIOs. You must be careful when disabling subsystems though as it may be a subsystem you require or a critical subsystem for the overall system. In which case you’ll need to shuffle pins around to both have the pins you want as GPIOs and have the subsystems you need be active.

Best Regards,
Jeremias

Thanks for your answer!

How would I go about the disabling? Create a new fragment for every muxed pin, that I want to disable?

For example, one for the iomuxc another for pwm2, and so on?

Yes this would be the correct workflow for this. Below is an example overlay for another customer. You can see there is fragment for each subsystem that needed to be disabled in order to free pins. Then a final GPIO fragment where these pins are now reassigned as GPIOs.

/dts-v1/;
/plugin/;

#include <imx6dl-pinfunc.h>

/ {
   compatible = "toradex,colibri_imx6dl", "fsl,imx6dl";

   /* Disable pwm1 to use MX6QDL_PAD_GPIO_9__GPIO1_IO09 */
   fragment@0 {
      target = <&pwm1>;
      __overlay__ { status = "disabled"; };
   };

   /* Disable pwm3 to use MX6QDL_PAD_SD4_DAT1__GPIO02_IO09 */
   fragment@1 {
      target = <&pwm3>;
      __overlay__ { status = "okay"; };
   };

   /* Disable pwm4 to use MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 */
   fragment@2 {
      target = <&pwm4>;
      __overlay__ { status = "disabled"; };
   };

   /* Disable SPI to use pins from MX6QDL_PAD_EIM_(D22,D28,D21*,A25*) */
   fragment@3 {
      target = <&ecspi4>;
      __overlay__ { status = "disabled"; };
   };

   /* Disable weim to use pins from MX6QDL_PAD_SD2_CLK__ */
   fragment@4 {
      target = <&weim>;
      __overlay__ { status = "disabled"; };
   };

   fragment@5 {
     target = <&iomuxc>;
     __overlay__ {
        pinctrl-names = "default";     
        pinctrl-0 = <&pinctrl_test>;

        pinctrl_test: gpiomuxgrp {
           fsl,pins = < 
              MX6QDL_PAD_SD4_DAT1__GPIO2_IO09   0x1b0b0 /* SODIMM 59  - GRN2  (J2-14) &pwm3   */
              MX6QDL_PAD_SD2_CLK__GPIO1_IO10    0x1b0b0 /* SODIMM 93  - RED2  (J2-16) &weim   */
              MX6QDL_PAD_GPIO_9__GPIO1_IO09     0x1b0b0 /* SODIMM 28  - RSTS2 (J2-13) &pwm1   */
              MX6QDL_PAD_SD4_DAT2__GPIO2_IO10   0x1b0b0 /* SODIMM 30  - GSTS2 (J2-12) &pwm4   */
              MX6QDL_PAD_SD2_DAT1__GPIO1_IO14   0x1b0b0 /* SODIMM 106 - YEL1  (J2-4)  &weim   */
              MX6QDL_PAD_EIM_CS1__GPIO2_IO24    0x1b0b0 /* SODIMM 107 - GRN1  (J2-5)  &weim   */
              MX6QDL_PAD_EIM_CS0__GPIO2_IO23    0x1b0b0 /* SODIMM 105 - RED1  (J2-3)  &weim   */
              MX6QDL_PAD_EIM_RW__GPIO2_IO26     0x1b0b0 /* SODIMM 89  - RSTS1 (J2-6)  &weim   */
              MX6QDL_PAD_EIM_D21__GPIO3_IO21    0x1b0b0 /* SODIMM 88  - GSTS1 (J2-7)  &ecspi4 */
              MX6QDL_PAD_EIM_A25__GPIO5_IO02    0x1b0b0 /* SODIMM 86  - EX03  (J3-16  &ecspi4 */
              MX6QDL_PAD_SD2_DAT3__GPIO1_IO12   0x1b0b0 /* SODIMM 99  - FAN   (J5-2   &weim   */
           >;
        };
     };
   };
};

Thanks!

I’ll test it out and report back!

Kind regards,
MGlolenstine

I tested it out, but the device still isn’t booting…
Here is my new ‘enable_gpio.dts’ file with some comments of what they disable.
I’ve also enabled it and the verification was successful.

/dts-v1/;
/plugin/;

#include <imx6dl-pinfunc.h>

/ {
  compatible = "toradex,colibri_imx6dl", "fsl,imx6dl";
  // EIM_A21
  fragment@0 {
    target = <&pwm2>;
    __overlay__ { status = "disabled"; };
  };

  // EIM_D24
  // EIM_D20
  // EIM_D19
  fragment@1 {
     target = <&pinctrl_uart1_dte>;
     __overlay__ { status = "disabled"; };
  };

  // SD4_CLK
  // SD4_CMD
  fragment@2 {
     target = <&pinctrl_uart3_dte>;
     __overlay__ { status = "disabled"; };
  };

  // SD1_DAT1
  // SD1_DAT2
  fragment@3 {
     target = <&pinctrl_usdhc1>;
     __overlay__ { status = "disabled"; };
  };

  // EIM_D23
  fragment@4 {
     target = <&pinctrl_uart1_ctrl>;
     __overlay__ { status = "disabled"; };
  };

  // Enable backlight pwm
  fragment@5 {
     target = <&pwm1>;
     __overlay__ { status = "enabled"; };
  };

  fragment@6 {
    target = <&iomuxc>;
    __overlay__ {
      pinctrl-names = "default";
       pinctrl-0 = <&pinctrl_test>;

       pinctrl_test: gpiomuxgrp {
         fsl,pins = <
         MX6QDL_PAD_EIM_A21__GPIO2_IO17    0x1b0b0
         MX6QDL_PAD_EIM_D24__GPIO3_IO24    0x1b0b0
         MX6QDL_PAD_SD4_CLK__GPIO7_IO10        0x1b0b0
         MX6QDL_PAD_EIM_D20__GPIO3_IO20    0x1b0b0
         MX6QDL_PAD_SD4_CMD__GPIO7_IO09        0x1b0b0
         MX6QDL_PAD_SD1_DAT2__GPIO1_IO19    0x1b0b0
         MX6QDL_PAD_EIM_D19__GPIO3_IO19    0x1b0b0
         MX6QDL_PAD_EIM_D23__GPIO3_IO23    0x1b0b0
         MX6QDL_PAD_NANDF_D7__GPIO2_IO07    0x1b0b0
         MX6QDL_PAD_SD1_DAT1__GPIO1_IO17    0x1b0b0
         MX6QDL_PAD_SD1_CLK__GPIO1_IO20        0x1b0b0
         MX6QDL_PAD_EIM_D25__GPIO3_IO25    0x1b0b0
         >;
       };
    };
  };
};

Also, this is the debug output when booting, if it helps:

Commercial temperature grade DDR3 timings, 32bit bus width.
Trying to boot from MMC1


U-Boot 2019.07-4.0.0-dev-20191211+build.36+g03cac0835c (Jan 01 1970 - 00:00:00 +0000)

CPU:   Freescale i.MX6SOLO rev1.4 996 MHz (running at 792 MHz)
CPU:   Commercial temperature grade (0C to 95C) at 40C
Reset cause: POR
DRAM:  256 MiB
PMIC:  device id: 0x10, revision id: 0x21, programmed
MMC:   FSL_SDHC: 1, FSL_SDHC: 0
Loading Environment from MMC... OK
In:    serial
Out:   serial
Err:   serial
Model: Toradex Colibri iMX6 Solo 256MB V1.1A, Serial# 10633043
Net:   using PHY at 0
FEC [PRIME]
Hit any key to stop autoboot:  0 
switch to partitions #0, OK
mmc0(part 0) is current device
Scanning mmc 0:1...
Found U-Boot script /boot.scr
2427 bytes read in 13 ms (181.6 KiB/s)
## Executing script at 17000000
445 bytes read in 18 ms (23.4 KiB/s)
59776 bytes read in 26 ms (2.2 MiB/s)
34 bytes read in 11 ms (2.9 KiB/s)
Applying Overlay: enable_pins.dts.dtbo
1614 bytes read in 13 ms (121.1 KiB/s)
8000000 bytes read in 228 ms (33.5 MiB/s)
3255570 bytes read in 108 ms (28.7 MiB/s)
## Flattened Device Tree blob at 12100000
   Booting using the fdt blob at 0x12100000
   Using Device Tree in place at 12100000, end 12131fff

Starting kernel ...

Multiple things here first of all most importantly I was able to recreate your issue on my end it seems the cause is disabling the uart1 interface. When I remove all uart1 related information from your overlay it then works and the system boots.

I’m still looking into why it does this as this is unintended behavior in my opinion as uart1 is just our default serial debugging interface. Meaning that your boot log is normal as it should cut off there since you just disabled the serial interface in the kernel. However at least on my end I can see from a connected display that the system never fully boots.

Some other points though, your syntax is slightly off. When your disabling interfaces you want to disable the interface itself not the pinmux group. Meaning you’d want to disable uart1 itself not the pinmux groups that are attached to uart1 (you got this right by disabling pwm2). Also in device tree land the syntax is disabled for off and okay for on (yes I realize enabled makes more sense).

I’ll comment further when I figure out why disabling uart1 causes boot issues.

Best Regards,
Jeremias

Thank you for your hard work!

I’ll be awaiting further developments!

Kind regards,
MGlolenstine

Hi @MGlolenstine,

Just wanted to report back that the issue with uart1 in Torizon has been resolved. You can access the latest builds with this fix using the CI/CD feeds via Easy Installer. Though this fix will also be a part of our quarterly release at the end of the month.

Best Regards,
Jeremias

Thanks for the follow-up!

I’ll test it out right now!

After installing the latest Torizon and applying the same script, it compiles fine and it also boots fine.

But there’s a side effect. I knew that the uart1 will not be accessible, but whay doesn’t /dev/console work anymore? I can’t access Docker anymore as I’m getting the following error

~$ docker run -it --privileged -v /dev:/dev -v /boot:/boot torizon/arm32v7-debian-dev-tools
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "process_linux.go:430: container init caused \"open /dev/console: no such device\"": unknown.

And also, a question… How can I apply built .dtbo to a normal linux image?

Thanks for the update and error log, we are looking into this.

As for your question, our overlay container uses U-Boot to apply overlays at boot time. The exact process is details in this U-Boot documentation: https://github.com/u-boot/u-boot/blob/master/doc/README.fdt-overlays

Best Regards,
Jeremias