关与设备树的概念,我们在Exynos4412 内核移植(六)—— 设备树解析 里面已经学习过,下面看一下设备树在设备驱动开发中起到的作用
Device Tree是一种描述硬件的数据结构,设备树源(Device Tree Source)文件(以.dts结尾)就是用来描述目标板硬件信息的。Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在Device Tree中,可描述的信息包括(原先这些信息大多被hard code到kernel中)
device tree 是一个简单的节点和属性树,属性是键值对,节点可以包含属性和子节点。下面是一个.dts 格式的简单设备树。
/{
node1 {
a-string-property = "A string";
a-string-list-property = "first string","second string";
a-byte-data-property = [0x01 0x23 0x34 0x56];
child-node1 {
first-child-property;
seconde-child-property = <1>;
a-string-property = "Hello, world";
};
chilid-node2{
};
};
node2 {
an-empty-property;
a-cell-property = <1 2 3 4>;/*each number(cell) is a uint32*/
child-node1{
};
};
};
该树并未描述任何东西,也不具备任何实际意义,但它却揭示了节点和属性的结构。即:
'/',两个子节点:node1和node2;node1的子节点:child-node1和child-node2,一些属性分散在树之间。key-value pairs):value可以为空也可以包含任意的字节流。而数据类型并没有编码成数据结构,有一些基本数据表示可以在device tree源文件中表示。null 终止)用双引号来表示:string-property = "a string"“Cells”是由尖括号分隔的32位无符号整数:cell-property = <0xbeef 123 0xabcd1234>[0x01 0x23 0x45 0x67];mixed-property = "a string", [0x01 0x23 0x45 0x67], <0x12345678>;逗号也可以用来创建字符串列表:string-list = "red fish", "blue fish";系统中的每个设备由 device tree 的一个节点来表示
每个节点都必须有一个格式的名称。是一个简单的ascii字符串,最长为31个字符,总的来说,节点命名是根据它代表什么设备。比如说,一个代表3com以太网适配器的节点应该命名为ethernet,而不是3com509
如果节点描述的设备有地址的话,就应该加上unit-address,unit-address通常是用来访问设备的主地址,并在节点的reg属性中被列出。后面我们将谈到reg属性
/{
compatible = "acme,coyotes-revenge";
cpus {
cpu@0 {
compatible = "arm,cortex-a9";
};
cpu@1 {
compatible = "arm,cortex-a9";
};
};
serial@101F0000 {
compatible = "arm,pl011";
};
serial@101F2000 {
compatible = "arm,pl011";
};
gpio@101F3000 {
compatible = "arm,pl061";
};
interrupt-cotroller@10140000 {
compatible = "arm,pl190";
};
spi@10115000 {
compatible = "arm,pl022";
};
external-bus {
ethernet@0,0 {
compatible = "smc,smc91c111";
};
i2c@1,0 {
compatible = "acme,a1234-i2c-bus";
rtc@58 {
compatible = "maxim,ds1338";
};
};
flash@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
};
};
};
在上面的设备树中,系统中的设备节点已经添加进来,树的层次结构反映了设备如何连到系统中。外部总线上的设备就是外部总线节点的子节点,i2c设备是i2c总线控制节点的子节点。总的来说,层次结构表现的是从CPU视角来看的系统视图。在这里这棵树是依然是无效的。它缺少关于设备之间的连接信息。稍后将添加这些数据。
设备树中应当注意:每个设备节点有一个compatible属性。flash节点的compatible属性有两个字符串。请阅读下一节以了解更多内容。 之前提到的,节点命名应当反映设备的类型,而不是特定型号。请参考ePAPR规范2.2.2节的通用节点命名,应优先使用这些命名。
树中的每一个代表了一个设备的节点都要有一个compatible属性。compatible是 OS 用来决定绑定到设备的设备驱动的关键。
compatible是字符串的列表。列表中的第一个字符串指定了"格式的节点代表的确切设备,第二个字符串代表了与该设备兼容的其他设备。例如,Freescale MPC8349 SoC有一个串口设备实现了National Semiconductor ns16550寄存器接口。因此MPC8349串口设备的compatible属性为:compatible = "fsl,mpc8349-uart", "ns16550"。在这里,fsl,mpc8349-uart指定了确切的设备,ns16550表明它与National Semiconductor 16550 UART是寄存器级兼容的。
可编址的设备使用下列属性来将地址信息编码进设备树
#address-cells; #size-cells; #reg;
每个可寻址的设备有一个reg属性,即以下面形式表示的元组列表:
reg =
每个元组,。每个地址值由一个或多个32位整数列表组成,被称做cells。同样地,长度值可以是cells列表,也可以为空。
既然address和length字段是大小可变的变量,父节点的#address-cells和#size-cells属性用来说明各个子节点有多少个cells。换句话说,正确解释一个子节点的reg属性需要父节点的#address-cells和#size-cells值。
与CPU节点中的单一地址值不同,内存映射设备会被分配一个它能响应的地址范围。#size-cells用来说明每个子节点中reg元组的长度大小
在下面的示例中,每个地址值是1 cell (32位) ,并且每个的长度值也为1 cell,这在32位系统中是非常典型的。64位计算机可以在设备树中使用2作为#address-cells和#size-cells的值来实现64位寻址。
serial@101f2000 {
compatible = "arm,pl011";
reg = <0x101f2000 0x1000>;
};
gpio@101f3000 {
compatible = "arm,pl061";
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
};
interrupt-controller@10140000 {
compatible = "arm,pl190";
reg = <0x1014000 0x1000>;
};
每个设备都被分配了一个基地址及该区域大小。本例中的GPIO设备地址被分成两个地址范围:0x101f3000~0x101f3fff和0x101f4000~0x101f400f。
我们仍以 Linux 设备驱动开发 —— platform设备驱动应用实例解析 文中的例子来解析设备树在platform设备驱动中如何使用;
其实我们可以看到,Device Tree 是用来描述设备信息的,每一个设备在设备树中是以节点的形式表现出来;而在上面的 platform 设备中,我们利用platform_device 来描述一个设备,我们可以看一下二者的对比
fs4412-beep{
compatible = "fs4412,beep";
reg = < 0x114000a0 0x4 0x139D0000 0x14 >;
};
a -- fs4412-beep 为节点名,符合咱们前面提到的节点命名规范;
我们通过名字可以知道,该节点描述的设备是beep, 设备名是fs4412-beep;
b -- compatible = "fs4412,beep"; compatible 属性, 即一个字符串;
前面提到, 所有新的compatible值都应使用制造商的前缀,这里是
fs4412;
c -- reg = < 0x114000a0 0x4 0x139D0000 0x14 >;
reg属性来将地址信息编码进设备树,表示该设备的地址范围;这里是我们用到的寄存器及偏移量;
static struct resource beep_resource[] =
{
[0] = {
.start = 0x114000a0,
.end = 0x114000a0+0x4,
.flag = IORESOURCE_MEM,
},
[1] = {
.start = 0x139D0000,
.end = 0x139D0000+0x14,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device hello_device =
{
.name = "bigbang",/*没用了*/
.id = -1;
.dev.release = hello_release,
.num_resources = ARRAY_SIZE(beep_resource),
.resosource = beep_resource,
};