Device tree customization for a custom carrier board

Hi all,

I have a question about device tree customization for a custom carrier board.

Configuration:

  • Module: Colibri IMX7D 1GB
  • Base image: torizon-core-docker-colibri-imx7-emmc-Tezi_5.6.0+build.13

This is what I have done (using the aster carrier board board as a base since our board is not too far off that one).

  1. copied “imx7-colibri-emmc-aster.dts” and called it “imx7-colibri-emmc-interferometer.dts”

  2. copied “imx7-colibri-aster.dtsi” and called it “imx7-colibri-interferometer.dtsi”
    The torizoncore-builder will take the new .dts file as a start for building my image

  3. In these two “interferometer” files, I disabled UART B (uart2), GPIO bank 2 and ECSPI3 since they will be used by the M4 core.
    The UARTs and SPI were simply done by setting their status to “disabled” in the .dts file. “disabling” GPIO bank 2 is done by removing “&pinctrl_gpio2” in the “&iomuxc” definition in the .dtsi file.

=> first question, is this enough to let Linux forget about these three “devices” ?

On our carrier board, I also need to reconfigure the handshake lines of UART A (uart1) into basic GPIO lines.

In order to de-associate the handshake lines from uart1, I modified imx7-colibri.dtsi (27.0 KB) which defines &uart1. The line that defines pinctrl-0 is modified and the line “UART-has-rtscts;” is removed as well. (you can easily find my modifications by searching for //@@)

Building a new image works but when I try to control GPIO6.IO[19] (SODIMM pin 25, formerly “uart1.CTS_B”) via the console, I do not see any change on the pin (Linux pin number (6 - 1) * 32 + 19 = 179) :

echo 179 > /sys/class/gpio/export
echo “out” > /sys/class/gpio/gpio179/direction
echo 0 > /sys/class/gpio/gpio179/value
echo 1 > /sys/class/gpio/gpio179/value

Same with GPIO6.IO[20] (SODIMM pin 27, formerly “uart1.RTS_B”)…

My questions are:

=> Is modifying "imx7-colibri.dtsi"the right way to go or shall I redefine the &uart1 structure in my top “interferometer.dtsi” file ?
=> What else must I modify (and where) in order to be able to use the handshake pins as GPIO ?

Your help is very much appreciated, as ever !

Jeroen

Hi @ompie ,

first question, is this enough to let Linux forget about these three “devices” ?

It depends on what you consider as forgotten. The disabled devices won’t work or be usable by Linux/TorizonCore, but their respective drivers will still be loaded if they were compiled as part of the kernel.

Is modifying “imx7-colibri.dtsi” the right way to go or shall I redefine the &uart1 structure in my top “interferometer.dtsi” file ?

You can do everything in the new interferometer.dtsi for better organization, but both approaches should work without problems.

What else must I modify (and where) in order to be able to use the handshake pins as GPIO ?

I took a look at your imx7-colibri.dtsi file and the modifications make sense to what you’re trying to do. The only thing left to do is put the handshake pins in a pinctrl node referenced in pinctrl-0 inside iomuxc. For instance, create a new pinctrl node similar to this:

	pinctrl_gpio6: gpio6-grp {
		fsl,pins = <
			MX7D_PAD_SAI2_TX_BCLK__GPIO6_IO20 	0x14 /* SODIMM 27 */
			MX7D_PAD_SAI2_TX_SYNC__GPIO6_IO19	0x14 /* SODIMM 25 */
		>;
	};

And add it to pinctrl-0 in iomuxc:

[...]
&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio3 &pinctrl_gpio4 &pinctrl_gpio6>;

	pinctrl_gpio6: gpio6-grp {
		fsl,pins = <
			MX7D_PAD_SAI2_TX_BCLK__GPIO6_IO20 	0x14 /* SODIMM 27 */
			MX7D_PAD_SAI2_TX_SYNC__GPIO6_IO19	0x14 /* SODIMM 25 */
		>;
	};

	pinctrl_atmel_adapter: atmelconnectorgrp { /* ATMEL MXT TOUCH ADAPTER */
		fsl,pins = <
			MX7D_PAD_GPIO1_IO09__GPIO1_IO9		0x74 /* SODIMM 28, INT */
			MX7D_PAD_GPIO1_IO10__GPIO1_IO10		0x14 /* SODIMM 30, RST */
		>;
	};

[...]

Pin groups assigned in iomuxc node’s pinctrl-0 make the pins available to userspace, which then can be used as GPIO.

You can change the name of the pinctrl node or add new pins to it if necessary.

Try doing the above and see if that helps you.

Best regards,
Lucas Akira

Thanks Lucas !

That did the job, so I can now control the relevant pins and some more that I did not mention. However, there is one pin that does not seem to work:

SODIMM pin 100
I would like to configure it as GPIO5.IO[16] while the Colibri i.MX7 data sheet defines it as Keypad_Out<1>.
I’ve been searching for ‘key’ and ‘MX7D_PAD_SD2_DATA2__GPIO5_IO16’ in the dts files but I can’t find any line that does something with this particular pin.
Trying to control it via the /sys/class/gpio interface (using I/O number 144) did not give any results.

=> Any idea why this isn’t working ?

My changes are all in these two files which form the starting point of my device tree :
imx7-colibri-interferometer.dtsi (4.5 KB)
imx7d-colibri-emmc-interferometer.dts (1.5 KB)

=> I’m also wondering how to define default/startup values for output pins (e.g. the Laser activation pin must remain ‘0’) ?

I plan using the ECSPI1 interface as a master for the SPI bus (SCK, MISO and MOSI. Pin SS can be ignored) with four chip selects.

In imx7-colibri-interferometer.dts, I added:

//-- SPI interface that controls the DDS, temperature DAC, offset current DAC and the PGAs
&ecspi1 {
    fsl,spi-num-chipselects = <4>;
    cs-gpios = <
        &gpio1 15 GPIO_ACTIVE_HIGH        // nTEMP_CS
        &gpio3 24 GPIO_ACTIVE_HIGH        // nDDS_CS
        &gpio3 25 GPIO_ACTIVE_HIGH        // nIOFFSET_CS
        &gpio3 27 GPIO_ACTIVE_HIGH        // nPGA_CS
    >;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1_cs>;
    status = "okay";

    spidev0: spidev@0 {
        compatible = "toradex,evalspi";
        reg = <0>;
        spi-max-frequency = <23000000>;
    };

    spidev1: spidev@1 {
        compatible = "toradex,evalspi";
        reg = <1>;
        spi-max-frequency = <23000000>;
    };
    
    spidev2: spidev@2 {
        compatible = "toradex,evalspi";
        reg = <2>;
        spi-max-frequency = <23000000>;
    };

    spidev3: spidev@3 {
        compatible = "toradex,evalspi";
        reg = <3>;
        spi-max-frequency = <23000000>;
    };
};

I also added the following lines to the iomuxc node:

//--- SPI1 chip selects
    pinctrl_ecspi1_cs: ecspi1-cs-grp {
        fsl,pins = <
            MX7D_PAD_GPIO1_IO15__GPIO1_IO15        0x14 /* SODIMM 178, nTEMP_CS    */
            MX7D_PAD_LCD_DATA19__GPIO3_IO24        0x14 /* SODIMM 138, nDDS_CS     */
            MX7D_PAD_LCD_DATA20__GPIO3_IO25        0x14 /* SODIMM 140, nIOFFSET_CS */
            MX7D_PAD_LCD_DATA22__GPIO3_IO27        0x14 /* SODIMM 144, nPGA_CS     */
        >;
    };

    //--- SPI1 clock/data interface
    pinctrl_ecspi1: ecspi1-grp {
        fsl,pins = <
            MX7D_PAD_ECSPI1_MISO__ECSPI1_MISO    0x2  /* SODIMM 79,  CTRL_MISO */
            MX7D_PAD_ECSPI1_MOSI__ECSPI1_MOSI    0x2  /* SODIMM 103, CTRL_MOSI */
            MX7D_PAD_ECSPI1_SCLK__ECSPI1_SCLK    0x2  /* SODIMM 101, CTRL_SCK  */ 
        >;
    };

I’m not yet able to test/use the SPI (I’m still setting up the Docker development environment and I also have to look into the exact way how to access SPI from C) but can you confirm that this is the way to define in the device tree?

=> Especially the definitions of the “spidev” sub nodes. Are the numbers OK?

=> I suppose the order of the chip select pins in both the “cs-gpios” and “pinctrl_ecspi1_cs” part determine which SPI “device” uses which CS ?

=> Is there a way to check (under /dev or /proc/device-tree for instance) that the SPI devices are at least recognized ?

I also would like to use two timers:

Timer GPT1 (mainly to divide an input frequency and put it on an output):

  • SODIMM pin 93 as GPT1.COMPARE1
  • SODIMM pin 60 as GPT1.CLK

Timer GPT4

  • SODIMM 23 as GPT4.CAPTURE_2

For now, I don’t have any clue on how to define them in the device tree or how to use them from C/C++.
=> Could you give me any hints please ?

In advance, many thanks for your valuable help !

Jeroen

Hi @ompie ,

Any idea why this isn’t working ?

I think I have a clue: looking through your dtsi file I see you put SODIMM 100 in pinctrl_gpio5 and this group is added in iomuxc. The problem is that the same pin is already in pinctrl_gpio1 which is also in iomuxc. (See here: imx7-colibri.dtsi « dts « boot « arm « arch - linux-toradex.git - Linux kernel for Apalis and Colibri modules)

So you got duplicate pin declarations, and I suspect this is the cause of your issue. Keep in mind that this also happens with other pins, not just SODIMM 100.

I’m also wondering how to define default/startup values for output pins (e.g. the Laser activation pin must remain ‘0’) ?

I will consult internally about this question and I’ll update you on that.

=> Especially the definitions of the “spidev” sub nodes. Are the numbers OK?

They seem to be OK, considering this topic Apalis iMX8 SPI multiple chip select has a similar syntax.

=> I suppose the order of the chip select pins in both the “cs-gpios” and “pinctrl_ecspi1_cs” part determine which SPI “device” uses which CS ?

From this document: spi-controller.yaml « spi « bindings « devicetree « Documentation - linux-toradex.git - Linux kernel for Apalis and Colibri modules it does seem to be the case, yes.

=> Is there a way to check (under /dev or /proc/device-tree for instance) that the SPI devices are at least recognized ?

The SPI devices should be in /dev. You can search with:

ls -l /dev/colibri-spi*

These articles about SPI in general on our modules might be useful:

Best regards,
Lucas Akira

Hi Lucas,

SODIMM 100
Removing the pin from pinctrl_gpio1 in imx7-colibri.dts did work. It’s a kind of mystery since SODIMM 186 is also part of the same two definitions and that one already worked.
=> A bit later, I got some strange behavior after other modifications and I reverted to yesterday’s version of the device tree. For some unexplained reasons, SODIMM 100 now works as well even without removing it from pinctrl_gpio1. This is more consistent with what I see for the other pins so I suppose I did wrong something else yesterday…

Just as a general remark that Toradex may take into account in future device trees: it is very confusing that there are nodes called pinctrl_gpio, pinctrl_gpio2, etc that DO NOT correspond to the module’s GPIO banks.

SPI device
There’s no spi under /dev/colibri-spi* :frowning:
I re-enabled the default ecspi3 and that one shows up. After more fiddling (I removed e.g. the pins used by ecspi1 from other iomuxc groups in `imx7-colibri.dtsi) I still did not see more than two spi devices (corresponding to the two chip selects of ecspi3).

After a while I got the good idea to also list /dev/*spi*. And now the ecspi1 shows up four times (I defined 4 chip selects) :

torizon@colibri-imx7-emmc-07209920:~$ ls -l /dev/*spi*
lrwxrwxrwx 1 root root        9 Aug 26 09:50 /dev/colibri-spi-cs0 -> spidev2.0
lrwxrwxrwx 1 root root        9 Aug 26 09:50 /dev/colibri-spi-cs1 -> spidev2.1
crw-rw-r-- 1 root spidev 153, 0 Aug 26 09:50 /dev/spidev0.0
crw-rw-r-- 1 root spidev 153, 1 Aug 26 09:50 /dev/spidev0.1
crw-rw-r-- 1 root spidev 153, 2 Aug 26 09:50 /dev/spidev0.2
crw-rw-r-- 1 root spidev 153, 3 Aug 26 09:50 /dev/spidev0.3
crw-rw-r-- 1 root spidev 153, 4 Aug 26 09:50 /dev/spidev2.0
crw-rw-r-- 1 root spidev 153, 5 Aug 26 09:50 /dev/spidev2.1

So everything seems okay so far. But there is apparently some other setting that creates the links to the /dev/colibri* names…
I don’t care about these links so for now, the issue is closed.

.

Concerning my questions about the general purpose timers, you probably forgot about them. I will opena separate thread for that one. It’ll also more useful for other people to find it as a separate thread…

And thanks for the links you provided. I had found some of them myself but not all of them. You guys really have a lot of documentation, but it’s not always easy to find exactly what you need.

Jeroen

Hi @ompie ,

Glad you managed to solve some of your questions.

Concerning my questions about the general purpose timers, you probably forgot about them.

Yes, I didn’t notice I skipped them, sorry for that! It looks like you’ve already created a new thread for them.

About your question on defining startup values for output pins, it depends on how early you need to set them: U-boot is probably the earliest stage in which you can do it.

This thread has a more general explanation on how the pins are initialized (the links referenced there are probably outdated though): Gpio state during boot sequence - #3 by max.tx

This thread details a possible approach on changing U-boot code to alter GPIO values: IOMUX GPIO configuration

Best regards,
Lucas Akira

Hi Lucas,
Thanks for the links. I’ll give it a try as soon as I’ve got some time for it.

Jeroen