内容来自宋老师《Linux设备驱动开发》
1、DTS
文件.dts是一种ASCII文本格式的设备树描述,此文本格式非常人性化,适合人类的阅读习惯。但是内核肯定和人不一样,所以就的转换。
基本上,在ARM Linux中,一个.dts文件对应一个ARM的设备,一般放置在内核的arch/arm/boot/dts/目录中。值得注意的是,在arch/powerpc/boot/dts、arch/powerpc/boot/dts、arch/c6x/boot/dts、arch/openrisc/boot/dts等目录中,也存在大量的.dts文件,这证明DTS绝对不是ARM的专利。
1.1 dts简介
由于一个SoC可能对应多个设备(一个SoC可以对应多个产品和电路板),这些.dts文件势必须包含许多共同的部分,Linux内核为了简化,**把SoC公用的部分或者多个设备共同的部分一般提炼为.dtsi,**类似于C语言的头文件。(我要解析的就是.dtsi文件)
其他的设备对应的.dts就包括这个.dtsi。譬如,对于VEXPRESS而言,vexpress-v2m.dtsi就被vexpress-v2p-ca9.dts所引用,vexpress-v2p-ca9.dts有如下一行代码:
/include/ "vexpress-v2m.dtsi"
这个和我写bp那里有点相似的思维,果然include包含世界。
当然,和C语言的头文件类似,.dtsi也可以包括其他的.dtsi,譬如几乎所有的ARM SoC的.dtsi都引用了skeleton.dtsi。
文件.dts(或者其包括的.dtsi)的基本元素即为前文所述的节点和属性,代码清单18.1给出了一个设备树结构的模版。
1 / { 2 node1 { 3 a-string-property = "A string"; 4 a-string-list-property = "first string", "second string"; 5 a-byte-data-property = [0x01 0x23 0x34 0x56]; 6 child-node1 { 7 first-child-property; 8 second-child-property = <1>; 9 a-string-property = "Hello, world"; 10 }; 11 child-node2 { 12 }; 13 }; 14 node2 { 15 an-empty-property; 16 a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */ 17 child-node1 { 18 }; 19 }; 20 };
上述.dts文件并没有什么真实的用途,但它基本表征了一个设备树源文件的结构:
1个root节点"/"; root节点下面含一系列子节点,本例中为node1和node2; 节点node1下又含有一系列子节点,本例中为child-node1和child-node2;
各节点都有一系列属性。
这些属性可能为空,如an-empty-property; 可能为字符串,如a-string-property; 可能为字符串数组,如a-string-list-property; 可能为Cells(由u32整数组成),如second-child-property; 可能为二进制数,如a-byte-data-property。
1.2 dts例子
上面知道了基础的知识,下来整个栗瞅瞅
先来文字描述:
1个双核ARM Cortex-A932位处理器;
ARM本地总线上的内存映射区域分布有两个串口(分别位于0x101F1000和0x101F2000)、GPIO控制器(位于0x101F3000)、SPI控制器(位于0x10170000)、中断控制器(位于0x10140000)和一个外部总线桥;
外部总线桥上又连接了SMC SMC91111以太网(位于0x10100000)、I2C控制器(位于0x10160000)、64MB NOR Flash(位于0x30000000);
外部总线桥上连接的I2C控制器所对应的I2C总线上又连接了Maxim DS1338实时钟(I2C地址为0x58)。
转换成dts文件
1 / { 2 compatible = "acme,coyotes-revenge"; 3 #address-cells = <1>; 4 #size-cells = <1>; 5 interrupt-parent = <&intc>; 6 7 cpus { 8 #address-cells = <1>; 9 #size-cells = <0>; 10 cpu@0 { 11 compatible = "arm,cortex-a9"; 12 reg = <0>; 13 }; 14 cpu@1 { 15 compatible = "arm,cortex-a9"; 16 reg = <1>; 17 }; 18 }; 19 20 serial@101f0000 { 21 compatible = "arm,pl011"; 22 reg = <0x101f0000 0x1000 >; 23 interrupts = < 1 0 >; 24 }; 25 26 serial@101f2000 { 27 compatible = "arm,pl011"; 28 reg = <0x101f2000 0x1000 >; 29 interrupts = < 2 0 >; 30 }; 31 32 gpio@101f3000 { 33 compatible = "arm,pl061"; 34 reg = <0x101f3000 0x1000 35 0x101f4000 0x0010>; 36 interrupts = < 3 0 >; 37 }; 38 39 intc: interrupt-controller@10140000 { 40 compatible = "arm,pl190"; 41 reg = <0x10140000 0x1000 >; 42 interrupt-controller; 43 #interrupt-cells = <2>; 44 }; 45 46 spi@10115000 { 47 compatible = "arm,pl022"; 48 reg = <0x10115000 0x1000 >; 49 interrupts = < 4 0 >; 50 }; 51 52 external-bus { 53 #address-cells = <2> 54 #size-cells = <1>; 55 ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet 56 1 0 0x10160000 0x10000 // Chipselect 2, i2c controller 57 2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash 58 59 ethernet@0,0 { 60 compatible = "smc,smc91c111"; 61 reg = <0 0 0x1000>; 62 interrupts = < 5 2 >; 63 }; 64 65 i2c@1,0 { 66 compatible = "acme,a1234-i2c-bus"; 67 #address-cells = <1>; 68 #size-cells = <0>; 69 reg = <1 0 0x1000>; 70 interrupts = < 6 2 >; 71 rtc@58 { 72 compatible = "maxim,ds1338"; 73 reg = <58>; 74 interrupts = < 7 3 >; 75 }; 76 }; 77 78 flash@2,0 { 79 compatible = "samsung,k8f1315ebm", "cfi-flash"; 80 reg = <2 0 0x4000000>; 81 }; 82 }; 83 };
在上述.dts文件中,可以看出external-bus是根节点的子节点,而I2C又是external-bus的子节点,RTC又进一步是I2C的子节点。每一级节点都有一些属性信息。