设备树基本语法:
下载网址: File:Power ePAPR APPROVED v1.1.pdf - eLinux.org
soc厂商一般会提供.dts文件,我们需要新增或者修改设备树;
设备树的头文件 .dtsi文件
以zcu102为例: 在内核源码中有三个设备树文件:
zynqmp-zcu102-revB.dts zynqmp-zcu102-revA.dts zynqmp-zcu102-rev1.0.dts
zynqmp-zcu102-revA.dts: dtsi是dts的头文件 但也可以用#include 引用.h和dts文件
#include "zynqmp.dtsi"
#include "zynqmp-clk-ccf.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
#include <dt-bindings/phy/phy.h>
设备树举例: 这个是赛灵思的设备树zcu102的源码截取
#include "zynqmp.dtsi"
#include "zynqmp-clk-ccf.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
#include <dt-bindings/phy/phy.h>
/ {
model = "ZynqMP ZCU102 RevA";
compatible = "xlnx,zynqmp-zcu102-revA", "xlnx,zynqmp-zcu102", "xlnx,zynqmp";
aliases {
ethernet0 = &gem3;
gpio0 = &gpio;
i2c0 = &i2c0;
i2c1 = &i2c1;
mmc0 = &sdhci1;
rtc0 = &rtc;
serial0 = &uart0;
serial1 = &uart1;
serial2 = &dcc;
spi0 = &qspi;
usb0 = &usb0;
};
chosen {
bootargs = "earlycon";
stdout-path = "serial0:115200n8";
};
memory@0 {
device_type = "memory";
reg = <0x0 0x0 0x0 0x80000000>, <0x8 0x00000000 0x0 0x80000000>;
};
}
设备节点:
每个节点都是一个设备 括号中包含的是这个设备对应一些属性信息;
例如上方: aliases chosen memory@0 /
每个节点都是由 “{}”包含,并且以分号结束;
“/” : 表示根节点;设备树的起始节点;剩下的都是根节点的子节点;可以看到引用了zynqmp.dtsi设备树文件,这个也是以跟文件开头的; 最终这个文件的根节点会和zynqmp.dtsi 中定义的跟文件合并,如何合并呢??之后会说;
命名方式: label :节点名 @ 地址
label : 方便访问这个节点整的一个标签;其他设备树文件或者节点引用的时候使用&label方式访问
属性介绍
每个节点都有不同的属性,属性值都是键值对(也就是名字和值),值可以是空或者任意的字节流;
常见的:
字符串 compatible = "xlnx,zynqmp-zcu102-revA";
字符串列表 compatible = "xlnx,zynqmp-zcu102-revA", "xlnx,zynqmp-zcu102";
32位无符号整型 reg = <0x0 0x0 0x0 0x80000000> ;
compatible: 非常重要的属性,这个值是一个字符串或者字符串列表; 驱动找设备树中对应的设备时就是通过这个属性来匹配的。
"xlnx,pinctrl-zynqmp" xInx :表示厂商, pinctrl-zynqmp:表示驱动模块名
如:xinx pinctrl中compatible列表 : "xlnx,zynqmp-pinctrl" "xlnx,pinctrl-zynqmp"
static const struct of_device_id zynqmp_pinctrl_of_match[] = {
{ .compatible = "xlnx,zynqmp-pinctrl" },
{ .compatible = "xlnx,pinctrl-zynqmp" },
{ }
};
static struct platform_driver zynqmp_pinctrl_driver = {
.driver = {
.name = "zynqmp-pinctrl",
.of_match_table = zynqmp_pinctrl_of_match,
},
.probe = zynqmp_pinctrl_probe,
.remove = zynqmp_pinctrl_remove,
};
static int __init zynqmp_pinctrl_init(void)
{
return platform_driver_register(&zynqmp_pinctrl_driver);
}
arch_initcall(zynqmp_pinctrl_init);
status:
值 | 描述 |
“okay” | 表明设备是可操作的。 |
“disabled” | 表明设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备 插入以后。至于 disabled 的具体含义还要看设备的绑定文档。 |
“fail” | 表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可 操作。 |
“fail-sss” | 含义和“fail”相同,后面的 sss 部分是检测到的错误内容。 |
reg属性:
一般是地址和长度成对出现,也有只含有地址的,比如i2c的设备地址。
一般用来描述设备的地址空间
其属性中的地址个数和长度个数依赖于 #address-cells 和 #size-cells属性,之后介绍;
一般形式:
reg = <address1 length1 address2 length2 address3 length3……>
#address-cells 和#size-cells 属性:
#address-cells: 决定了子节点中reg属性中地址信息所占用的字长(32位);
#size-cells: 决定了子字节中reg属性中长度信息所占用的字长(32位);
&eeprom {
#address-cells = <1>;
#size-cells = <1>;
board_sn: board-sn@0 {
reg = <0x0 0x14>;
};
eth_mac: eth-mac@20 {
reg = <0x20 0x6>;
};
board_name: board-name@d0 {
reg = <0xd0 0x6>;
};
board_revision: board-revision@e0 {
reg = <0xe0 0x3>;
};
};
如上述: board_sn节点
因为父节点中 #address-cells = <1>; #size-cells = <1>;
所以reg中 <address1 length1 address2 length2 address3 length3>;
0x0 表示address1 0x14表示length1
如果子节点属性中有range: ranges = <0x0 0x3000000 0x3000>;
1、ranges属性值的格式 <local地址, parent地址, size>, 表示将local地址向parent地址的转换。
比如对于#address-cells和#size-cells都为1的话,以<0x0 0x10 0x20>为例,表示将local的从0x0~(0x0 + 0x20)的地址空间映射到parent的0x10~(0x10 + 0x20)
其中,local地址的个数取决于当前含有ranges属性的节点的#address-cells属性的值,size取决于当前含有ranges属性的节点的#size-cells属性的值。
而parent地址的个数取决于当前含有ranges属性的节点的parent节点的#address-cells的值。
2、对于含有ranges属性的节点的子节点来说,其reg都是基于local地址的
3、ranges属性值为空的话,表示1:1映射
4、对于没有ranges属性的节点,代表不是memory map区域
根节点中compatible属性:
其他设备节点中的compatible属性是用来匹配设备的,根节点使用匹配
根节点有两个属性是干嘛用的?:
model = "ZynqMP ZCU102 RevA";
compatible = "xlnx,zynqmp-zcu102-revA", "xlnx,zynqmp-zcu102", "xlnx,zynqmp";
model 表示设备树的名字;
compatible 用来匹配对应的平台, 通过在u-boot传入给内核的dtb参数中找寻匹配的平台设备树。linux初始化过程中会定义一个section;
如下: zynq_dt_match 就是用来匹配支持的设备树平台 arch\arm\mach-xxxx common.c
DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
/* 64KB way size, 8-way associativity, parity disabled */
#ifdef CONFIG_XILINX_PREFETCH
.l2c_aux_val = 0x30400000,
.l2c_aux_mask = 0xcfbfffff,
#else
.l2c_aux_val = 0x00400000,
.l2c_aux_mask = 0xffbfffff,
#endif
.smp = smp_ops(zynq_smp_ops),
.map_io = zynq_map_io,
.init_irq = zynq_irq_init,
.init_machine = zynq_init_machine,
.init_late = zynq_init_late,
.init_time = zynq_timer_init,
.dt_compat = zynq_dt_match,
.reserve = zynq_memory_init,
MACHINE_END
static const char * const zynq_dt_match[] = {
"xlnx,zynq-7000",
NULL
};
参考: 根节点中compitable 作用 他参考的正点原子的讲解;