First Steps with Device Trees
Introductionβ
This article guides you through the initial stages of customizing a device tree. You will discover the process of creating your own custom Device Tree, exploring common scenarios for customization starting from a basic reference. Additionally, you will gain insight into the necessary modifications to ensure compatibility with your specific hardware.
Quick examples will be provided to facilitate understanding and enable you to easily replicate the customization, enhancing your familiarity with the entire workflow. Here you will learn the basics of device trees, their anatomy, and the steps involved in modifying, compiling and deploying them.
Prerequisitesβ
- Set up the build environment and compile the Linux kernel. For this, follow the instructions at Build Linux Kernel From Source Code.
Getting Started with Device Treesβ
Before diving into device tree customizations, it is essential to grasp the fundamental concepts and structure of Device Trees, as they are invaluable tools in the world of embedded systems. They provide a standardized and flexible approach for customizing the hardware configuration, enabling seamless integration between the operating system and the underlying hardware.
At its core, a device tree is a data structure that represents the hardware components in a system. It describes devices, their properties, and the interconnections between them using a hierarchical tree-like structure. The device tree is typically stored as a text file with a ".dts" or ".dtsi" extension. It can be compiled into a binary format known as a Device Tree Blob (DTB). The DTB is then loaded by the bootloader during system initialization.
Toradex offer a series of articles to aiming to provide a wide understanding of device trees on its computer on modules:
Identifying and Understanding Modification Requirementsβ
The first step in device tree customizations is to identify the specific hardware configurations or modifications your particular hardware requires.
This could include enabling or disabling peripherals, modifying pin assignments, adjusting clock frequencies, or configuring specific functionalities and other hardware-specific parameters as needed.
In other words, this .dts
file should reflect the description of your custom hardware and the changes you want to make to the base device tree.
To determine the customization needs, refer to the documentation and datasheets of your hardware components, including the System-on-Chip (SoC), System on Module (SoM), and carrier board. Understanding the capabilities and specifications of these components will guide you in making the necessary modifications.
Device Tree Binding Documentationβ
To understand the structure and syntax of the DTS file, it is crucial to refer to the device tree binding documentation specific to your hardware platform. The device tree binding documentation provides detailed information on the available device tree nodes, properties, and their valid values.
Toradex Resourcesβ
Toradex offer a series of articles to aiming to provide a wide understanding of pinmuxing and pin assignments on its computer on modules:
- Customizing Nodes and Properties
- Pinmuxing Guide Overview.
- Pinmuxing with i.MX 6/6ULL Based Modules.
- Pinmuxing with i.MX 7 Based Modules.
- Pinmuxing with i.MX 8/8X Based Modules.
- Pinmuxing with i.MX 8M Mini/Plus Based Modules.
First Steps Modifying a Device Treeβ
Choose the Base Device Treeβ
The next step is to locate the device tree source (DTS) file corresponding to your hardware platform. The DTS file contains the description of the hardware components and their configurations. It serves as the starting point for your customizations. The device tree files are provided by Toradex and are available in the Linux kernel source code, mainline or downstream. You can usually find it in the "arch/arm/boot/dts" or "arch/arm64/boot/dts" directory. If you cannot find a pre-existing DTS file for your specific hardware, you may need to create one from scratch using the existing DTS files as a reference.
Choose the base device tree that matches the hardware platform. Toradex provides a set of base device trees for its hardware platforms that can be found in:
- linux.git, if you are working with an upstream-based.
- linux-toradex.git, if downstream-based kernel
Clone the repositories as you might need. Check the branch at Kernel Version Informationβ
$ git clone -b <branch> git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
$ git clone -b <branch> git://git.toradex.com/linux-toradex.gitFind a device tree layout of the module you are using and the respective carrier board level device tree for you to base on. Check the following directories accordingly to the architecture of your SoM.
- 64-bits modules:
/arch/arm64/boot/dts/freescale/
- 32 bits modules:
/arch/arm/boot/dts/
- 64-bits modules:
Create Custom Device Treeβ
Once you have the DTS file, you can begin making the necessary customizations. This involves modifying the device tree nodes, properties, and values to reflect your desired hardware configuration. To understand the structure and syntax of the DTS file, it is crucial to refer to the device tree binding documentation specific to your hardware platform. The device tree binding documentation provides detailed information on the available device tree nodes, properties, and their valid values.
Create your custom
.dts
based on the previously selected device tree. You can do this by copying the base device tree and editing the custom one. For example:$ cp ./arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-dev.dts ./arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-dev-custom.dts
In the
/dts/freescale/
directory of the device trees, there is a Makefile to set the compilation process. Edit the Makefile and insert your custom device tree under the rightdtb-$(CONFIG_SOC_*)
. For example:/arch/arm64/boot/dts/freescale/Makefiledtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-wifi-dev-custom.dtb
noteThe compilation using
make
needs to be done inside the/arch/arm64/boot/dts/freescale/
.
Customizing the Device Treeβ
As mentioned on Device Tree Technical Overview - Customization, there are common use cases where you need to customize a device tree. The sections below illustrate quick examples of how to perform your first steps with these common use cases. You are encouraged to create your DTS, modify it according to the following examples, compile, and deploy them to have a practical experience with these concepts.
Change and overwrite nodes and properties: Typically the higher layers (e.g. carrier board device tree) overwrite the lower layers (e.g. SoC device tree) since the higher layers include the lower layers at the very beginning (the sequence order of entries is what matters, hence the include order matters). Entire nodes can be overwritten by simply redefining them. The node needs to be defined using the ampersand & character and the label, and its properties changed under the node. To overwrite the pin configuration of, for example, Colibri iMX6ULL ADC1, overwrite the
adc1grp
node by simply redefining it in your device tree. This will configure the ACD1 for using the SODIMM pins 2,4,6 and 8.pinctrl_adc1: adc1grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 0x3000 /* SODIMM 8 */
MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0x3000 /* SODIMM 6 */
MX6UL_PAD_GPIO1_IO08__GPIO1_IO08 0x3000 /* SODIMM 4 */
MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x3000 /* SODIMM 2 */
>;
};Activate and deactivate devices: An important device attribute is the
status
property. It allows devices to be activated/deactivated. A lot of devices are specified in the SoC level device trees but are disabled by default. By referencing the base node (using the ampersand character and the label), the device can be enabled by any of the layers overwriting the status property.&i2c2 {
status = "okay";
};Pin multiplexing: Add a pin group node to the
iomuxc
node defining the pin function and settings. The pin group node can be found in the related *.dtsi file.&iomuxc {
...
pinctrl_i2c3: i2c3grp {
fsl,pins = <
MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1
MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
>;
};
...
};Add and configure a new device/peripheral: You can add an I2C accelerometer and gyroscope by simply adding a child node under the
i2c
bus parent node.&i2c1 {
mpu6050: accelerometer@68 {
compatible = "invensense,mpu6050";
reg = <0x68>;
status="okay"
interrupt-parent = <&gpio1>;
interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
};
};
Compile the Device Treeβ
Once you have the DTS file, the next step is to compile it into a binary device tree blob (*.dtb
) file. The compilation process involves using the Device Tree Compiler (dtc) tool provided with the Linux kernel source code.
Compilation From Source Codeβ
If you want to perform a standalone compilation of your device tree and generate the blob file to be deployed on your Linux distribution, you need to use the DTC tool and the make
command, as shown in the command below.
$ make DTC_FLAGS="-@" freescale/<custom-device-tree>.dtb
$ make DTC_FLAGS="-@" <device-tree>.dtb
Keep in mind that you previously need to configure your build environment accordingly to you Linux kernel version. For more information on this topic, follow the instructions at Kernel Compilation article to find instructions on how to compile and deploy your new device tree.
Compilation on Torizonβ
When in the evaluation or early development phases, it can be convenient to use the TorizonCore Builder dt apply
command to compile and set the device tree source file to be used in the image. It should be used along with other commands to consolidate the modification to the image, as you can learn in the Command Manual. For example:
$ torizoncore-builder dt apply custom-device-tree.dts
During the later stages of development and when preparing the image for production, it's recommended to write a tcbuild.yaml
file and use the build
command to perform the task.
# Sample configuration file:
input:
easy-installer:
local: images/<base-image>.tar
#Sample customization: apply a new device tree to have my first steps with device trees customization
customization:
device-tree:
include-dirs:
- device-trees/include/
custom: <custom-device-tree>.dts
output:
easy-installer:
local: <custom-image>.CUSTOM
$ torizoncore-builder build
For detailed Torizon-related information, refer to Device Tree Overlays on Torizon and TorizonCore Builder Tool - Customizing Torizon OS Images.
Deploy the Device Treeβ
Deploy to an Embedded Linux Imageβ
If in development/test phase, the quickest approach to deploy your compiled custom device tree is simply copying the binary blob to the /boot
directory on the rootfs of your embedded linux image using scp command or a removable media.
$ scp <custom-device-tree>.dtb root@<ip-address>:/home/boot/
For production, it's ideal to update the kernel and the device tree on the final production image. For this, follow the steps at Deploying the Kernel to an Image
Update the DT on a NAND-based SoMβ
NAND-based modules do not support customizations through device tree overlays, but through device trees only. It means that to modify and update the device tree in your SoM, you will have to modify the base *.dts
file. Then, to update the DT on the UBIFS of a NAND-based SoM follow the steps at Updating NAND-based modules from userspace - Updating the Device Tree.
Deploy to Torizon OSβ
To deploy the custom image with a custom device tree to the device, you can use TorizonCore Builder to generate an image and then, use Toradex Easy Installer to deploy. This process is illustrated below but is better explained in the Deploy The Custom Toradex Easy Installer Image section.
$ torizoncore-builder union custom-branch
$ torizoncore-builder deploy custom-branch --output-directory <custom-image>.CUSTOM
$ cp -a <custom-image>.CUSTOM /media/user/myUSBstick
Or you can opt to deploy directly through SSH, as follows:
$ torizoncore-builder deploy custom-branch --remote-host <ip-addr> --remote-username torizon --remote-password torizon --reboot
However, when using the build command
, as explained in the section Compilation on Torizon, TorizonCore Builder is able to compile and deploy the device tree in a single step. It is done along with all the other customizations described in the build.yaml
file. This is a convenient way to directly integrate the .dts
file into your customization process without manually compiling and deploying the device trees.
You can also refer to Device Tree Overlays on Torizon and TorizonCore Builder Tool - Customizing Torizon OS Images articles for more content.
Next Stepsβ
Now you have completed the workflow of DT customization, going through the selection of a base device tree, from modifying to deploying. Your custom .dts
file should reflect the description of your custom hardware and the changes you want to make to the base device tree: enable or disable devices, adjust pin configurations, set clock frequencies, and modify other hardware-specific parameters as needed.
For this, follow the steps at How to Customize Device Trees.