1. ARM Device Tree起源Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a f*cking pain in the ass”,引发ARM Linux社区的地震,随后ARM社区进行了一系列的重大修正。在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data。读者有兴趣可以统计下常见的s3c2410、s3c6410等板级目录,代码量在数万行。
社区必须改变这种局面,于是PowerPC等其他体系架构下已经使用的Flattened Device Tree(FDT)进入ARM社区的视野。Device Tree是一种描述硬件的数据结构,它起源于 OpenFirmware (OF)。在Linux 2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。
Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在Device Tree中,可描述的信息包括(原先这些信息大多被hard code到kernel中):
CPU的数量和类别
内存基地址和大小
总线和桥
外设连接
中断控制器和中断使用情况
GPIO控制器和GPIO使用情况
Clock控制器和Clock使用情况
它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。
2. Device Tree组成和结构整个Device Tree牵涉面比较广,即增加了新的用于描述设备硬件信息的文本格式,又增加了编译这一文本的工具,同时Bootloader也需要支持将编译后的Device Tree传递给Linux内核。
DTS (device tree source).dts文件是一种ASCII 文本格式的Device Tree描述,此文本格式非常人性化,适合人类的阅读习惯。基本上,在ARM Linux在,一个.dts文件对应一个ARM的machine,一般放置在内核的arch/arm/boot/dts/目录。由于一个SoC可能对应多个machine(一个SoC可以对应多个产品和电路板),势必这些.dts文件需包含许多共同的部分,Linux内核为了简化,把SoC公用的部分或者多个machine共同的部分一般提炼为.dtsi,类似于C语言的头文件。其他的machine对应的.dts就include这个.dtsi。譬如,对于VEXPRESS而言,vexpress-v2m.dtsi就被vexpress-v2p-ca9.dts所引用, vexpress-v2p-ca9.dts有如下一行:
/include/ 'vexpress-v2m.dtsi'
当然,和C语言的头文件类似,.dtsi也可以include其他的.dtsi,譬如几乎所有的ARM SoC的.dtsi都引用了skeleton.dtsi。
.dts(或者其include的.dtsi)基本元素即为前文所述的结点和属性:
/ {
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;
second-child-property = <1>;
a-string-property = 'Hello, world';
};
child-node2 {
};
};
node2 {
an-empty-property;
a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */
child-node1 {
};
};
};
上述.dts文件并没有什么真实的用途,但它基本表征了一个Device Tree源文件的结构:
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'。
下面以一个最简单的machine为例来看如何写一个.dts文件。假设此machine的配置如下:
1个双核ARM Cortex-A9 32位处理器;
ARM的local bus上的内存映射区域分布了2个串口(分别位于0x101F1000 和 0x101F2000)、GPIO控制器(位于0x101F3000)、SPI控制器(位于0x10170000)、中断控制器(位于0x10140000)和一个external bus桥;
External bus桥上又连接了SMC SMC91111 Ethernet(位于0x10100000)、I2C控制器(位于0x10160000)、64MB NOR Flash(位于0x30000000);
External bus桥上连接的I2C控制器所对应的I2C总线上又连接了Maxim DS1338实时钟(I2C地址为0x58)。
其对应的.dts文件为:
/ {
compatible = 'acme,coyotes-revenge';
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = 'arm,cortex-a9';
reg = <0>;
};
cpu@1 {
compatible = 'arm,cortex-a9';
reg = <1>;
};
};
serial@101f0000 {
compatible = 'arm,pl011';
reg = <0x101f0000 0x1000 >;
interrupts = < 1 0 >;
};
serial@101f2000 {
compatible = 'arm,pl011';
reg = <0x101f2000 0x1000 >;
interrupts = < 2 0 >;
};
gpio@101f3000 {
compatible = 'arm,pl061';
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
interrupts = < 3 0 >;
};
intc: interrupt-controller@10140000 {
compatible = 'arm,pl190';
reg = <0x10140000 0x1000 >;
interrupt-controller;
#interrupt-cells = <2>;
};
spi@10115000 {
compatible = 'arm,pl022';
reg = <0x10115000 0x1000 >;
interrupts = < 4 0 >;
};
external-bus {
#address-cells = <2>
#size-cells = <1>;
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
ethernet@0,0 {
compatible = 'smc,smc91c111';
reg = <0 0 0x1000>;
interrupts = < 5 2 >;
};
i2c@1,0 {
compatible = 'acme,a1234-i2c-bus';
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
interrupts = < 6 2 >;
rtc@58 {
compatible = 'maxim,ds1338';
reg = <58>;
interrupts = < 7 3 >;
};
};
flash@2,0 {
compatible = 'samsung,k8f1315ebm', 'cfi-flash';
reg = <2 0 0x4000000>;
};
};
};
上述.dts文件中,root结点'/'的compatible 属性compatible = 'acme,coyotes-revenge';定义了系统的名称,它的组织形式为: 在.dts文件的每个设备,都有一个compatible 属性,compatible属性用户驱动和设备的绑定。compatible 属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确切设备,形式为' flash@0,00000000 { compatible = 'arm,vexpress-flash', 'cfi-flash'; reg = <0 0x00000000 0x04000000>, <1 0x00000000 0x04000000>; bank-width = <4>; }; compatible属性的第2个字符串'cfi-flash'明显比第1个字符串'arm,vexpress-flash'涵盖的范围更广。 再比如,Freescale MPC8349 SoC含一个串口设备,它实现了国家半导体(National Semiconductor)的ns16550 寄存器接口。则MPC8349串口设备的compatible属性为compatible = 'fsl,mpc8349-uart', 'ns16550'。其中,fsl,mpc8349-uart指代了确切的设备, ns16550代表该设备与National Semiconductor 的16550 UART保持了寄存器兼容。 接下来root结点'/'的cpus子结点下面又包含2个cpu子结点,描述了此machine上的2个CPU,并且二者的compatible 属性为'arm,cortex-a9'。 注意cpus和cpus的2个cpu子结点的命名,它们遵循的组织形式为: 可寻址的设备使用如下信息来在Device Tree中编码地址信息: reg #address-cells #size-cells 其中reg的组织形式为reg =
上一篇:Linux Kernel之flush_cache_all在ARM平台下是如何实现的
下一篇:最后一页
推荐阅读最新更新时间:2024-11-11 13:53
设计资源 培训 开发板 精华推荐
- 【航顺训练营】航顺MCU开发板
- DC2870A,使用 LTC5596 Linduino Shield 100MHz 至 40GHz RMS 功率检测器的演示板
- 具有开路检测功能的 LT4254 正高压热插拔控制器的典型应用
- LTC4162IUFD-FFS 9V 至 35V 2 节 3.2A 充电器的典型应用,具有 PowerPath 和 2A 输入限制
- LTC2470 的典型应用 - 具有 10ppm/摄氏度最大精度基准的可选 208sps/833sps、16 位 ADC
- C8051T630DK,基于C8051T630 8051 MCU的MCU开发套件
- LT1086CM-3.6 低压差负电源的典型应用
- 15W、5V、12V DC 至 DC 多输出电源
- RGB_800X480
- DC1096,用于 LTC2642 16 位 +/-5V 无缓冲 Vout DAC 的演示板
- 揭秘正确选择探头的5大要素 (泰克原装探头促销,高贵不贵,199元起)
- 免费试用|是德科技加快信号完整性和电源完整性测试
- 下载、答题赢好礼:使用Mentor的Xpedition Layout高效设计PCB
- 有奖活动 | 来 Pl BridgeSwitch™ 技术中心探秘半桥电机驱动器新技术
- 抢楼有礼:看直播,深入了解ST最新 MEMS气压计原理、操作、防水结构设计
- 下载、答题赢好礼:使用Mentor的Xpedition Layout高效设计PCB
- 参加RT-Thread软件包赛,赢取RoboMaster等丰厚奖品!
- 有奖评测:50套来自恩智浦全新快速物联网原型设计套件(价值350元)
- 【EEWORLD第二十二届社区明星人物】畅想十二月明星人物揭晓!