How to Program Linux .Dts Device Tree Files

How to program Linux .dts device tree files?

Take a look at the dts of the board which most closely resembles your dev-board. Use that as a reference and make changes to the dts according to the differences between the reference board and your dev-board.

Also checkout the following :

- Device-tree Documentation project at eLinux (has a vast collection of links to start reading).

- Series of articles on the basics of device tree.

- Walkthrough of migrating to device-tree.

How to compile dts Linux device tree source files to dtb?

Device trees do not need to be compiled with "architecture-aware" tools. The dtc compiler on your ubuntu machine is probably current enough to compile your device tree. Or you can download the latest source and compile it yourself. The dtc compiler can be found here:

https://git.kernel.org/pub/scm/utils/dtc/dtc.git

There are some good documents in that package that will help you better understand device trees in general.

It's pretty easy to compile (and disassemble) device trees. For example

$ dtc -O dtb -o p4080ds.dtb p4080ds.dts

To get the device tree in text from from the device tree blob, do this:

$ dtc -I dtb -O dts p4080ds.dtb

Hope this helps!

Tool to visualize the device tree file (dtb) used by the Linux kernel?

You can try the Component inspector tool.

Sample Image

It is part of QorIQ Configuration Suite which is a plugin for Eclipse.

Download here.
(Requires registration. Free to download.)


Personally as i am on the cmd-line most of the time, and quite addicted to vi, i find its built-in code folding capabilities are somewhat sufficient as long as the dts is properly indented.

Setup hot-keys commands to fold/expand blocks of code in vi

by adding the following lines to .vimrc :

nnoremap <silent> <F5> zfa}<CR>
nnoremap <silent> <F6> zo<CR>

With the above setup, to fold a block/node, simply move the cursor onto any of its lines(except the title) and hit F5. To expand a folded block/node, move to the line with the folded title and hit F6.

Here is what a partially folded dts looks like in vi.
Sample Image

Device Tree Vs .Config file | Are they different?


Device Tree Vs .Config file | Are they different?

Yes, they are different, and serve different purposes at different times.

The .config file is an integral component of the kernel's build procedure.
The .config file is data to control the building of the kernel, that is, its contents is used by makefiles.

A .config file could be customized to build a kernel specifically for just one specific version of a SBC.

Or the .config file could specify a kernel with a plethora of features, subsystems, and drivers for a variety of capabilities and support families of SBCs. Such a kernel image could be booted by any compatible board.


A .config file consists of lines of configuration symbols, e.g. CONFIG_xxx=....

Assignments of strings or numeric constants are rare, but do exist, e.g. CONFIG_LOCALVERSION="my_version" and CONFIG_INIT_ENV_ARG_LIMIT=32.

Typically the assignment is y to affirm that the configuration item is enabled.

A configuration item that is disabled is not asigned n, but rather commented out, e.g. # CONFIG_xxx is not set.

A configuration item that is "tristate" can be assigned m to affirm that the configuration item is enabled but built as a loadable module (rather than statically linked, aka built-in).

Note that although kernel source code may contain preprocessor directives (e.g. #ifdef for conditional compilation) utilizing CONFIG_xxx symbols that appear identical to the .config symbols, these symbols are not equivalent.

Kernel source code does not read or use the .config file.

Rather the .config file is converted into a C header file of preprocessor statements with a #define for each enabled CONFIG_xxx line, and stored in include/generated/autoconf.h (the exact path has changed for older versions).

It is the autoconf.h file that defines the CONFIG_xxx symbols used in kernel source code.

Note that a tristate configuration item that is assigned m in the .config becomes #define CONFIG_xxx_MODULE 1 in the autoconf.h file, rather than just #define CONFIG_xxx 1.


Device Tree is used by only a handful of CPU architectures in the Linux kernel.

The Device Tree (blob) is data to inform the executing kernel of its hardware environment (i.e. the target board). It also informs the kernel which device drivers to initialize (using the compatible property string).

Regardless of how many device drivers are statically linked into the kernel or available as loadable modules, a device driver is only initialized if there is a DT device node that references that device driver (e.g. see Driver code in kernel module doesn't execute?).

(The exception to that are buses that have self-identifying devices such as USB and PCI/PCIe, which have different procedures for initializing their device drivers.)


The Device Tree goes through several transformations before it is utilized by an executing kernel.

The DT source file(s) for a specific board exist as one .dts and optional .dtsi (included) files that are compiled into a .dtb file, aka DT blob.

It is the DT blob that is loaded with the kernel during boot, and then converted from its "flat" organization into a tree structure in kernel memory.

Kernel routines, e.g. device drivers, access the DT using methods provided by of_*() routines (where the "of" is for Open Foundation).

DTS: Overwriting pin configuration

You can overwrite a node as long as you have labled it. A label has the form of label: node@0x1 { /* data */ };

Lets take an example device tree named main.dts:

$ cat main.dts 
/dts-v1/;

/ {
model = "Test device tree";
#address-cells = <0>;
#size-cells = <1>;

iomuxc: iomuxc@0x1 {
reg = <0x1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog>;

imx6qdl-var-som-mx6 {
pinctrl_hog: hoggrp {
fsl,pins = <
0x1b8 0x588 0x000 0x5 0x0 0x80000000
/* more pins */
>;
};
};
};
};

&pinctrl_hog {
fsl,pins = <
0x1b8 0x588 0x000 0x5 0x0 0x89999999
/* more pins */
>;
};

Here, I overwrite the pin control for the label pinctrl_hog. You can validate the output by compile and decompile the device tree:

$ dtc -I dts -O dtb -o out.dtb main.dts # compile 
$ dtc -I dtb -O dts out.dtb
/dts-v1/;

/ {
model = "Test device tree";
#address-cells = <0x0>;
#size-cells = <0x1>;

iomuxc@0x1 {
reg = <0x1>;
pinctrl-names = "default";
pinctrl-0 = <0x1>;

imx6qdl-var-som-mx6 {

hoggrp {
fsl,pins = <0x1b8 0x588 0x0 0x5 0x0 0x89999999>;
linux,phandle = <0x1>;
phandle = <0x1>;
};
};
};
};

As you can see, the pins is set to 0x89999999 instead of the original 0x80000000. Just make sure that the label exists before you use it. Normally, just as in C, you include the header on top of your file.

I hope this helps ;-)

Linux Device Tree: How to make the device file?

The traditional UNIX "stream of bytes" device model is a pretty high-level abstraction of most modern hardware, and as such there are plenty of drivers which do not create /dev entries for the devices they control largely because they don't fit that model. Bus drivers in particular are very much a case of that - they exist, but only for the sake of discovering and allowing access to the devices behind them; there is no /dev/sata that lets you interact with the actual host controller, sending out raw commands on any old port regardless of what's connected or not; there is no /dev/usb that lets you attempt arbitrary transfers to arbitrary endpoints which may or may not exist.

Furthermore, your typical 'external interface' controller as in this case is orders of magnitude less complex than an interface like SATA or USB - the 'device' itself is often little more than a register block controlling some clocks and a chip-select multiplexer. Even if the driver did create something you could interact with directly, there's not exactly much you could do with it.

The correct way to proceed in this situation is to describe your FPGA device in the DT as a child of the GMI bus, accurately reflecting the hardware, no less, then develop your own driver for that. The bus driver itself just sits transparently in the middle. And if you do want a quick and dirty way to get started by just reading and writing bus addresses directly, well, it's behind a memory-mapped I/O region; that's exactly what /dev/mem exists for.



Related Topics



Leave a reply



Submit