补一点基础知识
一、dts产生原因
DTS即Device Tree Source 设备树源码,是一种描述硬件的数据结构。替代原有的spec代码,更便于管理。本质上,Device Tree改变了原来用hardcode方式将HW配置信息嵌入内核代码的方法,改用bootloader传递一些参数。
如果我们认为kernel是一个black box,那么其输入参数应该包括
a.识别platform的信息
b.runtime的配置参数
c.设备的拓扑结构以及特性
对于嵌入式系统,在系统启动阶段,bootloader会加载内核并将控制权转交给内核,此外,还需要把上述的三个参数信息传递给kernel,以便kernel可以有较大的灵活性。在linux kernel中,Device Tree的设计目标就是如此。
二、dts基本知识
2.1 dts加载过程
使用device tree,需要用户了解自己的硬件配置与系统运行参数,并把这些信息组织成Device Tree source file。通过DTC编译成DTB。在系统启动时,boot可以将保存在flash中的dtb复制到内存(也可以是其他方法),并把DTB起始地址传递给client program。
2.2 dts描述信息
Device Tree由一系列被命名的节点和属性组成。它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。
可描述的信息包括:
CPU的数量和类别
内存基地址和大小
总线和桥
外设连接
中断控制器和中断使用情况
GPIO控制器和GPIO使用情况
Clock控制器和Clock使用情况
正常情况下所有的dts文件以及dtsi文件都含有一个根节点”/”,这样include之后就会造成有很多个“根节点”。按理说 device tree既然是一个树,那么其只能有一个根节点,所有其他的节点都是派生于根节点的child node。其实Device TreeCompiler会对DTS的node进行合并,最终生成的DTB中只有一个root node.
device tree的基本单元是node。这些node被组织成树状结构,除了root node,每个node都只有一个parent。一个device tree文件中只能有一个root node。每个node中包含了若干的property/value来描述该node的一些特性。每个node用节点名字(node name)标识,节点名字的格式是node-name@unit-address。如果该node没有reg属性(后面会描述这个property),那么该节点名字中必须不能包括@和unit-address。unit-address的具体格式是和设备挂在那个bus上相关。例如对于cpu,其unit-address就是从0开始编址,依次加一。而具体的设备,例如以太网控制器,其unit-address就是寄存器地址。rootnode的node name是确定的,必须是“/”。
2.3 dts标准属性
1.compatible
compatible = “acme,coyotes-revenge”;
compatible定义了系统的名称,它的组织形式为<manufacturer>,<model>。Linux内核透过root结点"/"的compatible 属性即可判断它启动的是什么。
在.dts文件的每个设备,都有一个compatible属性,compatible属性绑定用户驱动和设备。 compatible属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确切设备**,形式为"<manufacturer>,<model>",其后的字符串表征可兼容的其他设备。可以说 前面的是特指,后面的则涵盖更广的范围。
flash@0,00000000 {
compatible = "arm,vexpress-flash", "cfi-flash";
reg = <0 0x00000000 0x04000000>,
<1 0x00000000 0x04000000>;
bank-width = <4>;
};
2.name@unit-address
注意cpus和cpus的2个cpu子结点的命名,它们遵循的组织形式为:
<name>[@<unit-address>]
<>中的内容是必选项,[]中的则为可选项。
name是一个ASCII字符串,用于描述结点对应的设备类型,如网卡适配器对应的结点name宜为ethernet,表示这个是网卡。如果一个结点描述的设备有地址,则应该给出@unit-address。多个相同类型设备结点的name可以一样,只要unit-address不同即可。
led17: led@17 {
label = "led17";
reg = <17>;
led-max-microamp = <10000>;
linux,default-trigger = "timer";
linux,default-trigger-delay-ms = <500>;
linux,blink-delay-on-ms = <100>;
linux,blink-delay-off-ms = <1200>;
};
led18: led@18 {
label = "led18";
reg = <18>;
led-max-microamp = <10000>;
linux,default-trigger = "default-on";
};
3.model属性
model 属性值也是一个字符串,一般 model 属性描述设备模块信息,比如名字什么的,比如:
model = “Firefly ROC-RK3308B-CC-PLUS analog mic board”;
4.status属性
值 | 含义 |
---|---|
okay | 当前设备可操作 |
disable | 当前设备不可操作,但是未来可以变为可操作的,比如热插拔设备 |
fail | 表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能操作 |
fail-sss | 含义和"fail"相同,后面sss部分是检测到的错误内容 |
5.reg
意为region,区域。一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息,一般是(address, length)对。格式为
reg = < address1 length1 [ address2 length2 ] [ address3 length3 ] >;
6. #address-cells #size-cells
#address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位)
#size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)
#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值
2.4 根节点的compatible属性
每个节点都有compatible属性,根节点“/”也不例外。
设备节点的compatible属性:是为了匹配Linux内核中的驱动程序。
根节点的compatible属性:是为了确认Linux内核是否支持次设备,一般,第一个值描述所使用的硬件设备名字,比如:imx6ull-14x14-evk;第二个值描述设备所使用的SOC,比如imx6ull。