TorizonCore GPIO initialization using gpiod

I’m working with a Verdin iMX8M Plus on a Verdin development board. I’m working on GPIO initialization, and found your documentation for working with GPIOs using gpiod on TorizonCore.

I’m at the very beginning of this exercise and ran into something peculiar. One of your examples had GPIO initialization:

/* config as output and set a description */
gpiod_line_request_output(output_line, “gpio-test”,
GPIOD_LINE_ACTIVE_STATE_HIGH);

I connected one of the GPIO outputs on X5 on the dev board to one of the user LEDs (LED21) on X38. That worked fine.

Then I changed the third argument to GPIOD_LINE_ACTIVE_STATE_LOW. And the LED still comes on ?!

After poking around, I found out that GPIOD_LINE_ACTIVE_STATE_LOW has numeric value 2. In gpiod.h these two are declared as follows :

/**

  • @brief Possible active state settings.
    */
    enum {
    GPIOD_LINE_ACTIVE_STATE_HIGH = 1,
    /< The active state of a GPIO is active-high. */
    GPIOD_LINE_ACTIVE_STATE_LOW,
    /
    < The active state of a GPIO is active-low. */
    };

The third argument is an integer, and from what I’ve seen I’m assuming 0 is off/low and non-zero is on/high. Passing in a ‘0’ instead of one of the enumerations works fine. Just wondering how something like this made it in? And leery of using any of the gpiod enumerations now.

Greetings @techczech,

Well that old example of ours while it works, does not use GPIOD_LINE_ACTIVE_STATE_HIGH in what I would call the expected/standard way. Both GPIOD_LINE_ACTIVE_STATE_HIGH and GPIOD_LINE_ACTIVE_STATE_LOW are not to be used to set logic level. They’re meant to be used with other libgpiod function to set and return whether a pin is configured for active low or active high, like in this function for example. So the actual value behind these macros is irrelevant since they’re suppose to correspond to the active state of the pin not the actual logic level.

If you see our latest example for pin toggling we don’t use these macros and just pass an integer: torizon-samples/gpio-toggle.c at bullseye · toradex/torizon-samples · GitHub

Best Regards,
Jeremias

A question I think is related. I’m going through GPIOs in the Verdin iMX8M Plus V1.1 datasheet. I’m trying to figure out what default functions are for pins we may use. I’ll use pin 151 as an example. For that pin, the Alt0 function is UART4_RX, the Alt5 function is GPIO5_IO28.

In the table in 3.2 Pin Assignment, about the Verdin Signal Name column, the preface says “This name corresponds to the default usage of the pin.” And the name for 151 is UART_4_RXD. So per that this pin by default is the receive line for UART 4.

In the table in 4.4 SoC Functions List, it has a table with a list of all the alt functions for each GPIO. There’s a column labeled “Default Mode”. For pin 151, the default mode is ALT5. So per that this pin by default is a GPIO.

Two different tables, two different answers. What am I misinterpreting?

It can often be confusing or even misleading to use the datasheet to determine the function of a pin. The datasheet looks at things from a hardware perspective and does not take into account whatever software may be running on the module at any given time.

If you want the source of truth of how a specific pin is configured the device tree is definitive configuration of the pins, at least in Linux.

So for example on TorizonCore 5.7 the Verdin i.MX8M Plus uses the device trees located here: freescale « dts « boot « arm64 « arch - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules

If we parse through these for SODIMM pin 151, we can see that the pin gets configured in 2 places:

# From imx8mp-verdin.dtsi
/* Wifi usage only */
pinctrl_gpio_hog4: gpiohog4grp {
		fsl,pins = <
			MX8MP_IOMUXC_UART4_RXD__GPIO5_IO28		0x1c4	/* SODIMM 151 */
			MX8MP_IOMUXC_UART4_TXD__GPIO5_IO29		0x1c4	/* SODIMM 153 */
		>;
	};
...
...
/* Non-wifi usage only */
pinctrl_uart4: uart4grp {
		fsl,pins = <
			MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX		0x1c4	/* SODIMM 151 */
			MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX		0x1c4	/* SODIMM 153 */
		>;
	};

So it’s either being used as a GPIO or a UART. As seen from the in-code comments we can see that for non-wifi variants it uses the UART configuration and for wifi variants the GPIO one is used.

Basically if you want to know how a particular pin will be configured in Linux, look at what device tree your module is loading up, and trace through the device tree source for the definitive truth. This of course only applies to our Linux-based images and only when the Linux kernel is in control. In the U-Boot bootloader for example a pin may have a different configuration entirely.

Best Regards,
Jeremias

Thanks for the redirect. I’ve read several more articles on your website, installed TorizonCore Builder, and have device tree source via “torizoncore-builder dt checkout”. I’m focusing on the sections of “Pin-Multiplexing…” involving GPIOs, the only thing I anticipate needing to change in the device tree is GPIO pin functions.

Regarding “…look at what device tree your module is loading up…”, in boot up messages I see these two messages that look related to the device tree :

Applying Overlay: verdin-imx8mp_native-hdmi_overlay.dtbo
Applying Overlay: verdin-imx8mp_lt8912_overlay.dtbo

There’s a dtb that is loaded before these two overlays? I don’t see any message about that. I have a Verdin iMX8M Plus with Wifi+BlueTooth, so that’s using device-trees/dts-arm64/imx8mp-verdin/wifi/dev.dts?

I find source for both of those overlays in the device-tree/overlays folder. But neither of those includes any other files. It’s not clear to me from your technical articles either, how do these know about the contents of imx8mp-verdin.dtsi in the dts-arm64 folder? They’re referencing definitions from that, example : lcdif1.

Regarding “…look at what device tree your module is loading up…”, in boot up messages I see these two messages that look related to the device tree

There’s a U-Boot variable fdtfile that controls what device tree gets loaded at boot-time. This is described in detail here: U-Boot | Toradex Developer Center

I have a Verdin iMX8M Plus with Wifi+BlueTooth, so that’s using device-trees/dts-arm64/imx8mp-verdin/wifi/dev.dts?

I believe the WiFi device tree should be the default device tree that gets loaded but this should be confirmed on your device to be sure.

how do these know about the contents of imx8mp-verdin.dtsi in the dts-arm64 folder?

Device tree overlays are applied at run-time on top of the underlying full device tree. A device tree overlay doesn’t need to know anything about the underlying device tree in order to be compiled. However, when the overlay is actually applied the definitions in it better match whatever full device tree is in use, or there will be issues or even system failures.

Best Regards,
Jeremias

I got into U-Boot and see fdtfile=imx8mp-verdin-wifi-dev.dtb. So it’s the one expected.

Next, after going through your responses, I’m walking through all the pins that should be GPIOs per the TorizonCore device tree being used. There are at least two that don’t work as expected. I’m going to use examples again – SODIMM 220 and SODIMM 222. Both look like they should be GPIOs per the device tree, 222 is working but 220 is not.

I’m again on the Verdin development board with a Verdin iMX8M Plus installed, with unmodified Torizon Core. I’m running a docker container we made based on torizon/weston-vivante:2. I’ve made no device tree changes, so using imx8mp-verdin-wifi-dev.dtb and the two overlays mentioned above.

I have simple code to blink LEDs from the GPIOs. I’m connecting SODIMMs on the development board header X5 to LEDs on X38.

I see both defined as GPIOs in imx8mp-verdin.dtsi :

pinctrl_gpio7: gpio7grp {
    fsl,pins = <
        MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03        0x184    /* SODIMM 220 */
    >;
};
pinctrl_gpio8: gpio8grp {
    fsl,pins = <
        MX8MP_IOMUXC_SAI1_RXC__GPIO4_IO01            0x184    /* SODIMM 222 */
    >;
};

In both imx8mp-verdin-nonwifi.dtsi and imx8mp-verdin-wifi.dtsi both pinctrl_gpio7 and pinctrl_gpio8 are in iomuxc pinctrl-0, they don’t appear anyplace else in imx8mp device tree files.

Here’s code I’m using to test these two GPIOs :

gpiod_chip *ChipHandle = gpiod_chip_open_by_number(3);

gpiod_line *LineSODIMM220 = gpiod_chip_get_line(ChipHandle, 3);
gpiod_line *LineSODIMM222 = gpiod_chip_get_line(ChipHandle, 1);

int iStatus220 = gpiod_line_request_output(LineSODIMM220, NULL, 0);
int iStatus222 = gpiod_line_request_output(LineSODIMM222, NULL, 0);
printf("Line open status : %d (220), %d (222)\r\n", iStatus220, iStatus222);

// Blink LEDs
printf("\r\n 5 seconds of LED blinking...\r\n");
for (unsigned int nIndex = 0 ; nIndex < 5 ; nIndex++)
{
    gpiod_line_set_value(LineSODIMM220, 0);
    gpiod_line_set_value(LineSODIMM222, 0);
    GXPTimeSleep(500); // cross platform sleep

    gpiod_line_set_value(LineSODIMM220, 1);
    gpiod_line_set_value(LineSODIMM222, 1);
    GXPTimeSleep(500); // cross platform sleep
}
gpiod_chip_close(ChipHandle);

Both calls to gpiod_chip_get_line return 0 (good). The LED connected to 222 blinks, the LED connected to 220 does not. I’ve swapped the LEDs connected and still get the same result. Any insight into what’s going on would be appreciated.

I did some testing on SODIMM 220, and I found some interesting results.

First of all I agree with your analysis that according to the device tree SODIMM 220 should be configured as a GPIO by default. I took a standard TorizonCore 5.7.0 image and flashed it on my Verdin i.MX8MP. I’m using our standard Verdin Development Carrier Board since it has easy access to the GPIO pins and test LEDs built into the board.

First I tested SODIMM 222 and used an LED to test the output via toggling, this works as you said. I then tried SODIMM 220, at first it seemed like this wasn’t working and the LED wasn’t toggling with the GPIO. I then tried testing this pin as an input by connecting it into either 1.8V or ground and then reading the value from SODIMM 220. This seems to work as the pin was returning 0 and 1 as expected.

At this point the pin seemed to work fine reading input but not as an output to drive an LED. All the other default GPIO pins seem to be able to toggle the LED just fine. I went back to messing with the LED using SODIMM 220, it was then I noticed that the LED was actually on, however it was very dim, barely even on. I had to be in a dark room to even notice it clearly.

In short SODIMM 220 seems to be working but for some reason it’s not driving LEDs at the same strength of the other GPIOs. In fact of the 4 test LEDs on this carrier board only 2 of them barely light while the other 2 don’t light at all when connected to SODIMM 220. So it seems to be on the bare threshold of driving these LEDs as well.

Let me inquire our team about this and see if perhaps I’m missing something or maybe this is a bug of sorts.

Best Regards,
Jeremias

Thanks Jeremias. Per my notes I also saw this on 252.

After consulting with our team, it seems that what makes SODIMM 220 special at least on our Verdin development board, is that it is not pulled down. On the Verdin development board there is a jumper at A13 X6 that connects SODIMM 220 to GPIO_7_CSI. For the SODIMM 220 side to behave normally as a GPIO you need to remove this jumper connection. On my side once I removed this jumper the LED lit normally, as expected.

Per my notes I also saw this on 252.

SODIMM 252 doesn’t seem to be configured as an unused GPIO by default. Are you noting the correct pin here?

Best Regards,
Jeremias

Pin 252 was my mistake. Going through the device tree again I see it’s assigned as GPIO4_IO00 in pinctrl_gpio_keys, but that isn’t used where the other GPIOs are, it’s used as a wake-up.

I verified 220 works on the X38 LEDs when I remove the X6 A13 jumper.

You’ve been a tremendous help again, thanks so much. I think this resolves questions & issues I had regarding GPIOs, so will consider this closed. I may have more questions when we get to doing an overlay.

Glad I could be of assistance!