[LINUX] I examined the device tree

1.First of all

While running an FPGA with an ARM CPU on Linux, it became necessary to modify what is called a device tree. Therefore, I would like to write about what I investigated (understood by myself) so that I could roughly understand the contents of the device tree source (.dts) included in the Kernel source. I hope that people who look at the .dts file in the Kernel source and think "what's wrong" will feel like they understand it and feel like they can make additional corrections.

2. Who is the Debye Tree?

2.1 Origin

The device tree can be called a data structure (file format) that describes hardware parts that can be accessed from the OS (CPU) from the perspective of software (device driver). This format was developed by a group called Open Firmware (a group separate from the Linux development group).

2.2 How to use on Linux

This format is also used in Linux, and the Kernel code and the information for each board (that is, the device tree) are separated and operated. This makes it possible to prepare a device tree for a board so that it can operate on different boards while keeping the Kernel binaries common. The Kernel source has a device tree source (.dts) file for the major supported boards, and the device tree binaries are on the Makefile system as well as build the Kernel binaries (eg make zImage). It can be generated (eg make dt bs). By the way, at the time of writing this article (May 2020), the Linux kernel source tree of the original Kernel.org registered more than 1200 .dts files only for ARM 32-bit CPUs. The Kernel code (each device driver) searches the device tree for the information that it needs at the time of initialization, and completes device registration and initialization according to that information. Therefore, there may be situations where the Kernel will not start unless the information required by the Kernel code is described in the device tree, so in principle, the Kernel binary and device tree should be created from the same version of the Kernel source. Kernel.

2.3 Device tree file type

Written in human-readable text format is called a device tree source and has a .dts extension. The file converted to binary format is called a device tree blob and has a .dtb extension. The Kernel reads the device tree blob (.dtb) in binary format. The device tree compiler (dtc command) is used to convert the device tree source to the device tree blob. The device tree compiler has the option of doing an inverse conversion .dtb-> .dts as well as .dts-> .dtb, which you can use if you want to see the contents of binary .dtb.

3. Understanding the device tree

To understand the device tree in Linux (although the introduction has been lengthened) --Device tree format (how to write) --What information needs to be written in the device tree (what information the Linux device driver reads from the device tree)

I think it is good to understand it by dividing it into two parts. Here, we will focus on the device tree writing (format). What information needs to be written in the device tree depends on what information the Linux device driver needs. At the end of this article, I'll give you a brief introduction.

3.1 Overview of dts file format

** Roughly speaking about dts files **

--A list of hardware (device nodes) that you want the CPU to access as a tree-like database. --There are only two types of components, node and property. --node can have various attribute information properties and child nodes --property is represented by a combination of the attribute name name and its value value, and is used to describe hardware information such as address information and interrupt numbers.

is. For more details, please see the link below. https://elinux.org/Device_Tree_Usage

3.2 Node

node format

	[label:] node-name[@unit-address] {
		[properties definitions]
		[child nodes]

--device is represented as node --node has property and node (child node) --By having a node inside a node, a tree structure of nodes will be created.

--node name Define the name in the format @ unit-address, and define the node contents in the following curly braces {} --The unit-address part describes the address specified by reg property in hexadecimal. Even if there are multiple devices with the same node name, they can be distinguished by unit-addres. No unit-address is needed for nodes that don't have a reg property. Linux dtc can compile without unit-address (although Warning appears) --The node name is a simple ASCII string with a maximum length of 31 characters. --It is recommended to give a name (ethernet, serial, gpio, etc.) that represents the function of the device. --The top (root) node has no node name, only "/". / {...}; --The node tree structure (parent node --relationship between child nodes) is described so as to indicate the connection status of the device as seen from the CPU (for example, Bus bridge is the parent and SlaveDevice connected to Bus bridge is defined as its child node. To do) --If you add a label (label :), you can specify the phandle of that node by writing & label. If it is compiled with the "-@" option, it can be referenced from another file (overlay file). (See also the description of phandle property below)

3.3 Property --property is a combination of property-name = value --There may be no value

[label:] property-name = value; [label:] property-name ;

3.3.1 Types of value used in Property

--Text String: Enclose in double quotes compatible = " arm, cortex-a9 "; --Array / Cell-list: A set of 32-bit unsigned integers separated by angle brackets <> reg = <0xffd04000 0x1000>; --Binary Data: Separated by square brackets [] mac-address = [12 34 56 ab cd ef]; --Multiple data: Can be concatenated using commas reg = <0xff900000 0x100000>, <0xffb80000 0x10000>; mixed-property ="a string", [0x01 0x23 0x45 0x67], <0x12345678>;

3.3.2 Standard Property commonly used in many nodes

#address-cells,Example of how to use renges

	sopc0: sopc@0 {
sopc@0 (Parent) and bridge@Relationship of 0xc0000000 (child)
sopc@0 and bridge@0xc0000000 has the same memory space (no address translation).
		#address-cells = <1>;
		#size-cells = <1>;
		hps_0_bridges: bridge@0xc0000000 {
			reg = <0xc0000000 0x20000000>,
			         <0xff200000 0x00200000>;
bridge@0xc0000000 is a memory space from 0xc0000000 to size 0x20000000,
Has two memory areas in the memory space from 0xff200000 to 0x00200000
			#address-cells = <2>;
			#size-cells = <1>;
bridge@The child node of 0xc0000000 is address-cells are two 32-bit numbers, size-The cell is represented by one 32-bit numerical value.
			ranges = 	< 0x00000000 0x00000000 0xc0000000 0x00010000 >,
					< 0x00000001 0x00020000 0xff220000 0x00000008 >,
					< 0x00000001 0x00010040 0xff210040 0x00000020 >;
The memory area from 0xc0000000 to size 0x00010000 is the address of the child node.<0x00000000 0x00000000>Assigned to size 0x00010000 from
The memory area from 0xff220000 to size 0x00000008 is the address of the child node.<0x00000001 0x00020000>Assigned to size 0x00000008 from
The memory area from 0xff210040 to size 0x00000020 is the address of the child node.<0x00000001 0x00010040>Assign to size 0x00000020 from
(Other areas are not allocated to child nodes).

			led_pio: gpio@0x100010040 {
				compatible = "altr,pio-16.0", "altr,pio-1.0";
				reg = <0x00000001 0x00010040 0x00000020>;
gpio@0x10001004 is<0x00000001 0x00010040>From size 0x00000020
Has a memory area, but this is the parent(Upper) size from 0xff210040 of node
Maps to 0x00000020 memory area(0xff210040 from CPU-Accessable in a range of 60).
			}; //end gpio@0x100010040 (led_pio)
		}; //end bridge@0xc0000000 (hps_0_bridges)

3.5 Other supplements

--The first line is / dts-v1 /; --Comments can use C style (/ * ... * /) and C ++ style (// ...). --If a definition for the same node name appears in the same hierarchy, it will be regarded as the same node and will be an additional definition for that node. Property can be redefined (later definition will be used) --When compiling with Kernel Makefile, it is processed by gcc preprocessor first. -#include ..., #define ... can be used

4. What kind of information to write in Device Tree

In this regard, it's best to read the Kernel Source documentation. As an example, let's take a look at the description of node with the following interrupt.

intc: intc@fffed000 {
    compatible = "arm,cortex-a9-gic";
    #interrupt-cells = <3>;
soc {
  interrupt-parent = <&intc>;
    i2c0: i2c@ffc04000 {
	    interrupts = <0 158 0x4>;

In the above code, the interrupts property of i2c @ ffc04000 consists of 3 cells, but how to find out what to write in these 3 numbers. Search the files under the Kernel Source Documentation / devicetree / bindings directory for the interrupt-controller compatible string "arm, cortex-a9-gic" (eg find Documentation / devicetree / bindings -name" *. txt "| xargs grep" arm, cortex-a9-gic ", git grep" arm, cortex-a9-gic "--Documentation / devicetree / bindings if you brought the Kernel Source with git). This will hit Documentation / devicetree / bindings / interrupt-controller / arm, gic.txt. Looking at the contents of this file, # interrupt-cells is set to 3, and the contents of each are

--First interrupt type: 0 is Shared Peripheral Interrupt (SPI), 1 is Private Peripheral Interrupt (PPI) --Second interrupt number: [0-987] for SPI, [0-5] for PPI --The third flag has the following meaning: - 1 = low-to-high edge triggered - 2 = high-to-low edge triggered (invalid for SPIs) - 4 = active high level-sensitive - 8 = active low level-sensitive (invalid for SPIs).

It is stated to be. <0 158 4> in the above code is --Shared Peripheral Interrupt interrupt, --SPI 158th interrupt number, --active high level interrupt Means. By the way, if you check the SoC specifications described by this .dts, the Shared Peripheral Interrupt interrupt number starts from 32 of the GIC interrupt controller, so subtract 32 from the GIC interrupt number of the SoC specifications. The value will be written second (i2c @ ffc04000 is the 190th interrupt in the SoC specifications). Probably, in SoC using ARM GIC, the interrupt number obtained by subtracting 32 is described in .dts in common.

Also, if you want to know more about how to write .dts in general, you may want to read Documentation / devicetree / booting-without-of.txt under the Documentation folder of Linux Source. As a required node - root node - /cpus node - /cpus/* nodes - /memory node(s) - /chosen node - /soc node There are plenty of descriptions such as.

That's it.

5. Reference materials

https://elinux.org/Device_Tree_Usage https://elinux.org/Device_Tree_presentations_papers_articles https://devicetree-specification.readthedocs.io/ https://git.kernel.org/?p=/linux/kernel/git/torvalds/linux.git;a=blob_plain;f=Documentation/devicetree https://www.nds-osk.co.jp/forum/freedownload/08/casestudy2/DeviceTree2.pdf

Recommended Posts

I examined the device tree
I investigated the device tree Overlay
I counted the grains
I examined OpenCV filtering
I examined the argument class_weight of Chainer's softmax_cross_entropy function.
I examined the data mapping between ArangoDB and Java
I tweeted from the terminal!
I touched the Qiita API
I tried the changefinder library!
I downloaded the python source
I read the SHAP paper
Check server I / O device usage with the Linux iostat command
I tried the TensorFlow tutorial 1st
I got lost in the maze
I tried the Naro novel API 2
I installed the IoT platform "Rimotte"
I investigated the mechanism of flask-login!
I participated in the ISUCON10 qualifying!
I tried the TensorFlow tutorial 2nd
I calculated the stochastic integral (I to integral)
I investigated how the scope looks
I liked the tweet with python. ..
I wrote the queue in Python
I tried the Naruro novel API
I tried to move the ball
I tried using the checkio API
I wrote the stack in Python
I tried to estimate the interval.
I don't know the value error
I checked the gift tax amount
I implemented the K-means method (clustering method)
I tried to understand the decision tree (CART) that makes the classification carefully
[Python] I examined the exe conversion method for distributing business efficiency tools.