/======================================================================================================/
1. dts是用文本格式画的一棵树,包含了要传递给内核的硬件及配置信息.
dts基本上就是画一棵电路板上CPU、总线、设备组成的树,
Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,
并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,
而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备.
.dts文件是一种ASCII文本格式的Device Tree描述.
/======================================================================================================/
2. 一个dts对应一个板子,把一个SOC或者同类板子的共同部分提炼为dtsi, 供不同板子的dts include.
在ARM Linux,一个.dts文件对应一个ARM的machine,一般放置在内核的arch/arm/boot/dts/目录。
由于一个SoC可能对应多个machine(一个SoC可以对应多个产品和电路板),势必这些.dts文件需包含许多共同的部分,Linux内核为了简化,把SoC公用的部分或者多个machine共同的部分一般提炼为.dtsi,类似于C语言的头文件。其他的machine对应的.dts就include这
个.dtsi。譬如,对于RK3288而言, rk3288.dtsi就被rk3288-chrome.dts所引用,rk3288-chrome.dts有如下一行:#include“rk3288.dtsi”
当然,和C语言的头文件类似,.dtsi也可以include其他的.dtsi,譬如几乎所有的ARM SoC的.dtsi都引用了skeleton.dtsi,即#include"skeleton.dtsi“
/======================================================================================================/
3. 节点。dts基本单元是node.每个node只有一个parent且包含多个property/value来描述本身特性.node格式node-name@unit-address
device tree的基本单元是node。这些node被组织成树状结构,除了root node,每个node都只有一个parent。一个device tree文件中只能有一个root node。每个node中包含了若干的property/value来描述该node的一些特性。
每个node用节点名字(node name)标识,节点名字的格式是node-name@unit-address
unit-address的具体格式是和设备挂在那个bus上相关
要想唯一指定一个node必须使用full path
/======================================================================================================/
4. 属性。property/value
(1)compatible: 用于匹配driver,多个字符串,匹配范围越来越大, 从一个具体板子开始
(2)model: 设备型号; model = "soc3311"
(3) #address-cells","#size-cells": 一个cell 类型u32.该node总线地址长度和地址范围需要几个cell(u32)表示
(4)reg 表示该node地址资源. 寄存器的起始地址及大小
例子:
#address-cells = 2,#size-cells = 2
0 0x110f0000 即两个u32表示一个起始地址
0 0x100 即两个u32表示一个地址空间size
reg = <0 0x110f0000 0 0x100> 表示一段地址空间 , 是个二维数组[起始地址][地址size]
(5)status 表示节点状态, okay/disabled.注意不在dtsi中打开,不然会打开所有包含它的板子
(6)标签。
例子:
.dtsi
spi0: spi@1a010000 {
compatible = .....
stattus = "disabled"
}
.dts
&spi0 {
pinctrl-0 = ...
spis0: spi@0 {
compatible = "socle, soc3311-spis"
reg = <>
...
}
}
属性的值在内存中由0个或多个字节存储。标准定义的基本类型包括:空,u32,u64,字符串,
,字符数组6种。空前边我们已经提到,当不需要值就可以表示节点的特性时,属性的值可以为空。u32,u64,字符串,字符数组和c语言的定义没有区别,
注意的是规范要求都是大端表示,字符串也是以0x00结尾
“compatible”属性是用来匹配驱动的,他的类型是字符串数组,每个字符串表示一种设备的类型,从具体到一般。
"model"属性用来表示设备的型号,用字符串表示,不像"compatible"用多个字符串,
"device_type"属性用来表示设备类型,用字符串表示。
"#address-cells","#size-cells","reg","ranges","dma-ranges"属性都是和地址有关的。
不同的平台,不同的总线,地址位长度可能不同,有32位地址,有64位地址,为了适应这个,规范规定一个32位的长度为一个cell。
"#address-cells"属性用来表示总线地址需要几个cell表示,该属性本身是u32类型的。
#size-cells"属性用来表示子总线地址空间的长度需要几个cell表示
可以这么理解父节点表示总线,总线上每个设备的地址长度以及地址范围是总线的一个特性,用"#address-cells","#size-cells"属性表示,比如总线是32位,那么"#address-cells"设置成1就可以了。这两个属性不可以继承,就是说在未定义这两个属性的时候,不会继
承更高一级父节点的设置,如果没有设置的话,内核默认认为"#address-cells"为2,"#size-cells"为1。
"reg"属性用来表示节点地址资源的,比如常见的就是寄存器的起始地址及大小。要想表示一块连续地址,必须包含起始地址和空间大小两个参数,如果有多块地址,那么就需要多组这样的值表示。还记得前边说过的类型的属性吧,就是用来干这个
的,他表示一个数组,每个元素的具体格式根据属性而定,对于'reg'属性,每个元素是一个二元组,包含起始地址和大小。还有另外一个问题,地址和大小用几个u32表示呢?这个就由父节点的"#address-cells","#size-cells"属性确定。
'status'属性用来表示节点的状态的,其实就是硬件的状态,用字符串表示。'okay'表示硬件正常工作,“disabled”表示硬件当前不可用,“fail”表示因为出错不可用,“fail-sss”表示因为某种原因出错不可用,sss表示具体的出错原因。实际中,基本只
用'okay'和'disabled'。
/======================================================================================================/
5. 中断。
(1)interrupt-controller. 属性不赋值,表明自己是中断控制器
(2)interrupt-parent. 指定该节点的中断父节点。注意是节点。interrupt-parent = <&gic>
(3)#interrupt-cells几个u32描述.#interrupt-cells = 3
(4)interrupts属性描述中断源. interrupts =
对于ARM GIC中断控制器而言,#interrupt-cells为3,它3个cell的具体含义kernel/Documentation/devicetree/bindings/arm/gic.txt
interrupt-controller属性表示自己是中断控制器,这个属性的类型是空,不用设置值,只要存在这个节点就表示该节点是中断控制器。
设备树的父节点不是中断的父节点(主要是中断控制器一般不是父节点),为此引入了interrupt-parent属性,该属性的类型是,用来引用中断父节点(我们前边说过,一般用父节点的标签
中断一般包括中断产生设备和中断处理设备。中断控制器负责处理中断,每一个中断都有对应的中断号及触发条件。中断产生设备可能有多个中断源,有时多个中断源对应中断控制器中的一个中断,这种情况中断产生设备的中断源称之为中断控制器中对应中断的子中断
。
/======================================================================================================/