[FAQ] PROCESSOR-SDK: Getting Started with GPIOs in Linux using the AM62 and AM64 Family Processors

Part Number: PROCESSOR-SDK-AM62X
Other Parts Discussed in Thread: AM62P, AM62L, SK-AM64B, SK-AM62B-P1, SK-AM62-LP, SK-AM62A-LP, SK-AM62P-LP, TMDS62LEVM, SYSCONFIG

Tool/software:

The objective of this FAQ is for someone with a TI EVM to enable using GPIOs in Linux. This guide will walk through how to setup a GPIO in the Linux Device Tree and how to toggle it in user space. This guide will also cover some common questions and issues someone may run into.

This applies to Linux SDK 10.0+ for AM64x, AM62x, AM62A, AM62P, AM62L.

  • Common Documentation Links:

    Datasheets:

    Technical Reference Manual:

    Various TI EVM Schematics:

    Linux SDK Documentation:

  • What pins can I use for GPIOs?

    This information is discussed in each device's respective datasheet under the "Pin Attributes" section.

    Notice from the "Pin Attributes" table that many of these pins are capable to be used many different functions. Before selecting a GPIO to use, make sure that its not conflicting with another pin function to be used.

  • Using a TI Evaluation Module (EVM), what GPIOs can I access?

    TI EVMs have RPI headers that are exposed on the board which includes Main Domain GPIOs and some MCU GPIOs. Refer to the schematic of the TI EVM to see what pins are connected to the RPI header.

    Refer to the common links to see the EVM product pages where the schematics can be found.

    The RPI headers are usually labeled as "User Expansion Connector" and "MCU Header". Here is an example for SK-AM62B-P1:

    Refer to the device's datasheet to see which signals can be used as GPIOs. Some pins are labeled for a different function, but still can be used as GPIOs.

    Use this information to select a GPIO to use and then it can be enabled in the Linux device tree.

  • GPIO(s) were selected to use in Linux, how can the GPIO be enable the in the Linux device tree?

    For generating sample device tree code, refer to the Sysconfig tool: https://dev.ti.com/sysconfig/#/start

    After launching the tool, just select the device and start (keep Software product empty).

    We can use the output of the Sysconfig tool to add to the Linux device tree. Just select which GPIOs to use and download the .dtsi output on the right hand side.

    Here is a very simple example for enabling a few GPIOs and MCU GPIOs in the Linux device tree for AM62x:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi
    index b1980b85c..6a34c9eeb 100644
    --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi
    +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi
    @@ -186,6 +186,20 @@ AM62X_IOPAD(0x1cc, PIN_OUTPUT, 0) /* (E14/E11) UART0_TXD */
    >;
    };
    + main_gpio0_pins_default: main-gpio0-default-pins {
    + pinctrl-single,pins = <
    + AM62X_IOPAD(0x009c, PIN_INPUT, 7) /* (V25) GPMC0_WAIT1.GPIO0_38 */
    + AM62X_IOPAD(0x00ac, PIN_INPUT, 7) /* (L21) GPMC0_CSn1.GPIO0_42 */
    + >;
    + };
    +
    + main_gpio1_pins_default: main-gpio1-default-pins {
    + pinctrl-single,pins = <
    + AM62X_IOPAD(0x01b4, PIN_INPUT, 7) /* (A13) SPI0_CS0.GPIO1_15 */
    + AM62X_IOPAD(0x01d0, PIN_INPUT, 7) /* (A15) UART0_CTSn.GPIO1_22 */
    + >;
    + };
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    For the device tree, there were two changes made:  setting the Pin Mux under &main_pmx0/&mcu_pmx0 and the reference node (&main_gpio0/&main_gpio1/&mcu_gpio0). Its generally recomended to add names to GPIOs for debugging purposes.

    If you are not using AM62x, refer to the pin control bindings to see which one applies to your device: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/blame/arch/arm64/boot/dts/ti/k3-pinctrl.h?h=ti-linux-6.12.y

  • The device tree is configured, how can I compile into .dtb?

    Refer back to the common links to the Linux SDK documentation. Follow the instructions to compiling the device tree source into .dtb.

  • After Linux has booted, how to control the GPIO in userspace?

    After the device tree is configured, compiled and loaded, the next step is to control the GPIO in userspace after the Linux kernel has booted. In userspace, we can use the GPIO SYSFS (deprecated) or the libgpiod command set. Important to note that you should only use one of these userspace methods, not both at the same time.

    Libgpiod

    In later Linux SDK versions, its recommended to use Libgpiod userspace commands. This tool set and API are not written by TI so please refer to the Github repo: https://github.com/brgl/libgpiod

    In the default Linux SDK, this is enabled, but refer to the menuconfig entry if needed:

    As seen in the sample device tree, its recommended to add 'gpio-line-names' parameter in the device tree because it makes calling the GPIO in userspace easier. See below for an example of enabling GPIO0_38:

    Fullscreen
    1
    2
    root@am62xx-evm:~# gpioset TEST_GPIO0_38=1 #use ctrl + c to send an interrupt to end the command
    root@am62xx-evm:~# gpioset -z TEST_GPIO0_38=1 #add the -z flag to daemonize the command
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Just be aware when daemonizing the GPIO command, trying to change the GPIO again will return a 'Device or resource busy error' so kill the PID of the existing command.

    In case a GPIO doesn't have a name, follow this process for GPIO0_38:

    Fullscreen
    1
    2
    3
    4
    5
    6
    root@am62xx-evm:~# gpiodetect #run gpiodetect to understand how gpio modules are assigned to chips
    gpiochip0 [600000.gpio] (92 lines)
    gpiochip1 [601000.gpio] (52 lines)
    gpiochip2 [1-0022] (24 lines)
    root@am62xx-evm:~# gpioset --unquoted -c 0 38=1 #use ctrl + c to send an interrupt to end the command, unquoted will not search for gpio line names.
    root@am62xx-evm:~# gpioset --unquoted -z -c 0 38=1 #add the -z flag to daemonize the command
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    For the most up to date commands, refer to the man page for the GPIO command or use the --help flag.

    For an example of using the libgpiod commands in Linux SDK versions 9.0 and prior, refer to this FAQ: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1260373/faq-transitioning-the-gpio-userspace-interface-from-sysfs-to-chardev

    GPIO SYSFS

    GPIO SYSFS has been deprecated as noted in the Documentation: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/Documentation/admin-guide/gpio/sysfs.rst?h=ti-linux-6.6.y

    In the case that it needs to be re-enabled, refer to Kernel config below: 

    Once the kernel config is updated, refer to the Linux documentation for compiling a Kernel Image.

    For this example, GPIO0_38 will be enabled. GPIO0's memory mapped address is 0x600000.

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    root@am62xx-evm:~# cd /sys/class/gpio/
    root@am62xx-evm:/sys/class/gpio# ls -l
    total 0
    --w------- 1 root root 4096 Feb 24 04:51 export
    lrwxrwxrwx 1 root root 0 Feb 24 04:51 gpiochip287 -> ../../devices/platform/bus@f0000/20010000.i2c/i2c-1/1-0022/gpio/gpiochip287
    lrwxrwxrwx 1 root root 0 Feb 24 04:51 gpiochip311 -> ../../devices/platform/bus@f0000/601000.gpio/gpio/gpiochip311
    lrwxrwxrwx 1 root root 0 Feb 24 04:51 gpiochip399 -> ../../devices/platform/bus@f0000/600000.gpio/gpio/gpiochip399 #Use for GPIO0
    lrwxrwxrwx 1 root root 0 Feb 24 04:51 gpiochip486 -> ../../devices/platform/bus@f0000/bus@f0000:bus@4000000/4201000.gpio/gpio/gpiochip486
    lrwxrwxrwx 1 root root 0 Feb 24 04:51 gpiochip510 -> ../../devices/platform/bus@f0000/3b000000.memory-controller/gpio/gpiochip510
    --w------- 1 root root 4096 Feb 24 04:51 unexport
    root@am62xx-evm:/sys/class/gpio# echo 437 > export #GPIO0=399 + pin 38 = 437
    root@am62xx-evm:/sys/class/gpio# cd gpio437
    root@am62xx-evm:/sys/class/gpio/gpio437# echo out > direction
    root@am62xx-evm:/sys/class/gpio/gpio437# echo 1 > value
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • Using a GPIO in Linux isn't working, what are some debugging steps?

    First lets start with checking the setup from the Linux SDK:

    • Make sure the device tree have the Pin Mux and Reference node. See the sample device tree above as an example.
    • Confirm that the pad used for the GPIO is not being used by another module.
    • Check if compiling the device tree into DTB did not return any warnings or errors.
    • Check if the required kernel configs are enabled in the Linux Image and modules.
    • Make sure the correct DTB file and Linux Image is being used to boot the device.

    Next check while Linux is booting:

    • When Linux is booting, check the boot logs in case there were any errors, warnings, or deferred probing.
      • If the device is deferred, look into the cause and try to remove the dependency. 

    After Linux has booted, check the following: 

    • 'cat /sys/kernel/debug/devices_deferred' can be checked for which devices were deferred during probing.
    • 'cat /sys/kernel/debug/gpio' will populate will all the GPIO names listed in the device tree.
    • 'gpioinfo' will also populate with all the GPIO names listed in the device tree.
    • 'gpiodetect' will populate the list of GPIO modules. Make sure the addresses listed make sense and match what the TRM's Memory mapped registers list.
    • Use 'devmem2 0x<PADCONFIG Address>' to check the PADCONFIG register to see if the input and output buffers are enabled. Refer to the 'Pin Attributes' table in the datasheet to find the address. Then refer to the TRM's PADCONFIG register section to understand what the hex output means.
    • Check the GPIO Register values. Refer to the TRM's section on the GPIO peripheral and GPIO registers.
  • Common Questions

    This next section is to discuss some commonly asked questions.

  • What is the difference between GPIO0, GPIO1, and MCU_GPIO0?

    Each SoC is partitioned into different device domains where each device domain is tied to SoC's core and is integrated with a certain list of peripherals. For more information about device domains, refer to each device's technical reference manual (TRM).

    Main Domain will have two GPIO modules name GPIO0 and GPIO1 & MCU Domain will have one GPIO module name MCU_GPIO0. Each of these GPIOs in different device domains function the same. They differ in the number of GPIOs each modules may have.

    To determine the number of consecutive GPIOs each peripheral has, refer to the device tree GPIO's 'ti,ngpio' parameter. This can be found in '<Linux SDK Install Path>/board-support/ti-linux-kernel-<version>/arch/arm64/boot/dts/ti/k3-<device>-<main/mcu>.dtsi'

    For example, see the following for AM62x:

    Notice for AM62x that the 'ti,ngpio' parameter value: Main Domain's GPIO0 = 92, Main Domain's GPIO1 = 52, and MCU Domain's MCU_GPIO0 =24.

    For more information about 'ti,ngpio', refer to the Linux device tree documentation: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/Documentation/devicetree/bindings/gpio/gpio-davinci.yaml?h=ti-linux-6.6.y#n53

    Note for AM62L, the GPIO modules are GPIO0 and GPIO2.

  • Can I access a MCU GPIO from the A53 core?

    Generally speaking, different peripherals can be accessed from different cores/device domains including GPIOs.

    Yes, the A53 cores running Linux will be able to access MCU GPIO. Refer to this E2E FAQ for an example: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1398198/faq-am62x-how-to-allocate-use-gpios-from-different-device-domains

    Important to note, when a MCU peripheral is claimed by Linux, the MCU application will not be able to access the same GPIO. Refer to the Multicore Academy for more information:

  • What does the 'IOPAD' do?

    The first field is the PADCONFIG register address offset which is the last 3 hex bits defined in the device's TRM and datasheet. This tells Linux which pin these settings apply to.

    The second field controls the input/output buffer which will be discussed in the next section. This does not define if a GPIO is input/output direction.

    The third field is the Mux Mode of the pad. Typically, GPIOs use Mux Mode 7 but refer to the device's datasheet for complete information.

    How does IOPAD relate to the PADCONFIG register? What does PIN_INPUT and PIN_OUTPUT  mean in the pinmux section in the device tree?

    At a hardware level, for each pad on the SoC, there is a PADCONFIG register to control the settings of the Pad. See Pad Configuration Registers Section in the device's TRM for more information.

    Each Pad as a Transceiver (Bit21) and Receiver (Bit18) buffer like the diagram below. By using the independent enable signals on each buffer, we can allow the pad to receive and/or transmit. These buffers allow the capability to receive and transmit data. This is true for most pads on the SoC, but refer to the datasheet for complete information.

    /resized-image/__size/320x240/__key/communityserver-discussions-components-files/791/pastedimage1730308931861v1.png

    So how does Linux configure the hardware? Refer to k3-pinctrl.h which defines the pin control bindings: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/arch/arm64/boot/dts/ti/k3-pinctrl.h?h=ti-linux-6.6.y

    The definitions are the exact same as the PADCONFIG registers bit fields seen in the TRM Section named 'Pad Configuration Registers'. Linux will use PIN_INPUT/PIN_OUTPUT and any other parameters to configure the pin when Linux is booting.

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #define PULLUDEN_SHIFT (16)
    #define PULLTYPESEL_SHIFT (17)
    #define RXACTIVE_SHIFT (18)
    #define DEBOUNCE_SHIFT (11)
    #define WKUP_EN_SHIFT (29)
    #define PULL_DISABLE (1 << PULLUDEN_SHIFT)
    #define PULL_ENABLE (0 << PULLUDEN_SHIFT)
    #define PULL_UP (1 << PULLTYPESEL_SHIFT | PULL_ENABLE)
    #define PULL_DOWN (0 << PULLTYPESEL_SHIFT | PULL_ENABLE)
    #define INPUT_EN (1 << RXACTIVE_SHIFT)
    #define INPUT_DISABLE (0 << RXACTIVE_SHIFT)
    /* Only these macros are expected be used directly in device tree files */
    #define PIN_OUTPUT (INPUT_DISABLE | PULL_DISABLE)
    #define PIN_OUTPUT_PULLUP (INPUT_DISABLE | PULL_UP)
    #define PIN_OUTPUT_PULLDOWN (INPUT_DISABLE | PULL_DOWN)
    #define PIN_INPUT (INPUT_EN | PULL_DISABLE)
    #define PIN_INPUT_PULLUP (INPUT_EN | PULL_UP)
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Notice the following:

    • INPUT is only influenced by RXACTIVE (Bit 18 from PADCONFIG)
    • OUTPUT is not influenced by TX_DIS (Bit 21 from PADCONFIG), only RXACTIVE

    This means in the device tree, PIN_INPUT means both the input buffer and the output buffer is enabled. PIN_OUTPUT means only the output buffer is enabled and input buffer is disabled. Remember, enabling the buffers allow for the functionality to receive and transmit on the pad.

    This also means that configuring the PIN_INPUT/PIN_OUTPUT does not impact the GPIO state.

  • The GPIO commands used to work in a old SDK, but not in the new one. What is the issue?

    GPIO SYSFS has been deprecated so its possible that it was removed from the kernel config. It can be re-enabled in the kernel config as seen in the GPIO Userspace section.

    Libgpiod is a tool set and API that is not written by TI. For new SDK versions, the libgpiod version imported might be different that previous SDKs. For the most up to date commands, refer to the man page for the GPIO command or use the --help flag.

  • The order that gpiochip are defined are different between Linux SDK versions. Why is it the case?

    When Linux is booting, it dynamically assigns gpiochips to GPIO modules defined in the device tree. With different Linux SDK version/Linux Kernel versions, there could be new dependencies that cause a deferred probing during the booting process. This will change how the gpiochips are enumerated. Its recommended to assign names to GPIOs for the application to search for the GPIO's name rather than relying on the gpiochip number.

  • I'm writing a custom application that will use a GPIO. Where can I get started?

    First, there is very limited support for custom drivers and applications because its beyond the scope of the E2E forums. We can only provide support for code provided in the Linux SDK because its been tested and validated by TI.

    Make sure that the GPIO can be used correctly in userspace before porting over to a custom application.

    For some basic examples, refer to the Libgpiod github page: https://github.com/brgl/libgpiod/tree/master/examples

    For using the legacy interface, refer to its documentation: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/Documentation/driver-api/gpio/legacy.rst?h=ti-linux-6.6.y