OSD335x Lesson 2: Linux Device Tree

Published On: May, 31, 2018 By: Eshtaartha Basu | Updated: April 29, 2019 by Cathleen Wicks

1      Linux Device Tree

1.1     Introduction

Most modern general-purpose computers, like a desktop or laptop, will consist of several peripherals connected to a main processor through a bus such as PCI, USB, etc. An operating system, such as Windows or Linux, running on the computer can discover or learn about the connected peripherals through enumeration. Enumeration is a process through which the OS can enquire and receive information, such as the type of the device, the manufacturer, or the device configuration, about all the devices connected to a given bus. Once the OS gathers information about a device, it can load the appropriate driver for the device. However, this is not the case when it comes to most embedded systems.

In embedded systems, many peripherals are connected to the main processor with busses like I2C, SPI, and UART, which do not support enumeration. Therefore, when an embedded system uses an operating system, such as Linux, it is necessary to convey the hardware configuration of the system, i.e. all the information about the connected peripherals, to the OS in a standard form. The most common way to do this in Linux is to use a device tree. A device tree is a tree data structure that describes the hardware configuration of the system to the Linux operating system. During boot, the Linux kernel will use the information in the device tree to recognize, load appropriate drivers and manage the hardware devices in the system.

This article will help you get started with Linux device trees by introducing the structure of device trees, describing some properties of device trees and showing you how to modify an existing device tree for your custom hardware configuration.  If you are working with Device Trees, you will also benefit from the follow up article OSD335x Lesson 2: Linux Device Tree Overlay .

Perk
Devices which use buses that support enumeration do not need to be included in the device tree. For example, devices that are connected to a USB Host port do not need to be included in the device tree, since the USB bus protocol supports enumeration. Similarly, all devices that are connected to an I2C bus must be included in the device tree, since the I2C bus protocol does not support enumeration.

Prerequisite

This article is a part of the broader OSD335x Reference Design Lesson 2 series which consists of a sequence of articles designed to help you build the bare minimum circuitry required to boot Linux on the OSD335x.  We recommend reading the article OSD335x Lesson 2: Linux Boot Process with the OSD335x  before this one. This article builds upon the foundation outlined in it.

All PCB design files for this lesson can be downloaded here.  

Lesson 2 Device Tree files can be downloaded here.

Table of Contents

1Linux Device Tree
1.1Introduction
1.2Device Tree Structure and Properties
1.3Modifying an Existing Device Tree
1.4Pin Multiplexing

A PDF version of this Lesson as well as the entire OSD335x Design Tutorial can be downloaded here.

Notice
The information provided within this document is for informational use only. Octavo Systems provides no guarantees or warranty to the information contained.

1.2     Device Tree Structure and Properties

A Linux device tree begins from a root node (i.e. the Tree Root) and will consist of a level of child nodes and one or more levels of children nodes. Each child node represents a hardware component of the micro-processor. For example, in the OSD335x, each child node represents a component of the AM335x processor, such as the CPU, an I2C peripheral, etc. Each children node represents a sub-component of a child node or a device attached to the child node. For example, in the OSD335x, the TPS65217C PMIC is attached to the I2C0 peripheral bus and appears as a children node under the I2C0 child node. Each node consists of property-value pairs that describe the hardware of the node. Each child node or children node can have only one parent and the root node has no parent. A block diagram of a simple device tree structure is shown in Figure 1.

Figure 1 Block diagram of a simple device tree structure

In the above picture, you can see the parent-child relationship that exists between the child and children nodes. For example, all CPU cores are grouped as children nodes under CPU child node. Similarly, all I2C devices on a given I2C bus are grouped as children under that I2C node

Perk
As mentioned above, a parent-child relationship exists between child and children nodes. Although it is counter intuitive to call parent node a child node and child node a children node, this was done to match the terminology used in the official device tree documentation.

To express these relationships, the Linux device tree has a specific syntax and structure that should be followed to ensure a device tree works as intended. Let’s look at a simple device tree template (Figure 2) that shows the generic syntax of the root node, child nodes, children nodes and property-value pairs.

.

Figure 2 Simple Device Tree Template (© Thomas Petazzoni, Device Tree for Dummies)

In the above figure:

  • node@0 and node@1 are child nodes.
  • child-node@0 and child-node@1 are children nodes of their respective child nodes.
  • node1 is an easy to remember label of node@1.
  • a-string-property, a-string-list-property, are properties that are used to describe the child and children nodes.
  • <&node1> is a phandle (i.e. a reference to node1 from node@0).

The official Device Tree Specification can be found here (this article will refer to information from version v0.2). A more detailed explanation of the device tree structure and basic concepts is available on the Device Tree Usage webpage. Please make sure you are familiar with these two documents before proceeding.

Now that the structure and the syntax of a device tree is clearer, the next question is: what property-value pairs should be used to describe a particular component and where can that information be found? The answer can be found in Device Tree Bindings. The properties that are necessary to describe a particular component in the device tree depends on the requirements of the Linux driver, or kernel module, for that component. All the required properties must be supplied to ensure that the Linux kernel recognizes the component properly and loads the appropriate drivers for that component. The Device Tree Bindings for a particular hardware device will give you this information. Therefore, it is essential to find the right Device Tree Bindings information for your component. More supporting documentation about device tree bindings can be found on the Device Tree Reference webpage.

As an example of Device Tree Bindings, the Lesson 2 board has a peripheral header that supports MikroElektronika Click Boards. To use a MPU 9DOF Click that has MPU-9150 9-axis motion tracking component, the appropriate information must be added to the device tree. This Click communicates with the host using I2C and has a single interrupt line to the processor. The device tree bindings for this component can be found here. Based on this, the following entry would be added to the device tree as a children node under the appropriate I2C child node:

The unit address (i.e. the @69 after the mpu9150) and reg values are both 69 because the MPU 9DOF Click’s address on the I2C bus is 0x69. The INT pin of the peripheral header, which is used for interrupts from the MPU 9DOF Click, is connected to the GPMC_AD9 pin of the OSD335x (which is the GPMC_AD9 pin of AM335x, see the Lesson 2 board schematics for more information). The GPMC_AD9 pin is also available to the system as bit 23 in GPIO bank 0 (see the Pin Attributes section of AM335x datasheet). Hence, the interrupt-parent for this device is a phandle for gpio0 node and the first value of interrupts property is 23. The second value of the interrupts property is used to describe the behavior of the interrupt, i.e. the trigger type and level, which can be found in the AM335x TRM. See here for more information about device tree interrupts.

The device tree bindings for all the hardware components must be consolidated to form a complete device tree so that the system can function properly. While this may seem like a daunting task, device trees are seldom built from scratch. The next section will discuss modification and reuse of existing device trees.

1.3      Modifying an Existing Device Tree

For an embedded Linux system, a device tree is generally a complex data structure requiring several hundred nodes to describe the entire system hardware architecture. Creating a device tree from scratch and validating it can be a daunting and time-consuming task. Therefore, you should look to reuse device tree include files and modify an existing device tree to meet your requirements.

A device tree for the Lesson 2 board can be created by modifying the published device tree from the OSD3358-SM RED board. You can download the device tree files here.

The OSD3358-SM RED board has several components that do not exist on the Lesson 2 board. Those components will need to be removed from the device tree to make it suitable for the Lesson 2 board. However, before doing this, you need to understand how the OSD3358-SM RED board device tree is structured.

The device tree consists of 2 files:

  • osd335x-sm.dtsi – This is a device tree include file that describes all the hardware that is present in the OSD335x-SM System-in-Package (SiP) device.
  • osd3358-bsm-refdesign.dts – This is the main device tree file that includes the previous file and adds nodes corresponding to the hardware that is specific to the OSD3358-SM-RED board.

Dividing the device tree into separate files helps with code reusability. Since the internal hardware of the OSD335x-SM remains the same irrespective of where it’s used, the device tree corresponding to it can be put into an include file (osd335x-sm.dtsi). Then, this file can be used in many device trees that utilize the OSD335x-SM.

When using device tree include files, it is important to understand the status of each node (i.e. after loading the include file, is a given node in an okay or a disabled state). The main device tree file (osd3358-bsm-refdesign.dts in this case) can then enabled or disable nodes depending on the system hardware. The nodes with the preceding ampersand (&) in the main device tree file are referencing nodes that are already declared in osd335x-sm.dtsi.

At this point, the OSD3358-SM-RED board’s device tree can be modified to match the hardware on Lesson 2 board. The nodes and node references that do not correspond to the Lesson 2 board can be removed in osd3358-bsm-refdesign.dts. Figure 3 lists all the nodes that are present in this file. The nodes that are marked with X should be removed.

Figure 3 osd3358-bsm-refdesign.dts before modifications

After the modifications, the osd3358-bsm-refdesign.dts will look like Figure 4. Since it now reflects the Lesson 2 hardware, the file can be renamed to osd335x-lesson2.dts

Figure 4 osd3358-bsm-refdesign.dts after modifications to reflect Lesson 2 hardware

You can directly download the osd335x-lesson2.dts device tree file for the Lesson 2 board here. The .dts device tree source files are human readable and can be viewed in your favorite text editor. Next, this source file will be converted to a Device Tree Blob or .dtb file, i.e. a binary file that is smaller and easier to parse by the Linux kernel. For the OSD335x Family of devices, Robert Nelson’s Device Tree Rebuilder can be used to compile the device tree source. You can download it here.  (We have tested our .dts files using 4.14-ti branch with the OSD3358-SM RED Debian image. For a different image, use a branch that matches the image’s kernel version).

The steps to compile and use the new device tree on the Lesson 2 board are as follows:

  1. Install a clean software image (optional)
    1. Download the latest OSD3358-SM RED Debian image (or a suitable Linux image from Beagleboard.org depending on your board) on your host PC
    2. Flash the image on a microSD card or the on-board eMMC
    3. Boot the board with the image
  2. Install dtb-rebuilder by either
    1. Downloading dtb-rebuilder on your host PC and copying it your board. You can use Cloud9, SSH, or SFTP client app like WinSCP.
    2. Cloning the git repository if the board has internet connectivity
  3. Copy source files
    1. Copy osd335x-lesson2.dts and osd335x-sm.dtsi files to the “<install_path>/dtb-rebuilder/src/arm” directory of the board.
  4. Build the device tree
    1. Run the make command in the “<install_path>/dtb-rebuilder” directory of the board (see Caveat below for debug help).
    2. Result: The osd335x-lesson2.dtb file will be in the “<install_path>/dtb-rebuilder/src/arm
  5. Install the dtb file
    1. Copy the osd335x-lesson2.dtb file to “/boot/dtbs/<kernel version>/” directory to make it available to the Linux Kernel during boot.
  6. Edit the boot configuration file (uEnv.txt) to use the new device tree:
    1. Open the /boot/uEnv.txt configuration file using a text editor. For example: “nano /boot/uEnv.txt
    2. Comment out the existing dtb variable and add the line dtb=osd335x-lesson2.dtb as shown in Figure 120. Save the file.
    3. Reboot the board using the command: “sudo reboot -h now

The board should now boot using the new device tree

Figure 5 Setting Kernel Device Tree file in uEnv.txt
Perk
To understand what was loaded during the boot process, you can look at the boot messages on the serial console (by default UART0) during boot or in the system logs after boot. This can help you debug any boot issues.
Caveat
If you get time skew warnings while building the device tree, run “touch *” in:

  • <install_path>/dtb-rebuilder
  • <install_path>/dtb-rebuilder/src”
  • <install_path>/dtb-rebuilder/src/arm

directories to update the file modification time of all files to resolve the warning.  If there are any syntax errors in the device tree, the compiler will indicate the line number where the error was found. You can use this information to track and resolve the error. The most common error is phandle references to non-existing nodes. Since some nodes were deleted while modifying the device tree, any references to the deleted nodes might cause errors. Make sure to delete all phandle references to the deleted nodes to fix any errors.

1.4       Pin Multiplexing

The OSD335x family of devices provides access to all 123 signal pins of the AM335x processor. Each of these signal pins can have up to seven (7) different functions, or modes, which allows a given peripheral within the AM335x to be multiplexed to different pins. The pin modes for each pin can be found in the Pin Attributes table of AM335x datasheet (the OSD335x family uses ZCZ package of AM335x when referring to pin names / pin functionality). The RESET REL. MODE column of the table shows the default mode that will be assigned to the pin after the processor is released from reset. If this mode is not the mode required by system, you will need to add information to the device tree to set the pin mulitplexing so that the connected components interface properly with the AM335x processor.

For example, below shows a device tree snippet from the am33xx_pinmux node of the osd3358-bsm-refdesign.dts file. The pinctrl-single driver is used to set the appropriate pin configuration (more information about pinctrl-single driver can be found here). The AM33XX_IOPAD macro (which can be found in the dt-bindings/pinctrl/omap.h file, which is included by the dt-bindings/pinctrl/am33xx.h file, which is included by the osd335x-sm.dtsi file) helps configure each pin (more information about AM33XX_IOPAD macro can be found here)

 

 

You can find the absolute physical address of the pins, which is required for the macro, in the CONTROL_MODULE REGISTERS table of AM335x TRM. In the table, each signal pin name is prefixed with conf_. For example, the absolute physical address of the GPMC_A5 pin, 0x854, is shown in Figure 6.

Figure 7 Physical Address of GPMC_A5

In addition, you can also use TI’s PinMux Tool to ensure the pin muxing of your pins do not conflict with each other (You will need a TI user account to use the tool). You can watch the TI PinMux Tool getting started video here to learn more about the tool.

Caveat
The Device Tree and Device Tree Overlay standards and common practices are still being refined. Please let us know if you see any updates by contacting us at https://octavosystems.com/forums/.

For any questions or concerns, you can reach us at: https://octavosystems.com/forums/

We’d like to thank lewing@isc.tamu.edu and The GIMP for permission to use the ‘Tux’ Linux image used in our social media about this post

 

<< Return to “OSD335x Lesson 2 : Linux Boot Process with the OSD335x”Continue to “OSD335x Lesson 2 Linux Device Tree Overlay” >>