系统总线为树干,主线连接的 设备控制器为分支, 设备为分支上的树枝,设备树相当于stm32的数据手册。
图源:正点原子.
/ {
//根节点——树干
compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";
//分支
cpus {
#address-cells = <1>;
#size-cells = <0>;
//树枝
//CPU0 节点
cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
};
};
//soc 节点
soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges;
//ocram 节点
ocram: sram@00900000 {
compatible = "fsl,lpm-sram";
reg = <0x00900000 0x20000>;
};
}
}
DTS文件
设备树源码文件
语法
头文件
.h
、.dtsi
和.dts
文件
.dtsi
文件:SOC 的内部外设信息
设备节点
根节点:/
子节点:aliases
、cpus
和 intc
等
命名
- 节点名称@设备地址(寄存器首地址)
interrupt-controller@00a01000
cpu@0
- 节点标签:节点名称@地址
cpu0:cpu@0
可以用&cpu0
访问节点
节点属性
- compatible——兼容性,匹配内核中的驱动程序
compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
//设备名称,soc名称
- model——模块信息(名称等)
- status——设备状态
- reg——外设的寄存器起始地址和地址长度
reg = <0x02020000 0x4000>; //起始地址 长度
- #address-cells——reg属性中起始地址的字长
- #size-cells——reg属性中地址长度的字长
#address-cells = <1>;
#size-cells = <0>;
在reg的父节点处设置
aips3: aips-bus@02200000 {
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
dcp: dcp@02280000 {
compatible = "fsl,imx6sl-dcp";
reg = <0x02280000 0x4000>;
};
};
- range——地址映射/转换表
ranges; //空:子地址空间和父地址空间完全相同,不需要进行地址转换
或
ranges = <0x0 0xe0000000 0x00100000>;
//三个数值分别为child-bus-address(子总线地址空间的物理地址),parent-bus-address(父总线地址空间的物理地址),length
- name——节点名字
节点属性的数据形式
- 字符串
compatible = "arm,cortex-a7";
-
32位unsigned int
-
字符串列表
compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand";
设备匹配
Linux内核用DT_MACHINE_START
和MACHINE_END
来定义一个 machine_desc
结构体来描述这个设备
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
某个设备(板子)根节点“/”的 compatible
属性值=imx6ul_dt_compat
表中的任何一个值,表示 Linux 内核支持此设备。
Linux 内核找到匹配的 machine_desc
:用设备树根节点的compatible
属性值和 Linux 内核中 machine_desc
下.dt_compat
的值比较,如果相等的话就表示找到匹配的 machine_desc
。
arch_get_next_mach
函数:获取 Linux 内核中下一个machine_desc
结构体。
添加设备——添加子节点
在设备树文件.dst
中添加
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
mag3110@0e {
compatible = "fsl,mag3110";
reg = <0x0e>;
position = <2>;
};
fxls8471@1e {
compatible = "fsl,fxls8471";
reg = <0x1e>;
position = <0>;
interrupt-parent = <&gpio5>;
interrupts = <0 8>;
};
};
查看设备属性值——绑定文档
绑定文档:在Linux 内核源码中,描述如何添加节点的.txt
文档,、路径为:Linux 源码目录/Documentation/devicetree/bindings
在系统文件中查看设备树
根节点
cd /
cd /proc/device-tree
ls
可以看到根节点属性和它的子节点
查看属性值
cat model
cat compatible
特殊子节点
- aliases——定义节点别名,方便访问
- chosen——uboot写入数据
DTB文件
DTS 编译以后得到的二进制文件
DTC工具
将.dts
编译为.dtb
进入Linux 源码根目录
make dtbs
arch/arm/boot/dts/Makefile
查看对应开发板所要编译的DTS文件
OF函数
用于获取设备树中的节点或者属性信息,前缀为of_
,在 include/linux/of.h
中定义。
节点结构体
struct device_node {
const char *name; /* 节点名字 */
const char *type; /* 设备类型 */
phandle phandle;
const char *full_name; /* 节点全名 */
struct fwnode_handle fwnode;
struct property *properties; /* 属性 */
struct property *deadprops; /* removed 属性 */
struct device_node *parent; /* 父节点 */
struct device_node *child; /* 子节点 */
struct device_node *sibling;
struct kobject kobj;
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
const char *path_component_name;
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
of_find_node_by_name
函数通过节点名字查找指定的节点
of_find_node_by_type
函数通过 device_type 属性查找指定的节点
of_find_compatible_node
函数根据 device_type 和 compatible 这两个属性查找指定的节点
of_find_matching_node_and_match
函数通过 of_device_id 匹配表来查找指定的节点
of_find_node_by_path
函数通过路径来查找指定的节点
of_get_parent
函数用于获取指定节点的父节点(如果有父节点的话)
of_get_next_child
函数用迭代的方式查找子节点
of_find_property
函数用于查找指定的属性
of_property_count_elems_of_size
函数用于获取属性中元素的数量
of_property_read_u32_index
函数用于从属性中获取指定标号的 u32 类型数据值(无符号 32位)
of_property_read_u8_array 函数
of_property_read_u16_array 函数
of_property_read_u32_array 函数
of_property_read_u64_array 函数
一次读取出 reg 属性中的所有数据
of_property_read_u8 函数
of_property_read_u16 函数
of_property_read_u32 函数
of_property_read_u64 函数
读取这种只有一个整形值的属性
of_property_read_string
函数用于读取属性中字符串值
of_n_addr_cells
函数用于获取#address-cells 属性值
of_device_is_compatible
检查设备兼容性
of_get_address
函数用于获取地址相关属性
of_translate_address
函数负责将从设备树读取到的地址转换为物理地址
of_address_to_resource
函数,获取内存空间结构体
of_iomap
函数用于直接内存映射