Linux driver development study notes [3]: device tree

table of Contents

1. What is a device tree

2. The relationship between DTS, DTB and DTC

Three, DTS basic syntax

Fourth, create a small device tree template

Five, the embodiment of the device tree in the system

Six, special nodes

1, aliases node

2. Choose node

Seven, special attributes

1. Compatible attribute (compatibility attribute)

2. Model attributes

3. Status attribute

4. #address-cells and #size-cells attributes

5. reg attribute

6, ranges property

7, device_type attribute

Eight, the OF operation function of the Linux kernel


1. What is a device tree

Device Tree (Device Tree) . Separating the word into "device" and "tree", the file describing the device tree is called DTS (Device Tree Source), this DTS file uses a tree structure to describe board-level devices, that is, the development board Device information, such as the number of CPUs, memory base address, which devices are connected to the IIC interface, which devices are connected to the SPI interface, etc., as shown in the figure:

 

2. The relationship between DTS, DTB and DTC

1. DTS is equivalent to .c, which is the source file of the device tree

2. The DTC tool is equivalent to the gcc compiler, which compiles .dts into .dtb. The source code of the DTC tool is in the scripts/dtc directory of the Linux kernel.

3. DTB is a binary file obtained after compiling DTS

Compile all dts files by make dtbs

You can also compile the specified dtbs, such as: make imx6ull-alientek-emmc.dtb

When compiling the dtb file, you can specify the dts device tree source file to be compiled through \arch\arm\boot\dts\Makefile

Three, DTS basic syntax

The device tree also has a header file with a .dtsi extension. You can bring up the common information of a SOC and all other devices/platforms as a common .dtsi file

1, DTS also  start, / is the entire device with node tree

2. Describe the device information from the root node

 

3. There are some statements like &cpu0 outside the root node that are "append"

 

4. Node naming

label:node-name@unit-address

label: It is the label of the node, followed by the name, it is optional, for example

intc: interrupt-controller@00a01000 完整的名字是interrupt-controller@00a01000

在后面追加的时候直接使用&intc

node-name: node name

unit-address: generally the starting address of the peripheral register, sometimes it is the device address of the I2C, or other meanings, specific node specific analysis

Fourth, create a small device tree template

/dts-v1

#include .h
#include .dtsi

/ {
    /* skeleton.dtsi文件*/
    #address-cells = <1>;
    #size-cells = <1>;
    
    chosen {
      stdout-path = &uart1;  
    };
    
    aliases {
	};

	cpus {
	};

	intc: interrupt-controller@00a01000 {
	};

	clocks {
	};

	soc {
	};
 
    memory {
    };
    
    reserved-memory{
    };
    
    ...
}

Five, the embodiment of the device tree in the system

The Linux kernel will parse the DTB file when it starts, and then generate the corresponding device tree node file in the /proc/device-tree directory

How the Linux kernel parses the DTB file, the process is as follows:

Six, special nodes

1, aliases node

2. Choose node

The main purpose is to pass the value of the bootargs environment variable in uboot to the Linux kernel as a command line parameter, command line . The bootargs value in uboot is:

bootargs=console=ttymxc0,115200 root=/dev/nfs rw 
nfsroot=192.168.199.158:/home/denghengli/linux/nfs/rootfs ip=192.168.199.20:192.168.199.158:192.168.199.1:255.255.255.0::eth0:off
//说明:192.168.199.158为ubuntu主机ip,192.168.199.20为开发板ip

The linux kernel cmdline value is:

Kernel command line: console=ttymxc0,115200 root=/dev/nfs rw 
nfsroot=192.168.199.158:/home/denghengli/linux/nfs/rootfs ip=192.168.199.20:192.168.199.158:192.168.199.1:255.255.255.0::eth0:off

So how does uboot pass bootargs to the kernel?

After checking, it is found that the chosen node contains the bootargs attribute, and the attribute value is consistent with the bootargs of uboot. uboot contacted dtb, and finally started the kernel through bootz 80800000-83000000. After analysis, it is judged that uboot has the bootargs environment variable and dtb, so it is most likely to commit crimes. Finally, it is found that the chosen node will be found in the fdt_chosen function of uboot, and the bootargs attribute will be added in it, and the attribute value is the value of the bootargs variable.

Seven, special attributes

1. Compatible attribute (compatibility attribute)

(1) The value is a string. The ompatible attribute is used to bind the device and the driver. The string list is used to select the driver to be used by the device. The value format of the compatible attribute is as follows: "manufacturer, model", where manufacturer represents the manufacturer, and model is generally the driver name corresponding to the module. For example, the sound node in imx6ull-alientek-emmc.dts is the audio device node of the i.MX6U-ALPHA development board:

compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";
其中 fsl表示厂商是飞思卡尔,“imx6ul-evk-wm8960”和 imx-audio-wm8960”表示驱动模块名字。
sound这个设备首先使用第一个兼容值在 Linux内核里面查找,看看能不能找到与之匹配的驱动文件,
如果没有找到的话就使用第二个兼容值查。

(2) Generally, the driver file will have an OF matching table. This OF matching table stores some compatible values. If the compatible attribute value of the device node is equal to any value in the OF matching table, then the device can use this driver .

static const struct of_device_id imx_wm8960_dt_ids[] = {
	{ .compatible = "fsl,imx-audio-wm8960", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_wm8960_dt_ids);

static struct platform_driver imx_wm8960_driver = {
	.driver = {
		.name = "imx-wm8960",
		.pm = &snd_soc_pm_ops,
		.of_match_table = imx_wm8960_dt_ids,
	},
	.probe = imx_wm8960_probe,
	.remove = imx_wm8960_remove,
};
module_platform_driver(imx_wm8960_driver);

(3) The root node/compatible below . When the kernel is started, it will check whether it supports this platform or machine.

When the device tree is not used, the machine id is used to determine whether the kernel supports this machine:

#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
 __used \
 __attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
 
#define MACHINE_END \
};


MACHINE_START(MX35_3DS, "Freescale MX35PDK")
/* Maintainer: Freescale Semiconductor, Inc */
.atag_offset = 0x100,
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
MACHINE_END


展开以后:
static const struct machine_desc __mach_desc_MX35_3DS __used
 __attribute__((__section__(".arch.info.init"))) = {
.nr = MACH_TYPE_MX35_3DS, //机器ID
.name = "Freescale MX35PDK",
.atag_offset = 0x100,
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
};

When using the device tree, the machine ID is not used, but compatible under the root node/:

#define DT_MACHINE_START(_name, _namestr) \
static const struct machine_desc __mach_desc_##_name \
 __used \
 __attribute__((__section__(".arch.info.init"))) = { \
.nr = ~0, \
.name = _namestr,


DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)")
.map_io = imx6ul_map_io,
.init_irq = imx6ul_init_irq,
.init_machine = imx6ul_init_machine,
.init_late = imx6ul_init_late,
.dt_compat = imx6ul_dt_compat,
MACHINE_END


展开以后:
static const struct machine_desc __mach_desc_IMX6UL __used
 __attribute__((__section__(".arch.info.init"))) = {
.nr = ~0,
.name = "Freescale i.MX6 Ultralite (Device Tree)",
.map_io = imx6ul_map_io,
.init_irq = imx6ul_init_irq,
.init_machine = imx6ul_init_machine,
.init_late = imx6ul_init_late,
.dt_compat = imx6ul_dt_compat,
};

2. Model attributes

The model attribute value is also a string. Generally, the model attribute describes device module information, such as the name, such as:

model = "wm8960-audio";

3. Status attribute

The status attribute is related to the device status by looking at the name. The status attribute value is also a string, which is the status information of the device. The optional status is shown in the table.

4. #address-cells and #size-cells attributes

In devices with child nodes, it is used to describe the address information of the child nodes. The #address-cells attribute value determines the word length (32 bits) occupied by the address information in the reg attribute of the child node, and the #size-cells attribute value determines the word length (32 bits) occupied by the length information in the child node reg attribute. #address-cells and #size-cells indicate how the child node should write the reg attribute value. Generally, the reg attribute is the content related to the address, and there are two kinds of information related to the address: the start address and the length of the address, and the reg attribute Format one is:

reg = <address1 length1 address2 length2 address3 length3…………>

5. reg attribute

Generally used to describe device address space resource information, generally the register address range information of a certain peripheral

reg = <0x4600 0x100>;

6, ranges property

The value of the ranges attribute can be empty or a numeric matrix written in the format of (child-bus-address, parent-bus-address, length), ranges is an address mapping/conversion table, and each item of the ranges attribute consists of child address, parent address and address The space length consists of three parts:

child-bus-address : The physical address of the child bus address space. The #address-cells of the parent node determines the word length occupied by this physical address.

parent-bus-address : The physical address of the parent bus address space, and the word length occupied by this physical address is also determined by the #address-cells of the parent node.

length : The length of the sub-address space. The #size-cells of the parent node determines the word length occupied by this address length.

If the range attribute value is a null value, it means that the sub address space is exactly the same as the parent address space, and no address conversion is required.

7, device_type attribute

The device_type attribute value is a string, IEEE 1275 will use this attribute to describe the FCode of the device, but the device tree does not have FCode, so this attribute is also discarded. This attribute can only be used for cpu nodes or memory nodes. The cpu0 node of imx6ull.dtsi uses this attribute

Eight, the OF operation function of the Linux kernel

1. If you want to obtain the node or attribute information in the device tree in the driver, you need to use the OF function. The prototypes of these OF functions are defined in the include/linux/of.h file.

2. If the driver wants to obtain the content of the device tree node, it must first find the node.

 

 

Guess you like

Origin blog.csdn.net/m0_37845735/article/details/106976651