Search by Tags

Pin Multiplexing - Changing Pin Functionalities in the Linux Device Tree

 

Article updated at 13 Jul 2020
Subscribe for this article updates

Introduction

To improve design flexibility, the NXP's i.MX SoCs family provides pin muxing capability. This feature allows developers to select among multiple functions for the device's IO pins. These pins have a default (ALT0) function and may have other functionalities (ALT1, ALT2, ALT3, etc.).

Toradex provides the Pinout Designer tool. Among other features, with this software you can verify in a simple and easy-to-use graphical interface the default function for each module's pins. You can also check which pins are available for a specific function so that you can determine the best allocation of pins for your design.

In Linux, to modify the default status of the pin muxing configuration, it is necessary to alter the Device Tree. However, in Torizon you can use the Device Tree Overlays article approach in order to change this without the need of external cross-compilation. This process comprises writing a dts file, building the overlay, and enabling it directly in the module. Make sure to read the related documentation to get a better idea.

In this article, we will explore how to create a dts file to change the pin muxing configuration.

This article complies to the Typographic Conventions for Torizon Documentation

Prerequisites

Creating the DTS

Introduction

Before we start modifying the software we need to plan the function for each module's pin we plan to use.

As explained earlier, Pinout Designer tool is a handy tool to understand the default pins function (ALT0) allocation before modifying it.

Note: Tip: On the Pinout Designer tool, you can select View->Pin Filter->Configure Pin Filter to visualize only the functions of a specific pin.

And of course, another important source of information about the pin function multiplexing for a specific SOM is the Toradex module's datasheet.

The dts file to set the pin muxing will target the IOMUX Controller (IOMUXC) for i.MX. You can find the documentation and device tree binding for the IOMUX controller on the documentation files in the Linux Kernel source-code. Please, be sure to check the documentation for the corresponding kernel version of your SoM.

Here we show the base template for an overlay to change the default pin muxing:

/dts-v1/;
    /plugin/;

    // A) Header file with pin definitions
    #include <soc-pinfunc.h>

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

                // B) GPIO pinctrl node
                pinctrl-0 = <&pinctrl_my_gpios>;
                pinctrl_my_pins: my_muxgrp {

                   fsl,pins = <
                        PIN_NAME   BIT_CONFIG // C) PINS
                    >;

                };
            };
        };
    };

Note: To simplify the comprehension, in this article we divided this example dts file into the following three sections: A, B, and C.

A) Pin Definitions Header File

Each SoC has it's own pin definitions file. These files are present on the Developer Tools Container, which is the tool to build the Device Tree Overlays. These are the definition files for each SoC:

SoM Header file
Apalis iMX8 </device-tree-overlays/include/dt-bindings/pinctrl/pads-imx8qm.h>
Apalis/Colibri iMX8X </device-tree-overlays/include/dt-bindings/pinctrl/pads-imx8qxp.h>
Apalis/Colibri iMX6 </device-tree-overlays/dts-arm32/imx6q-pinfunc.h>
Colibri iMX7 1GB </device-tree-overlays/dts-arm32/imx7d-pinfunc.h>

This file lists each pin with all of its possible muxing options. It contains definitions in a pattern comprising the ball name prefix and the muxing option suffix.

As an example, MX6QDL_PAD_SD2_DAT1__SD2_DATA1, comprises:

  • The ball name: MX6QDL_PAD_SD2_DAT1
  • The pin mux option: SD2_DATA1

B) Pin Control Node

Here we have the actual pin control node that will add the chosen pins as GPIOs. In our example, we decided to call the node my_muxgrp and label it as pinctrl_my_pins. You don't need to use the same names though. These are arbitrary names, and you can choose any name accordingly with your preference.

C) Adding the Pins

Finally, we come to the pin functions declaration themselves. Here you can add multiple pins.

The PIN_NAME field should be in the format <name prefix>_<muxing option suffix> as explained earlier, that will directly reference the pin definition .h file, so make sure that it is exactly the same.

The BIT_CONFIG is a hexadecimal value to set the Pad Control register of the SoC. See the SoC Reference Manual and also the Device Tree Customization article for more information.

Example: Creating a dts File to Set the GPIO Functionality to a Pin

Suppose we want to change the pin 11 and 13 of the MXM3 connector of the Apalis iMX8 for GPIO function.

By looking to the SoC Functions List chapter on the datasheet, we see the following table:


  • Pin Multiplexing information on CoM's Datasheet

    Pin Multiplexing information on CoM's Datasheet

The corresponding SoC balls' names are: FLEXCAN2_RX and FLEXCAN2_TX.

First, make sure to run the Torizon Developer Tools container.

Once inside the container, we can make sure that these pins are not already in use by some other peripheral in the device tree. In this case, the most important file to take a look is the fsl-imx8qm-apalis.dtsi:

## cat /device-tree-overlays/dts-arm64/fsl-imx8qm-apalis.dtsi | grep FLEXCAN2_RX

Other files from the device tree may have code activating this pin for different functionality, so it's better to take a look at all the dts and dtsi corresponding to your setup.

Note: The device tree that is loaded is set at boot time via u-boot variable fdt_file. Note: Protip: You can use the command grep to check all the files at the same time.

In our case, we didn't find any peripheral using the FLEXCAN2_RX and FLEXCAN2_TX pin.

The next step is to find the pin functionality definition macro. Looking to the pin definition file inside the Developer Tools container, we can see the FLEXCAN2_RX pin:

## cat /device-tree-overlays/include/dt-bindings/pinctrl/pads-imx8qm.h | grep FLEXCAN2_RX
#define SC_P_FLEXCAN2_RX 150 /* DMA.FLEXCAN2.RX, LSIO.GPIO4.IO01 */
#define SC_P_FLEXCAN2_RX_DMA_FLEXCAN2_RX SC_P_FLEXCAN2_RX 0
#define SC_P_FLEXCAN2_RX_LSIO_GPIO4_IO01 SC_P_FLEXCAN2_RX 3

The corresponding pin definition macro for the GPIO for FLEXCAN2_RX and FLEXCAN2_TX functionalities are, respectively:

  • SC_P_FLEXCAN2_RX_LSIO_GPIO4_IO01
  • SC_P_FLEXCAN2_TX_LSIO_GPIO4_IO02

In this case, the bits configuration values were selected according to the registers SW_PAD_CTL of the SoC, as described in the previous sections of this article. In our case, we will set it with the value of 0x41.

With these values, we go forward and write dts file:

/dts-v1/;
    /plugin/;

    #include </device-tree-overlays/include/dt-bindings/pinctrl/pads-imx8qm.h>

    / {
        compatible = "toradex";
        fragment@0 {
            target = <&iomuxc>;
            __overlay__ {
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_my_gpios>;
                pinctrl_my_gpio_example: my_example_grp {
                   fsl,pins = <
                        SC_P_FLEXCAN2_RX_LSIO_GPIO4_IO01    0x41
                        SC_P_FLEXCAN2_TX_LSIO_GPIO4_IO02    0x41
                    >;

                };
            };
        };
    };

Note: You can write this file in your development PC and then transfer it to the Torizon Developer Tools container OR directly write it in the module with vim (also available inside the container).

Building and Enabling the Overlay

To build and enable the overlay defined by the dts file, refer to the Device Tree Overlays article.

Important: Pin Settings Conflicts

It's a common situation when developers are defining a function for a pin, that this unit to be already in use by other peripherals, causing a pin conflict. If this is the case, the interface that is currently using the pin must be disabled.

To check if the pin is already in use, inspect the base device tree files. The .dts and .dtsi that describes the device tree for the board is available inside the Developer Tools Container in the following path:

  • For i.MX6 and i.MX7 SoMs (ARM 32-bits): /device-tree-overlays/dts-arm32/
  • For i.MX8 SoMs (ARM 64-bits): ./device-tree-overlays/dts-arm64/

In TorizonCore, the Developer Tools Container also have the command dtconf status to verify which is the base device tree for your board.

See in the next chapter how to find the correct pin name to look for when inspecting the device tree source files.

If you selected a pin that is already in use, you need to disable the current functionality associated with this pin or select another pin.

Attention: Failure to resolve all pin conflicts can cause the kernel not to boot at all.

Removing a conflicting DTO

In case you find yourself with a non-working kernel (normally, stuck at the "Loading kernel..." message), you can delete your custom overlays easily directly from your PC. You would need to set up a USB-OTG connection with your PC and run the UMS functionality of U-Boot by simply stopping the autoboot at U-boot, and running the following commands:

ums 0 mmc 0

If the connection is properly done, you should see a BOOT partition show up in your PC. Simply delete the conflicting .dtbo and the conflicting line in the overlays.txt file.

Note: Check your carrier board datasheet what ports and jumper configurations work with USB-OTG. In Toradex Carrier Boards, it simply requires using the correct port or a small jumper removal (like Ixora's JP2). Note: You can delete the overlays.txt file if you don't have any DTBO working. TorizonCore will recreate this file when activating a new DTBO.