设备树背景
设备资源以前都是用.c文件,但是随着时间的推移。冗余代码越来越多,所以用设备树来替代资源文件的指定。
设备树在linux里的查看:
ls /sys/firmware/
devicetree fdt
#devicetree 目录下是以目录结构呈现的dtb文件,根节点对应base目录,每个节点对应一个目录,每个文件对应一个属性
官方文档:https://www.devicetree.org/specifications/
设备树文件
- dtb:内核编译号的设备树镜像
- dts:设备树的源码文件
- dtsi:厂家出的,可以包含在dts里面的设备树代码文件,语法和dts文件时一样的。
示例:
/dts-v1/;
#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"
/ {
……
};
DTS文件格式
- dts文件布局:
/dts-v1/; //表示版本
[memory reservations] //格式为: /meemreserve/ <address> <length>;
/{ //这里就是根节点,下面可以填写很多子节点
[property definitions] //根节点也有一些属性
[child nodes] //根节点的子节点
}
- 设备树中的基本单元,被称为"node",node节点的格式为:
[label:] node-name[@unit-address] {
[properties definitions]
[child nodes]
};
//label是标识,可以方便引用node
//node-name是节点的名字
//unit-address描述的是位于哪个地址
//其中用[]修饰的是可选项
- properties格式
节点都会有properties属性,它的格式一般是"name = value",但是value有多种取值方式
- array of cells:
- cell是一个32位数据,用尖括号 显示,
interrupts = <17 0xc>;
- cell是一个64位数据,
clock-frequency = <0x00000001 0x00000000>;
- cell是一个32位数据,用尖括号 显示,
- string:
- 字符串属性用双引号包围,
compatible = "simpile-bus";
- 字符串属性用双引号包围,
- bytestring:
- 字节序列用中括号包围,
local-mac-address = [00 00 12 34 56 78];
local-mac-address = [000012345678]
- 字节序列用中括号包围,
- 也可以是各种值的组合,用逗号隔开
compatible = "ns16550", "ns8250";
example = <0xf00f0000 19>, "a strage property format";
常用属性
#address-cells、#size-cells
- address-cells:表示address要用多少个32位数来表示。
- size-cells:表示size要用多少个32位数来表示
/ {
#address-cells = <1>; //reg中用1个树表示地址
#size-cells = <1>; //reg中用1个数表示大小
memory {
reg = <0x80000000 0x20000000>; //0x80000000为地址,0x20000000表示大小
};
};
compatible
compatible的值,建议取这样的格式:“manufacturer,model”,即“厂家名,模块名”。
led {
compatible = “A”, “B”, “C”; //compatible表示兼容,内核中可能有A、B、C三种驱动支持
}; //内核就会按顺序找驱动
model
model与compatible属性有些类似,modle用来准确地定义这个硬件是什么。
/ {
compatible = "samsung,smdk2440", "samsung,mini2440"; //这个单板兼容内核中地smdk2440,mini2440
model = "jz2440_v3"; //具体地板子用model来明确
};
status
在dtsi中有很多设备,但是在当前地板子上某些设备是没有地。这时候可以给设备节点添加status属性,设置为disabled。
status可以填写的值:
- “okay”:设备正常运行。
- “disabled”:设备不可操作,但是后面可以恢复工作。
- “fail”:发生了严重错误,需修复。
- “fail-sss”:发生了严重错误,需修复;sss表示错误信息。
&uart1 {
status = "disabled";
};
reg
在设备树中描述一段空间。在ARM总,寄存器和内存是统一编址的,在访问上没有区别。
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
memory {
reg = <0x80000000 0x20000000>; //reg的地址和地址长度,有address和size决定
};
};
name(过时了)
用来表示节点名字,在platform_driver匹配时使用,优先级最低。
ldevice_type(过时了)
字符串,用来表示节点类型。在platfrom_driver匹配时使用,优先级为中。
常用节点
根节点
dst中必须有一个根节点。
/dts-v1/;
/ {
model = "SMDK24440"; //这个板子是什么
compatible = "samsung,smdk2440"; //板子兼容哪些平台,定义一系列的字符串, 用来指定内核中哪个 machine_desc 可以支持本设备
#address-cells = <1>; // 在它的子节点的 reg 属性中, 使用多少个 u32 整数来描述地址(address)
#size-cells = <1>; // 在它的子节点的 reg 属性中, 使用多少个 u32 整数来描述大小(size)
};
CPU节点
一般不需要我们设置,在 dtsi 文件中都定义好了
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
.......
}
};
memory节点
芯片厂家不可能事先确定你的板子使用多大的内存,所以 memory 节点需要板厂设置。
memory {
reg = <0x80000000 0x20000000>;
};
chosen节点
可以通过设备树文件给内核传入一些参数,这要在 chosen 节点中设置 bootargs 属性。
chosen {
bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200";
};
编译、更换设备树
在内核中可以单独编译设备树
make dtbs V=1
手工编译,除非熟练掌握
./scripts/dtc/dtc -I dts -O dtb -o tmp.dtb arch/arm/boot/dts/xxx.dts // 编译 dts 为 dtb
./scripts/dtc/dtc -I dtb -O dts -o tmp.dts arch/arm/boot/dts/xxx.dtb // 反编译 dtb 为 dts
#/sys/firmware/fdt 文件,它就是 dtb 格式的设备树文件
./scripts/dtc/dtc -I dtb -O dts /从板子上/复制出来的/fdt -o tmp.dts
rk3288中源码编译在arch/arm/boot/dts/rk3288-firefly.dtb
,更换设备树目录是/boot/rk3288-firefly.dtb
。