The Linux kernel introduces the concept of the device tree starting from 3.x, which is used to separate the driver code from the device information . Before the device tree appears, all specific information about the device is written in the drive, and once the peripheral device changes, the driver code is rewritten. After the introduction of the device tree, the driver code is only responsible for processing the driver logic, and the specific information about the device is stored in the device tree file, so that if only the hardware interface information changes without driving logic changes, driver developers only need to modify the device tree file information, do not need to rewrite the driver code. For example, within Arm Linux, a . DTS (device tree source) file corresponds to an arm machine, which is typically placed in the kernel's "arch/arm/boot/dts/" directory. For example, the board-level device tree file for the exynos4412 reference board is "Arch/arm/boot/dts/exynos4412-origen.dts". This file can be compiled into binary . dtb files by $make dtbs
command for kernel-driven use.
Based on the same idea of layered software design, because one soc may correspond to multiple machines, if each machine's device tree is written as a completely separate . dts file , then there is bound to be quite a few . DTS files have duplicate parts, To solve this problem, the Linux device tree catalog refines a common part of the SOC or parts of a machine together into a corresponding . dtsi file . So each . DTS only has its own differences, and the public part only needs the "include" corresponding. dtsi file , so that the entire device tree is managed more orderly. Here I use the ' Linux4.8.5 source of the dm9000 network card as an example to analyze the use and migration of the device tree. This network card device tree node information in the "Documentation/devicetree/bindings/net/davicom-dm9000.txt" has detailed description, its network card driver source code is "Drivers/net /ethernet/davicom/dm9000.c ".
Device Tree Framework
The device tree describes the device information in a tree-like structure, and it has several characteristics
- Each device tree file has a root node, and each device is a node.
- Nodes can be nested to form a parent-child relationship, so that the relationship between devices can be conveniently described.
- The properties of each device are described by a set of key-value pairs (key-value pairs).
- The description of each property
;
ends with
Therefore, the basic framework of a device tree can be written as follows, in General,/for the board, its child node Node1 represents a controller on the SOC, the child node in the controller Node2 represents the devices attached to the controller (we).
/{ //根节点 node1{ //node1是节点名,是/的子节点 key=value; //node1的属性 ... node2{ //node2是node1的子节点 key=value; //node2的属性 ... } } //node1的描述到此为止 node3{ key=value; ... }}
Node name
The theory of a node name as long as it is not more than 31 characters in length ASCII string, in addition
The Linux kernel also agreed that the device name should be written as <name>[@<unit_address>]
a form, where name is the device name and can be up to 31 characters long. Unit_address is usually the device address, used to uniquely identify a node, the following is the typical node name notation
The node name above is the firmware
node path /[email protected]
, which should be noted because the parameters of the API for finding nodes according to the node name cannot have the "@xxx" section.
The device tree in Linux also includes several special nodes, such as the Chosen,chosen node does not describe a real device, but is used for firmware to pass some data to the OS, such as bootloader pass kernel boot parameters to the kernel
Reference
When we look for a node, we have to write the full node path so that it is not very convenient when a node is deeply nested, so the device tree allows us to label the nodes with references (aliases) in the following form, thereby eliminating the lengthy path. This allows the effect of similar function calls to be implemented. When compiling the device tree, the different attribute information of the same node is merged, the same attributes of the same node are rewritten, and references can be used to avoid the porting of the nodes around, directly at the board level. DTS can be changed.
The following example directly references a node in DTSi and adds/modifies new property information to it
KEY
In the device tree, a key-value pair is a way to describe a property, for example, a Linux driver can find a device node through the "compatible" attribute in the device node.
The Linux device tree syntax defines a number of attributes that are canonical, including:compatible, address, interrupt , etc., which can be found when the kernel initializes a node. Automatic parsing generates the appropriate device information. In addition, there are some Linux kernel defined, a class of devices common with the default meaning of the property, these properties can not be automatically parsed by the kernel to generate the corresponding device information, but the kernel has been written by the corresponding analytic extraction function, the common "mac_addr"," Gpio "," Clock "," Power ". "Regulator" and so on.
Compatible
The corresponding node information in the device node has been constructed as a struct platform_deviceby the kernel. The driver can extract information from the corresponding function. The compatible property is one of the methods used to find nodes, and you can also find the specified node by node name or node path . The dm9000 driver uses the following function to extract the corresponding information through the "compatible" attribute in the device node, so the strings need to be strictly matched.
In the following example of this dm9000, we found this block of code in the corresponding board-level DTS:
Then we take the kernel source to find the dm9000 network card driver, which can be found that this driver is used by the device tree description of the device information (this is not nonsense, obviously with the device tree benefits a lot). We can find the structure used to describe the device information, and it can be seen that the compatible used for matching structures in the drive is exactly the same as in the device tree, otherwise it may not match, and the other point here is the struct of_device_id the last member of the array must be empty, because the associated operation API reads the array until it encounters an empty one.
Address
(almost) All devices need to be connected to the IO ports of the CPU, so their IO port information needs to be described in the Device node node. The common properties are
- #address-cells, the number of cells used to describe the first address in the Address table of the child node "reg" attribute ,
- #size-cells, the number of cells used to describe the address length in the Address table of the child node "Reg" property .
With these two properties, "Reg" in a child node can describe a contiguous range of addresses. In the following example, the parent node specifies the #address-cells = <2>; #size-cells = <1>, the reg in the child node Dev-bootscs0 The first two numbers in the mbus_id represent an address, that is, 0xf0, 0x01 , and 0x1045c, and the last number represents the address span, which is the 0x4
Interrupts
A large number of devices in a computer system interrupt the request for CPU service, so the device node needs to specify the interrupt number. The common properties are
- Interrupt-controller An empty attribute is used to declare the node receive interrupt signal, that is, this node is an interrupt controller.
- #interrupt-cells, which is the attribute of the interrupt Controller node, is used to identify the controller that requires several units to do the interrupt descriptor, which describes the "interrupts" attribute in the child node using the parent node the specific value of the interrupts property . In general, if the value of this property of the parent node is 3, then the child node's interrupts three 32bits integer values for a cell are:< interrupt domain interrupt triggering method, if the parent node is 2, it is the < interrupt trigger mode >
- interrupt-parent, identifies which interrupt controller this device node belongs to, and if this property is not set, it is automatically attached to the parent node's
- interrupts, a list of interrupt identifiers representing each of the output signals
The part of the device tree that is interrupted is much more,Interrupt-controller indicates that the node is an interrupt controller, and it is important to note that there may be more than one interrupt controller in one SOC, which involves many concepts of the device tree interrupting the organization. The following is a description of the interrupt controller (GIC) node for exynos4412 in the file "Arch/arm/boot/dts/exynos4.dtsi" :
To say interrupt-parent, we must first of all talk about the evolution of design ideas for interrupts in Linux device management. With the development of Linux kernel, the concept of interrupt controller abstraction into irqchip in the kernel is becoming more and more popular, even the Gpio controller can be seen as a interrupt Controller chip, so that there are at least two interrupt controllers in the system, in addition, on the hardware, as the system complexity increases, peripheral interrupt data increase, in fact, the system can require multiple interrupt controller cascade to form a de facto hardware interrupt processing structure:
In this trend, the original interrupt source in the kernel directly to the interrupt number is difficult to continue to develop, in order to solve these problems, the Linux kernel to create a IRQ domain (interrupt domain) this concept. Domain in the kernel there are many, in addition to Irqdomain, there is power domain,clock domain and so on, so-called domain, is the domain, the meaning of the scope, that is, any definition of this range is meaningless. As mentioned above, all interrupt controllers in the system form a tree structure, and for each interrupt controller can connect interrupt requests for several peripherals (interrupt source, interrupt source), interrupt The controller will number (i.e. HW interrupt ID) on the interrupt source connected to it, based on its physical characteristics in the interrupt controller. IRQ domain , this number is limited to the scope of this interrupt controller only , with such a design, the CPU (Linux kernel) can find the interrupt to be accessed at the level of the Cascade rules. Of course, usually we are concerned about only the core of the interrupt number, the specific interrupt number is how to find the corresponding interrupt source, we as programmers often do not need to care, in addition to writing the device tree, the device tree is to describe the embedded software development involved in all the hardware information, so, The device tree needs to accurately describe the tree structure on which the interrupts are handled on the hardware, so there is the concept of our Interrupt-parant , which is used to connect the hierarchy of such a tree structure, Used to indicate which interrupt controller the interrupt belongs to, such as a key that is connected to a Gpio, which is organized as:
Interrupt Source --interrupt parent-->GPIO--interrupt parent-->GIC1--interrupt parent--> GIC2--...-->CPU
With Parant, we can use a first-level offset to finally get the absolute number of the current interrupt, as you can see, in the dm9000 device node on my board, its "interrupt-parent" references gpx0 node in "Exynos4x12-pinctrl.dtsi"(Exynos4412.dtsi included by the board-level device tree):
In the gpx0 node, "#interrupt-cells = <2>;"is specified, so the properties in dm9000 "interrupts = <6 4>;" Represents the interrupt offset in the dm9000 of the interrupt in the gpx0 of the IRQ parant, the "interrupts" in the attribute "<0" in the gpx0, By checking the exynos4412 's manual, the corresponding interrupt number is eint[6].
Gpio
Gpio is also the most common IO port, and the commonly used attributes are
- "Gpio-controller"to indicate that the node describes a GPIO controller
- "#gpio-cells", used to describe the properties of a gpio using a node, the contents of a cell, that is, ' attribute = <& Reference gpio node alias Gpio label working mode >
The Gpio setting also uses the idea of the above offset , such as the device book for the LED below, which represents the 7th pin using the GPX2 group:
Drive Custom Key
For specific devices, some of the properties are difficult to achieve common, need to drive their own definition, through the kernel's attributes to extract the analytic function to obtain the value, such as the following sentence in the dm9000 node is a custom node property, to indicate that the configuration EEPROM is not available.
VALUE
DTS describes the value of a key in a number of ways, of course, a key can also have no value
String information
32bit unsigned integer array information
Binary number Array
String hash table
Mixed form
Some of the above mixed forms
Device tree/Drive porting instance
The device tree is for the drive service, and after configuring the device tree, you also need to configure the appropriate driver to detect whether the configuration is correct. For example, dm9000 network card, you need to first attach the sample information to our board-level device tree, and according to the chip manual and circuit schematic diagram of the corresponding properties are configured, and then configure the corresponding driver. Note that the dm9000 address line is generally connected to the chip selection line, so the device tree should belong to the corresponding slice line node, I use the exynos4412 here, connected to the BANK1, so is "<0x50000000 0x2 0x50000004 0x2> "
The final configuration results are:
Tick the appropriate option to compile the dm9000 driver into the kernel.
make menuconfig[*] Networking support ---> Networking Options ---> <*> Packet socket <*>unix domain sockets [*] TCP/IP networking [*] Ip:kernel level autoconfigurationdevice Drivers ---> [* ] Network Device Support ---> <*> DM9000 supportfile systems ---> [*] Network File Systems (NEW) ---> <*> NFS Client Support [*] NFS Client Support for NFS version 3 [*] NFS Client Support for the NFSv3 ACL protocol Exten Sion [*] Root file system on NFS
Execute make uImage;make dtbs
, tftp download, successfully load NFS root file system and enter system, indicating successful NIC porting
Linux Device Tree Syntax detailed