dts入门Word文档下载推荐.docx
《dts入门Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《dts入门Word文档下载推荐.docx(21页珍藏版)》请在冰点文库上搜索。
kernel通过传入的dtb地址进行设备的创建。
2.2dts描述信息
DeviceTree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。
所谓属性,其实就是成对出现的name和value。
在DeviceTree中,可描述的信息包括(原先这些信息大多被hardcode到kernel中):
CPU的数量和类别
内存基地址和大小
总线和桥
外设连接
中断控制器和中断使用情况
GPIO控制器和GPIO使用情况
Clock控制器和Clock使用情况
它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。
是否DeviceTree要描述系统中的所有硬件信息?
答案是否定的。
基本上,那些可以动态探测到的设备是不需要描述的,例如USBdevice。
不过对于SOC上的usbhostcontroller,它是无法动态识别的,需要在devicetree中描述。
同样的道理,在computersystem中,PCIdevice可以被动态探测到,不需要在devicetree中描述,但是PCIbridge如果不能被探测,那么就需要描述之。
.dts文件是一种ASCII文本格式的DeviceTree描述,此文本格式非常人性化,适合人类的阅读习惯。
基本上,在ARMLinux在,一个.dts文件对应一个ARM的machine,一般放置在内核的arch/arm/boot/dts/目录。
由于一个SoC可能对应多个machine(一个SoC可以对应多个产品和电路板),势必这些.dts文件需包含许多共同的部分,Linux内核为了简化,把SoC公用的部分或者多个machine共同的部分一般提炼为.dtsi,类似于C语言的头文件。
其他的machine对应的.dts就include这个.dtsi。
譬如在arch/arm/boot/dts/qcom/目录下,高通的很多.dtsi都include了skeleton.dtsi或者skeleton64.dtsi。
正常情况下所有的dts文件以及dtsi文件都含有一个根节点”/”,这样include之后就会造成有很多个“根节点”。
按理说devicetree既然是一个树,那么其只能有一个根节点,所有其他的节点都是派生于根节点的childnode。
其实DeviceTreeCompiler会对DTS的node进行合并,最终生成的DTB中只有一个rootnode.
devicetree的基本单元是node。
这些node被组织成树状结构,除了rootnode,每个node都只有一个parent。
一个devicetree文件中只能有一个rootnode。
每个node中包含了若干的property/value来描述该node的一些特性。
每个node用节点名字(nodename)标识,节点名字的格式是node-name@unit-address。
如果该node没有reg属性(后面会描述这个property),那么该节点名字中必须不能包括@和unit-address。
unit-address的具体格式是和设备挂在那个bus上相关。
例如对于cpu,其unit-address就是从0开始编址,依次加一。
而具体的设备,例如以太网控制器,其unit-address就是寄存器地址。
rootnode的nodename是确定的,必须是“/”。
在一个树状结构的devicetree中,如何引用一个node呢?
要想唯一指定一个node必须使用fullpath,例如/node-name-1/node-name-2/node-name-N
2.3dts组成结构示例
/{"
/"
表示root结点,该结点下有两个子结点node1和node2
node1{结点"
node1"
下又含有子结点,本例中为"
child-node1"
和"
child-node2"
,各结点都有一系列属性
a-string-property="
Astring"
;
属性是字符串
a-string-list-property="
firststring"
"
secondstring"
字符串数组
a-byte-data-property=[0x010x230x340x56];
二进制数组
child-node1{
first-child-property;
second-child-property=<
1>
Cells(由u32整数组成)
Hello,world"
};
child-node2{
node2{
an-empty-property;
属性为空
a-cell-property=<
1234>
/*eachnumber(cell)isauint32*/
};
上述.dts文件并没有什么真实的用途,但它基本表征了一个DeviceTree源文件的结构。
2.4dts语法
完整的DeviceTree可以将一个PCB摆在你眼前,下面我们一起来看一下:
下面以一个最简单的machine为例来看如何写一个.dts文件。
假设此machine的配置如下:
1个双核ARMCortex-A932位处理器;
ARM的localbus上的内存映射区域分布了2个串口(分别位于0x101F1000和0x101F2000)、GPIO控制器(位于0x101F3000)、SPI控制器(位于0x10115000)、中断控制器(位于0x10140000)和一个externalbus桥;
Externalbus桥上又连接了SMCSMC91111Ethernet(位于0x10100000)、I2C控制器(位于0x10160000)、64MBNORFlash(位于0x30000000);
Externalbus桥上连接的I2C控制器所对应的I2C总线上又连接了MaximDS1338实时钟(I2C地址为0x58)。
其对应的.dts文件为:
/
{
compatible
=
"
acme,coyotes-revenge"
#address-cells
<
子结点需要一个cell描述地址
#size-cells
子结点需要一个cell描述长度
interrupt-parent
&
intc>
cpus
0>
cpu@0
arm,cortex-a9"
reg
cpu@1
serial@101f1000
串口
arm,pl011"
0x101f1000
0x1000
>
interrupts
1
0
serial@101f2000
0x101f2000
2
gpio@101f3000
GPIO控制器
arm,pl061"
0x101f3000
0x101f4000
0x0010>
3
intc:
interrupt-controller@10140000
中断控制器
arm,pl190"
0x10140000
interrupt-controller;
#interrupt-cells
2>
spi@10115000
spi控制器
arm,pl022"
0x10115000
起始地址为0x10115000,长度为0x1000
4
external-bus
externalbus桥
子结点需要两个cell描述地址,片选
ranges
0x10100000
0x10000
//
Chipselect
1,
Ethernet
片选00,地址0x10100000
,长度0x10000
1
0x10160000
2,
i2c
controller
2
0x30000000
0x1000000>
3,
NOR
Flash
ethernet@0,0
smc,smc91c111"
0x1000>
5
i2c@1,0
acme,a1234-i2c-bus"
rtc需要一个cell描述地址
rtc不需要0描述长度
rtc@58
maxim,ds1338"
58>
7
flash@2,0
samsung,k8f1315ebm"
cfi-flash"
0x4000000>
注释不是太多,下面来详细分类解释:
2.4.1compatible
上述.dts文件中,root结点"
的compatible属性compatible="
定义了系统的名称,它的组织形式为:
manufacturer>
<
model>
。
Linux内核透过root结点"
的compatible属性即可判断它启动的是什么machine。
在.dts文件的每个设备,都有一个compatible属性,compatible属性用户驱动和设备的绑定。
compatible属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确切设备,形式为"
,其后的字符串表征可兼容的其他设备。
可以说前面的是特指,后面的则涵盖更广的范围。
如在arch/arm/boot/dts/vexpress-v2m.dtsi中的Flash结点:
flash@0,00000000
{
arm,vexpress-flash"
0x00000000
0x04000000>
bank-width
4>
compatible属性的第2个字符串"
明显比第1个字符串"
涵盖的范围更广。
2.4.2name@unit-address
接下来root结点"
的cpus子结点下面又包含2个cpu子结点,描述了此machine上的2个CPU,并且二者的compatible属性为"
注意cpus和cpus的2个cpu子结点的命名,它们遵循的组织形式为:
name>
[@<
unit-address>
],<
中的内容是必选项,[]中的则为可选项。
name是一个ASCII字符串,用于描述结点对应的设备类型,如网卡适配器对应的结点name宜为ethernet,表示这个是网卡。
如果一个结点描述的设备有地址,则应该给出@unit-address。
多个相同类型设备结点的name可以一样,只要unit-address不同即可,如本例中含有cpu@0、cpu@1以及serial@101f0000与serial@101f2000这样的同名结点。
设备的unit-address地址也经常在其对应结点的reg属性中给出。
2.4.3regaddress-cellssize-cells
设备的地址特性根据一下几个属性来控制:
●reg
●#address-cells
●#size-cells
reg意为region,区域。
格式为:
reg=<
address1length1[address2length2][address3length3]>
父类的address-cells和size-cells决定了子类的相关属性要包含多少个cell,如果子节点有特殊需求的话,可以自己再定义,这样就可以摆脱父节点的控制。
address-cells决定了address1/2/3包含几个cell,size-cells决定了length1/2/3包含了几个cell,用上面的dts文件内容举例子说明:
例子2.4.3.1
root结点的#address-cells=<
和#size-cells=<
决定了serial、gpio、spi等结点的address和length字段的长度分别为1
地址0x101f1000,长度
0x1000
例子2.4.3.2
i2c控制器模块下的rtc模块。
因为I2C设备只是被分配在一个地址上,不需要其他任何空间,所以只需要一个address的cell就可以描述完整,不需要size-cells
...
external-bus{
#address-cells=<
#size-cells=<
i2c@1,0{
compatible="
重新写address-cells
#size-cells=<
reg=<
100x1000>
rtc@58{
只需要一个addresscell,不需要cell再描述长度
例子2.4.3.3
当需要描述的设备不是本地设备时,就需要描述一个从设备地址空间到CPU地址空间的映射关系,这里就需要用到ranges属性。
还是以上边的external-bus举例
ranges属性为一个地址转换表。
表中的每一行都包含了子地址、父地址、在自地址空间内的区域大小。
他们的大小(包含的cell)分别由子节点的address-cells的值、父节点的address-cells的值和子节点的size-cells来决定。
子结点需要一个cell描述地址
子结点需要一个cell描述长度
00两个cell,由子节点external-bus的address-cells=<
决定;
0x10100000一个cell,由父节点(/)的address-cells=<
0x10000一个cell,由子节点external-bus的size-cells=<
决定。
最终第一行说明的意思就是:
片选0,偏移0(选中了网卡),被映射到CPU地址空间的0x10100000~0x10110000中,地址长度为0x10000。
external-bus{
ranges=<
000x101000000x10000//Chipselect1,Ethernet
100x101600000x10000//Chipselect2,i2ccontroller
200x300000000x1000000>
//Chipselect3,NORFlash
进阶例子2.4.3.4
pci@0x10180000{
arm,versatile-pci-hostbridge"
pci"
0x101800000x1000>
interrupts=<
80>
bus-ranges=<
00>
3>
ran