文章目录
参考链接:
https://kernel.meizu.com/device-tree.html
https://zhuanlan.zhihu.com/p/143167176
DTS语法
- DeviceTree的结构非常简单,由两种元素组成:Node(节点)、Property(属性)
- Node节点。在DTS中使用一对花括号”node-name{}”来定义
- Property属性。在Node中使用”property-name=value”字符串来定义
标准的property
Property的格式为”property-name=value”,其中value的取值类型如下:
Value | 描述 |
---|---|
Property值为空,用property本身出现或者不出现来表示一个treue/false值 | |
32bit的值,用大端格式存储 | |
64bit的值,用大端格式存储 | |
字符串 | |
混合编码,自定义property的值 | |
作为一个句柄指向一个Node,用来引用Node | |
字符串数组 |
- 文本字符串(无结束符)可以用双引号表示:string-property = “a string”;
- 无符号整数,用尖括号限定:cell-property = <0xbeef 123 0xabcd1234>;
- 二进制数据用方括号限定:binary-property = [0x01 0x23 0x45 0x67];
- 不同表示形式的数据可以使用逗号连在一起:mixed-property = “a string”, [0x01 0x23 0x45 0x67], <0x12345678>;
- 逗号也可用于创建字符串列表:string-list = “red fish”, “blue fish”;
compatible属性
- “compatible”属性通常用来device和driver的适配,推荐的格式为”manufacturer,model”,如:compatible = “fsl,mpc8641”, “ns16550”;
model属性
- “model”属性只是简单的表示型号,root节点用其来传递值给machine_desc_str,如:model = “fsl,MPC8349EMITX”;
phandle属性
- “phandle”属性通用一个唯一的id来标识一个Node,在property可以使用这个id来引用Node,如:phandle = <1>;
- 在DeviceTree中通过另一种方式进行phandle的定义和引用,定义一个“label:”,通过"&“来引用"label”,在编译是系统会自动为node生成一个phandle属性,如:cpu0: cpu@0{…},cpu = <&cpu0>;
#address-cells、#size-cells属性
- “#address-cells, #size-cells”属性用来定义当前node的子node中”reg”属性的解析格式
- #address-cells和#size-cells属性不会从设备树中的父节点继承
- 1.如果node”soc”中”#address-cells=<1>”、”#size-cells=<1>”,那么子node”serial”中”reg”属性的解析为“addr1 = 0x0, size1 = 0x100, addr2 = 0x0, size2 = 0x200”
soc {
#address-cells = <1>;
#size-cells = <1>;
serial {
reg = <0x0 0x100 0x0 0x200>;
}
}
- 2.如果node”soc”中”#address-cells=<2>”、”#size-cells=<2>”,那么子node”serial”中”reg”属性的解析为“addr1 = 0x100, size1 = 0x200”
soc {
#address-cells = <2>;
#size-cells = <2>;
serial {
reg = <0x0 0x100 0x0 0x200>;
}
}
- 3.如果node”soc”中”#address-cells=<2>”、”#size-cells=<0>”,那么子node”serial”中”reg”属性的解析为“addr1 = 0x100, addr2 = 0x200”
soc {
#address-cells = <2>;
#size-cells = <0>;
serial {
reg = <0x0 0x100 0x0 0x200>;
}
}
regs属性
- “reg”属性解析出”address,length”数字,解析格式依据父节点的”#address-cells、#size-cells”定义
- reg 属性描述设备资源在其父总线定义的地址空间内的地址
- 任意数目的地址和长度对组成[地址 长度],由设备节点的父节点中#address-cells和#size-cells属性指定。如果父节点#size-cells值 为0,则应省略 reg 值中的长度字段。
- 假设系统内的设备有两个寄存器块,偏移 0x3000 的 32 字节块和偏移 0xFE00 的 256 字节块。reg 属性的编码方式如下(假设#address-cells和#size-cells值为 1):reg = <0x3000 0x20 0xFE00 0x100>;
ranges属性
- ranges提供了一种在总线的地址空间(子地址空间)和总线节点的父节点(父地址空间)的地址空间之间定义映射或转换的方法
- 格式为(child-bus-address, parentbus-address, length)
- child-bus-address是子总线地址空间内的物理地址。表示地址的单元数与总线相关,可以从该节点的#address-cells(显示范围属性的节点)确定
- parentbus-address是父总线地址空间中的物理地址。表示父地址的单元数与总线相关,可以从定义父地址空间的节点的#address-cells属性确定
- length指定子地址空间中范围的大小。表示大小的单元数可以从该节点的#size-cells(显示范围属性的节点)确定
- 如果属性使用值定义,则指定父地址空间和子地址空间相同,并且不需要地址转换
- 如果该属性不存在于总线节点中,则假定节点的子节点和父地址空间之间不存在映射
{
...
#address-cells = <1>;
#size-cells = <1>;
...
soc {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
ranges = <0x0 0x0 0x10100000 0x10000
0x1 0x0 0x10160000 0x10000
0x2 0x0 0x30000000 0x10000
>;
ethernet@0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
};
i2c@1,0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
rtc@58 {
compatible = "maxim,ds1338";
reg = <58>;
};
};
flash@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
}
//child-bus-address:0 0或1 0或2 0(因为soc的#address-cells = <2>)
//parentbus-address:0x10100000或0x10160000或0x30000000(因为soc的父节点#address-cells =<1>)
//length:0x10000(因为soc的#size-cells = <1>)
ranges = <0x1 0x0 0x10160000 0x10000>对应i2c@1,0的reg = <1 0 0x1000>
此属性值指定在开始地址0x10160000,大小0x10000 地址空间范围,以物理 地址1寻址的子节点映射到物理 0x10160000的父地址。通过此映射,挂载设备1的节点可以通过负载或存储地址 0、0x1000(在 reg 中指定)的偏移量以及范围中指定的 0x10160000映射进行寻址
status属性
status属性指示设备的运行状态
- “okay”:指示设备正在运行
- “disabled”:表示该设备当前无法运行,但是将来可能会运行(比如未插入或关闭的某些设备)
- “reserved”:表示设备可运行,但不应使用。通常,它用于由另一个软件组件(例如平台固件)控制的设备
- “fail”:表示设备无法运行。在设备中检测到严重错误,且不进行修复就无法运行
- “fail-sss”:表示设备无法运行。在设备中检测到严重错误,且如果不进行修复就无法开始运行。sss的部分指定设备,并指示侦测到的错误情况
dts的中断
产生中断的设备(device)
- interrupts:定义设备的中断解析,根据其”interrupt-parent”node中定义的“#interrupt-cells”来解析, 会被interrupts-extended覆盖, 通常两者用其一
- interrupt-parent: 用来制定当前设备的Interrupt Controllers/Interrupt Nexus,phandle指向对应的node, 如果没有设置这个属性, 会自动依附父节点的
- interrupts-extended: 当设备连接到多个中断控制器时使用; 与interrupts相互排斥,当两者都存在时, interrupts-extended优先
中断控制器
- #interrupt-cells: 用来规定连接到该中断控制器上的设备的”interrupts”属性的解析长度
- interrupt-controller: 一个空属性,用来声明当前node为中断控制器
关联属性(nexus properties),实现从一个interrupt domain转化到另一个interrupt domain
- interrupt-map: 用来描述interrupt nexus设备对中断的路由,解析格式为5元素序列“child unit address, child interrupt specifier, interrupt-parent, parent unit address, parent interrupt specifier”
interrupt-map = <child_unit_address child_interrupt_specifier interrupt_parent parent_unit_address parent_interrupt_specifier>
//child_unit_address:被映射的子节点的单元地址。cells长度由子节点的“#address-cells”指定
//child_interrupt_specifier: 被映射的子节点的中断说明符。 cells长度由子节点的“#interrupt-cells”指定
//interrupt_parent: phandle指向interrupt controller的引用
//parent_unit_address:父中断域中的单元地址。 cells长度由父节点的“#address-cells”指定
//parent_interrupt_specifier: 父域中的中断说明符。 cells长度由父节点的“#interrupt-cells”指定
- interrupt-map-mask: 与"interrupt-map"执行&操作,cell的数量取决自身节点的"#address-cells"
- #interrupt-cells: 用来规定连接到该中断控制器上的设备的”interrupts”属性的解析长度
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
open-pic {
clock-frequency = <0>;
interrupt-controller;
#address-cells =<0>;
#interrupt-cells = <2>;
};
pci {
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map = <
/* IDSEL 0x11 - PCI slot 1 */
0x8800 0 0 1 &open-pic 2 1 /* INTA */
0x8800 0 0 2 &open-pic 3 1 /* INTB */
0x8800 0 0 3 &open-pic 4 1 /* INTC */
0x8800 0 0 4 &open-pic 1 1 /* INTD */
/* IDSEL 0x12 - PCI slot 2 */
0x9000 0 0 1 &open-pic 3 1 /* INTA */
0x9000 0 0 2 &open-pic 4 1 /* INTB */
0x9000 0 0 3 &open-pic 1 1 /* INTC */
0x9000 0 0 4 &open-pic 2 1 /* INTD */
>;
};
};
//child unit address: 0x8800 0 0 (因为: #address-cells = <3>;)
//child interrupt specifiler: 1 (因为: #interrupt-cells = <1>;)
//interrupt-parent: &open-pic
//parent unit address: empty (因为open-pic的#address-cells =<0>;)
//parent interrupt specifier: 2 1 (因为open-pic的#interrupt-cells = <2>)
标准Node
Node Name常常由两部分组成“node-name@unit-address”,主要是为了防止Node Name重复冲突
- “node-name”是node的名字
- “unit-address”是node中“reg”属性描述的开始地址
Root node
每个DeviceTree只有一个根节点。根节点需要有以下必备属性:
属性名 | 描述 |
---|---|
#address-cells | 定义子node中”reg”属性的address cells长度 |
#size-cells | 定义子node中”reg”属性的address_size cells长度 |
model | root节点用其来传递值给machine_desc_str |
compatible | 用于在内核启动匹配对应的machine ID |
/aliases node
用来给一些绝对路径定义别名
aliases {
serial0 = "/simple-bus@fe000000/serial@llc500";
ethernet0 = "/simple-bus@fe000000/ethernet@31c000";
};
/memory node
用来传递内存布局
\ {
#address-cells = <2>;
#size-cells = <2>;
memory@0 {
device_type = "memory";
reg = <0x000000000 0x00000000 0x00000000 0x80000000
0x000000001 0x00000000 0x00000001 0x00000000>;
};
}
/chosen node
其中“bootargs”属性用来传递cmdline参数,“stdout-path”属性用来指定标准输出设备,“stdin-path”属性用来指定标准输入设备
/* chosen */
chosen {
bootargs = "console=tty0 console=ttyMT0,921600n1 root=/dev/ram";
};
/cpus node
/cpus节点也是必须有的
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a35";
reg = <0x000>;
enable-method = "psci";
cpu-idle-states = <&LEGACY_MCDI &LEGACY_SODI &LEGACY_SODI3 &LEGACY_DPIDLE>,
<&LEGACY_SUSPEND &MCDI &SODI &SODI3 &DPIDLE &SUSPEND>;
cpu-release-addr = <0x0 0x40000200>;
clock-frequency = <1248000000>;
};
cpu1: cpu@001 {
device_type = "cpu";
compatible = "arm,cortex-a35";
reg = <0x001>;
enable-method = "psci";
cpu-idle-states = <&LEGACY_MCDI &LEGACY_SODI &LEGACY_SODI3 &LEGACY_DPIDLE>,
<&LEGACY_SUSPEND &MCDI &SODI &SODI3 &DPIDLE &SUSPEND>;
cpu-release-addr = <0x0 0x40000200>;
clock-frequency = <1248000000>;
};
cpu2: cpu@002 {
device_type = "cpu";
compatible = "arm,cortex-a35";
reg = <0x002>;
enable-method = "psci";
cpu-idle-states = <&LEGACY_MCDI &LEGACY_SODI &LEGACY_SODI3 &LEGACY_DPIDLE>,
<&LEGACY_SUSPEND &MCDI &SODI &SODI3 &DPIDLE &SUSPEND>;
cpu-release-addr = <0x0 0x40000200>;
clock-frequency = <1248000000>;
};
cpu3: cpu@003 {
device_type = "cpu";
compatible = "arm,cortex-a35";
reg = <0x003>;
enable-method = "psci";
cpu-idle-states = <&LEGACY_MCDI &LEGACY_SODI &LEGACY_SODI3 &LEGACY_DPIDLE>,
<&LEGACY_SUSPEND &MCDI &SODI &SODI3 &DPIDLE &SUSPEND>;
cpu-release-addr = <0x0 0x40000200>;
clock-frequency = <1248000000>;
};
cpu4: cpu@100 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x100>;
enable-method = "psci";
cpu-idle-states = <&LEGACY_MCDI &LEGACY_SODI &LEGACY_SODI3 &LEGACY_DPIDLE>,
<&LEGACY_SUSPEND &MCDI &SODI &SODI3 &DPIDLE &SUSPEND>;
cpu-release-addr = <0x0 0x40000200>;
clock-frequency = <1378000000>;
};
cpu5: cpu@101 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x101>;
enable-method = "psci";
cpu-idle-states = <&LEGACY_MCDI &LEGACY_SODI &LEGACY_SODI3 &LEGACY_DPIDLE>,
<&LEGACY_SUSPEND &MCDI &SODI &SODI3 &DPIDLE &SUSPEND>;
cpu-release-addr = <0x0 0x40000200>;
clock-frequency = <1378000000>;
};
cpu6: cpu@102 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x102>;
enable-method = "psci";
cpu-idle-states = <&LEGACY_MCDI &LEGACY_SODI &LEGACY_SODI3 &LEGACY_DPIDLE>,
<&LEGACY_SUSPEND &MCDI &SODI &SODI3 &DPIDLE &SUSPEND>;
cpu-release-addr = <0x0 0x40000200>;
clock-frequency = <1378000000>;
};
cpu7: cpu@103 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x103>;
enable-method = "psci";
cpu-idle-states = <&LEGACY_MCDI &LEGACY_SODI &LEGACY_SODI3 &LEGACY_DPIDLE>,
<&LEGACY_SUSPEND &MCDI &SODI &SODI3 &DPIDLE &SUSPEND>;
cpu-release-addr = <0x0 0x40000200>;
clock-frequency = <1378000000>;
};
cpu8: cpu@200 {
device_type = "cpu";
compatible = "arm,cortex-a73";
reg = <0x200>;
enable-method = "psci";
cpu-idle-states = <&LEGACY_MCDI &LEGACY_SODI &LEGACY_SODI3 &LEGACY_DPIDLE>,
<&LEGACY_SUSPEND &MCDI &SODI &SODI3 &DPIDLE &SUSPEND>;
cpu-release-addr = <0x0 0x40000200>;
clock-frequency = <1638000000>;
};
cpu9: cpu@201 {
device_type = "cpu";
compatible = "arm,cortex-a73";
reg = <0x201>;
enable-method = "psci";
cpu-idle-states = <&LEGACY_MCDI &LEGACY_SODI &LEGACY_SODI3 &LEGACY_DPIDLE>,
<&LEGACY_SUSPEND &MCDI &SODI &SODI3 &DPIDLE &SUSPEND>;
cpu-release-addr = <0x0 0x40000200>;
clock-frequency = <1638000000>;
};
cpu-map {
cluster0 {
core0 {
cpu = <&cpu0>;
};
core1 {
cpu = <&cpu1>;
};
core2 {
cpu = <&cpu2>;
};
core3 {
cpu = <&cpu3>;
};
};
cluster1 {
core0 {
cpu = <&cpu4>;
};
core1 {
cpu = <&cpu5>;
};
core2 {
cpu = <&cpu6>;
};
core3 {
cpu = <&cpu7>;
};
};
cluster2 {
core0 {
cpu = <&cpu8>;
};
core1 {
cpu = <&cpu9>;
};
};
};
idle-states {
entry-method = "arm,psci";
LEGACY_MCDI: legacy-mcdi {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x0000001>;
entry-latency-us = <600>;
exit-latency-us = <600>;
min-residency-us = <1200>;
};
LEGACY_SODI: legacy-sodi {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x0000002>;
entry-latency-us = <600>;
exit-latency-us = <600>;
min-residency-us = <1200>;
};
LEGACY_SODI3: legacy-sodi3 {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x0000003>;
entry-latency-us = <600>;
exit-latency-us = <600>;
min-residency-us = <1200>;
};
LEGACY_DPIDLE: legacy-dpidle {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x0000004>;
entry-latency-us = <600>;
exit-latency-us = <600>;
min-residency-us = <1200>;
};
LEGACY_SUSPEND: legacy-suspend {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x0000005>;
entry-latency-us = <600>;
exit-latency-us = <600>;
min-residency-us = <1200>;
};
MCDI: mcdi {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x0010001>;
entry-latency-us = <600>;
exit-latency-us = <600>;
min-residency-us = <1200>;
};
SODI: sodi {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x1010002>;
entry-latency-us = <800>;
exit-latency-us = <1000>;
min-residency-us = <2000>;
};
SODI3: sodi3 {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x1010003>;
entry-latency-us = <800>;
exit-latency-us = <1000>;
min-residency-us = <2000>;
};
DPIDLE: dpidle {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x1010004>;
entry-latency-us = <800>;
exit-latency-us = <1000>;
min-residency-us = <2000>;
};
SUSPEND: suspend {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x1010005>;
entry-latency-us = <800>;
exit-latency-us = <1000>;
min-residency-us = <2000>;
};
};
};