汕头论坛贴吧,seo入门教程,软件开发分工5个角色,山东省城乡与建设厅网站本文翻译自Device Tree Usage主页#xff1a; http://devicetree.org/Device_Tree_Usage 此译文为本人原创#xff0c;若要转载请注明#xff01;Linux device tree的背景#xff08;引用自宋宝华博客#xff09;#xff1a;Linus Torvalds在2011年3月17日的ARM Linux邮件…本文翻译自Device Tree Usage主页 http://devicetree.org/Device_Tree_Usage 此译文为本人原创若要转载请注明 Linux 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 TreeFDT进入ARM社区的视野。Device Tree是一种描述硬件的数据结构它起源于 OpenFirmware (OF)。在Linux 2.6中ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx采用Device Tree后许多硬件的细节可以直接透过它传递给Linux而不再需要在kernel中进行大量的冗余编码。 设备树使用________________________________________________本页演示怎样为一个新的机器编写设备树。这主要为了给出设备树的整体概念以及他们是怎样被用来描述机器的。如果需要设备树数据格式的完整描述请参考ePAPR规范。本本主页只是讲述了一些基本主题而ePAPR规范讲述了很多这些主题的细节对于本页中没有讲述的高级用法请参考ePAPR。基本数据格式________________________________________________设备树是具有简单树形结构的节点和属性。属性是成对的键值节点可能包含属性和子节点。举个例子来说下面是一个简单的.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; 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 { }; };}; 这棵树很明显是没用的因为它没用描述任何东西但是它确实展示出了节点属性。即单个根节点/一对子节点node1, node2一对node1的子节点child-node1, child-node2树上散布的一堆属性 属性是简单的键值对其中键值既可以是空也可以包含任何字节流。虽然数据类型没用被编码在数据结构中但是在设备树源文件中有一些基本的数据表示方法。文本字符串以null作为终止以双引号的形式表示 string-property a string Cells是32位无符号整数并且使用尖括号分隔 cell-property 0xbeef 123 0xabcd1234 二进制数据使用方括号分隔 binary-perperty [0x01 0x23 0x45 0x67] 不同表示类型的数据可以通过逗号级联在一起 mixed-perperty a string, [0x01 0x23 0x45 0x67], 0x12345678; 逗号也可以用来创建字符串列表 string-list red fish, blue fish; 基本概念________________________________________________为了理解怎样使用设备树我们从一个样品机开始并且搭建设备树来一步步描述它样品机考虑下面的假想机器粗略地基于ARM VersatileAcme制造命名 “Coyotes Revenge:32位 ARM CPU单核PLB粘附在内存映射串口上spi总线控制器i2c控制器中断控制器以及外部总线桥256MB SDRAM基址从0开始2个串口基址从0x101F10000X101F2000开始GPIO控制器基址从0x101F3000开始SPI控制器基址从0x10170000并且总线上挂载着下列设备 MMC卡槽并且SS引脚连接在GPIO #1上 外部总线桥并且总线上挂载着下列设备 SMC SMC91111以太网设备连接在基址从0x10100000开始的外部总线上i2c控制器基址从0x10160000开始并且总线上挂载着如下设备 Maxim DS1338实时时钟。该器件响应0x58的从机地址。 64MB NOR flash基址从0x30000000开始 初始结构第一步是为机器制定框架结构。下面是一个合法的设备树所需的最小结构。在这个节点你想想要能够唯一地识别该机器/ { compatible acme,coyotes-revenge;}; compatible制定系统的名称。它包含manufacture,model格式的字符串。准确地确定器件型号是非常重要的并且我们需要包含厂商的名字来避免名字空间冲突。因为操作系统会使用compatible这个值来决定怎样在这个机器上运行所以在这个属性中放入正确的值是非常重要的。理论上来说compatible是一个OS需要唯一地识别机器所需要的唯一数据。如果所有机器的细节都是写死的那么OS可以在顶层compatible属性中专门查找acme,coyotes-revenge。CPUs下一步是描述每个CPU。一个命名为cpus的容器节点跟有对应每个CPU的子节点。在这个例子中系统是一个双核ARM Cortex A9的系统。/ { compatible acme,coyotes-revenge; cpus { cpu0 { compatible arm,cortex-a9; }; cpu1 { compatible arm,cortex-a9; }; };}; 每个CPU节点中的compatible属性是以manufacturer,model的格式确定CPU型号的字符串就像顶层的compatible属性那样。更多的属性会在稍后添加到cpu节点中但是我们首先需要讨论更多基本的概念。节点名字我们值得花一段时间讨论命名习惯。每一个几点必须要有一个以name[unit-address]形式的名字。name是简单的ascii字符串并且长度最大可以到31个字符。通常来说节点是根据它所代表的设备类型来命名的。举个例子3com公司的以太网适配器节点可能会使用ethernet作为它的名字而不是3com509。unit-address只有在节点描述含有地址的设备时会被包含进来。通常来说unit address是用来访问设备的基址并且在节点的reg属性中被罗列出来。我们稍后会在本文档中介绍reg属性。兄弟节点必须被唯一地命名不过对于不只一个节点的情况我们通常会使用通用的名字只要它们的地址不一样就可以。比如seriali101f1000 和serial101f2000)。如果需要更多节点命名方面的详细情况请参考ePAPR规范的第2.21部分设备系统中的每一个设备都由一个设备树节点来代表。下一步就是用每一个设备对应的节点来填充树。现在来说新节点将会被置空知道我们可以讨论地址范围以及终端是怎样安排的。/ { compatible acme,coyotes-revenge; cpus { cpu0 { compatible arm,cortex-a9; }; cpu1 { compatible arm,cortex-a9; }; }; serial101F0000 { compatible arm,pl011; };serial101F2000 { compatible arm,pl011; };gpio101F3000 { compatible arm,pl061; };interrupt-controller10140000 { compatible arm,pl190; };spi10115000 { compatible arm,pl022; };external-bus { ethernet0,0 { compatible smc,smc91c111; };i2c1,0 { compatible acme,a1234-i2c-bus; rtc58 { compatible maxim,ds1338; }; };flash2,0 { compatible samsung,k8f1315ebm, cfi-flash; }; };}; 在这棵树中系统中的每个设备都被添加了响应的节点并且层次结构反映了设备时怎样连接到系统的。举个例子来说外部总线上的设备是外部总线的子节点并且i2c设备是i2c总线控制器的子节点。通常来说层次结构代表了从CPU角度看到的系统视图。在这里这棵树并不是合法的。它缺少了设备之间连接的信息。那部分数据会在稍后添加。这棵树中有一些需要注意的地方每一个设备节点都有一个compatible属性flash节点的compatible属性中有两个字符串。阅读下一部分来了解为什么会这样。之前提到过节点的名字反映了设备的类型而不是特定的型号。情况ePAPR规范的2.2.2部分规范中提到了一系列已经定义好了随处可能用到的通用节点名字 理解compatible属性设备树中代表设备的每一个节点必须要有compatible属性。compatible是操作系统用来决定哪个设备驱动绑定哪个设备的关键字。compatible是字符串列表。列表中的第一个字符串以manufacturer,model的形式确定了节点代表的设备。接下来的字符串表示该设备可以兼容的其他设备。举个例子来说Freescale MPC8349 片上系统SoC有一个串行设备实现了国家半导体 ns16550寄存器接口。MPC8349穿行设备的compatible属性因此应该是compatible fsl,mpc8349-uart,ns16550。在这个例子中fsl,mpc8349-uart确定了设备并且ns16550表示它在寄存器级别兼容国家半导体16550 UART。注意ns16550没有厂商前缀纯粹是因为历史原因IBM-PC/AT吧..。所有新的compatible值应该使用厂商前缀。该操作允许现存的设备驱动绑定到更新的设备上不过它仍然唯一地识别确切的硬件。警告不要在compatible值中使用通配符比如fsl,mpc83xx-uart或者类似地。硅片厂商总是会做一些打破你通配符假设的变化到那时再改变就为时已晚了。相反选择一个特定的硅片实现并且使所有随后的硅片与之兼容。寻址是如何工作的________________________________________________可寻址的设备使用下面的属性来将地址信息编码进入设备树reg#address-cells#size-cells 每一个可寻址的设备获取的reg是以reg address1 length1 [address2 length2] [address3 length3] ...形式的表格元组。每一个元组代表设备所使用的地址范围。每一个地址值是被称为cells的一个或者多个32位整数的列表。相似地长度值既可以是cells的列表也可以是空的。因为地址和长度域都是长度可变的所以父节点中的#address-cells和#size-cells属性是用来说明每一个域中有多少个cells。换句话说正确地翻译一个reg属性需要父节点的#address-cells和#size-cells值。为了看到这一切是怎样工作的让我们将寻址属性添加到样例设备树中首先从CPU开始CPU寻址讨论到寻址时CPU节点代表最简单的情况。每一个CPU被赋予了一个唯一的ID并且CPU的ID没有关联的尺寸。cpus { #address-cells 1; #size-cells 0; cpu0 { compatible arm,cortex-a9; reg 0; }; cpu1 { compatible arm,cortex-a9; reg 1; }; }; cpu节点中#address-cells被设置为1#size-cells被设置为0.这意味着子节点的reg值是代表地址且没有size域的单个32位无符号整数。在这个例子中2个cpu被赋予了地址0和1。cpu节点的#size-cells是0因为cpu仅仅被赋予了单个地址。 你能注意到reg值匹配节点名字中的值。按照惯例如果一个节点具有reg属性这个节点必须包含单元地址也就是reg属性中的第一个地址值。内存映射设备不同于cpu节点中找到的单地址值内存映射设备被分配了它会响应的一个地址范围。#size-cells用来说明每一个子节点中的reg元组有多长。接下来的例子中每一个地址值都是一个单元的32位每一个长度值也是一个单元即典型的32位系统。64位系统可以把#address-cells和#size-cells赋值为2从而在设备设备树中得到64位寻址。/ { #address-cells 1; #size-cells 1; ... serial101f0000 { compatible arm,pl011; reg 0x101f0000 0x1000 ; }; serial101f2000 { compatible arm,pl011; reg 0x101f2000 0x1000 ; }; gpio101f3000 { compatible arm,pl061; reg 0x101f3000 0x1000 0x101f4000 0x0010; }; interrupt-controller10140000 { compatible arm,pl190; reg 0x10140000 0x1000 ; }; spi10115000 { compatible arm,pl022; reg 0x10115000 0x1000 ; }; ...}; 每一个设备都被分配了一个基地址以及它被分配的区域的尺寸。本例中的GPIO设备地址被分配了两个地址范围:0x101f3000...0x101f3fff 和0x101f4000..0x101f400f。有一些设备挂载在具有不同寻址策略的总线上。举个例子来说一个设备可以被连接到具有独立片选信号的外部总线上。因为每一个父节点定义了它子节点的寻址域所以我们可以从最佳描述系统的角度来选择地址映射方案。下面的代码显示了连接到外部总线上的设备的地址分配情况并且这些外部总线具有编码如地址的片选数字。external-bus { #address-cells 2 #size-cells 1; ethernet0,0 { compatible smc,smc91c111; reg 0 0 0x1000; }; i2c1,0 { compatible acme,a1234-i2c-bus; reg 1 0 0x1000; rtc58 { compatible maxim,ds1338; }; }; flash2,0 { compatible samsung,k8f1315ebm, cfi-flash; reg 2 0 0x4000000; }; }; 外部总线使用了2个单元的地址值。一个是片选数字另一个是片选基地址的偏移。长度域仍旧是单个单元因为只有地址的偏移部分需要一个范围。因此在本例中每一个reg入口都包含了3个单元片选数字偏移以及长度。因为地址域被包含在节点以及它的子节点中所以父节点可以自由定义任何总线上可行的寻址方案。直接父节点之外的节点通常不需要考虑本地寻址域并且为了从一个域到另一个域地址必须被映射。非内存映射设备其他设备并没有内存映射在处理器总线上。它们可以有寻址范围但是它们并不能直接被CPU访问。相反父节点设备的驱动会代表CPU间接地访问。现在来看i2c设备的例子每一个设备被分配了一个地址但是它没有关联的长度或者范围。这看上去与CPU地址分配时一样的。i2c1,0 { compatible acme,a1234-i2c-bus; #address-cells 1; #size-cells 0; reg 1 0 0x1000; rtc58 { compatible maxim,ds1338; reg 58; }; }; 范围地址转换我们已经讨论过了怎样为设备分配地址但是这里的这些地址只是本地的设备节点地址。它缺并没有描述怎样从那些地址映射到CPU可以使用的地址。根节点总是描述从CPU的视角看到的地址空间。根节点的子节点已经使用了CPU的地址域是、因此不需要任何显示地映射。举个例子来说serial101f0000设备是直接被分配了0x101f0000地址。那些不是根节点的直接子节点的节点不能使用CPU的地址域。为了得到一个内存映射的地址设备树必须制定如何从一个域地址转换到另一个域。ranges属性就是用于这个目的的。这里是添加了ranges属性的设备树例子。/ { compatible acme,coyotes-revenge; #address-cells 1; #size-cells 1; ... 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 ethernet0,0 { compatible smc,smc91c111; reg 0 0 0x1000; }; i2c1,0 { compatible acme,a1234-i2c-bus; #address-cells 1; #size-cells 0; reg 1 0 0x1000; rtc58 { compatible maxim,ds1338; reg 58; }; }; flash2,0 { compatible samsung,k8f1315ebm, cfi-flash; reg 2 0 0x4000000; }; };}; ranges是地址转换清单。ranges表中的每一个条目是包含子节点地址,父节点地址以及子节点地址空间区域大小的元组。每一个域的大小分别由子节点的#address-cells值,父节点的#address-cells值以及子节点的#size-cells值决定。对于本例子中的外部总线子节点地址是2个单元父节点地址是1个单元大小也是一个单元的。三个ranges是这样被转换的从片选0处偏移0开始的地方被映射到地址范围0x10100000...0x1010ffff从片选1处偏移0开始的地方被映射到地址范围0x10160000...0x1016ffff从片选2处偏移0开始的地方被映射到地址范围0x30000000...0x10000000 或者如果父节点和子节点的地址空间是相同的那么节点也可以添加空的ranges属性。空的ranges属性意味着子节点地址空间中的地址被1:1地映射到父节点地址空间。你可能会问为什么地址转换总是用在所有1:1映射的情况下。一些总线比如PCI具有完全不同的地址空间而这些细节必须暴露给操作系统。其他总线具有DMA引擎这些引擎需要知道总线上的实际滴孩子。有时候设备需要被组合在一起因为它们都共享有同样的软件可编程物理地址映射方法。该不该用1:1映射更大程度上取决于操作系统所需的信息以及硬件设计。你应该也注意到i2c1,0节点中没有ranges属性原因是不像外部总线i2c总线上的设备没有内存映射到CPU的地址域。相反地CPU通过i2c1,0设备间接地访问rtc58设备。缺少ranges属性意味着设备不能直接被除了其父节点之外的任何设备访问中断是怎样工作的________________________________________________中断不同于遵循树自然结构的地址范围转换中断信号可能来自以及终止在机器的任何设备。不像设备树中自然表示的设备寻址中断信号是以独立于设备树的节点之间的链接表示的。四个属性用来描述中断的联系interrupt-controller —— 一个空的属性声明接收中断信号的设备为节点#interrupt-cells —— 这是中断控制器节点的属性。它表明这个中断控制器的中断描述符符中有多少单元。类似于#adderss-cells以及#size-cellsinterrupt-parent —— 包含phandle的设备节点的一个属性这个phandle指向它所连接到的中断控制器interrupts —— 包含中断描述符列表的设备节点的一个属性每一个设备上的中断输出信号都有一个 中断描述符是一个或多个单元的数据由#interrupt-cells指定它们指定设备连接到哪个中断输入。大部分设备只有单个中断输出如下面的例子所示不过设备上也有可能有多个中断输出。中断描述符的意义完全取决于中断控制器设备的绑定。每一个中断控制器可以决定需要多少个单元才能唯一地定义一个中断输入。下面的代码添加了连接到我们的Coyotes Revenge样例机器的中断。/ { compatible acme,coyotes-revenge; #address-cells 1; #size-cells 1; interrupt-parent intc; cpus { #address-cells 1; #size-cells 0; cpu0 { compatible arm,cortex-a9; reg 0; }; cpu1 { compatible arm,cortex-a9; reg 1; }; }; serial101f0000 { compatible arm,pl011; reg 0x101f0000 0x1000 ; interrupts 1 0 ; }; serial101f2000 { compatible arm,pl011; reg 0x101f2000 0x1000 ; interrupts 2 0 ; }; gpio101f3000 { compatible arm,pl061; reg 0x101f3000 0x1000 0x101f4000 0x0010; interrupts 3 0 ; }; intc: interrupt-controller10140000 { compatible arm,pl190; reg 0x10140000 0x1000 ; interrupt-controller; #interrupt-cells 2; }; spi10115000 { 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 ethernet0,0 { compatible smc,smc91c111; reg 0 0 0x1000; interrupts 5 2 ; }; i2c1,0 { compatible acme,a1234-i2c-bus; #address-cells 1; #size-cells 0; reg 1 0 0x1000; interrupts 6 2 ; rtc58 { compatible maxim,ds1338; reg 58; interrupts 7 3 ; }; }; flash2,0 { compatible samsung,k8f1315ebm, cfi-flash; reg 2 0 0x4000000; }; };}; 有一些事情需要注意这个机器只有一个中断控制器,interrupt-controller10140000标签intc:已经被添加到中断控制器节点并且标签被用来分配指向根节点的interrupt-parent属性的phandle。这个interrupt-parent值变成了系统的默认值因为所有的子节点都继承了它除非它被显示地覆盖。每一个设备都使用一个interrupt属性来制定一个不同的中断输入信号。#interrupt-cells是2因此每一个中断描述符有2个单元。这个例子采用了使用了常见的模式用第一个单元来编码中断线号用第二个单元来编码标志比如高有效还是低有效又或者是边缘触发还是电平触发。对于任何给定的中断控制器请参考控制器绑定文档来了解描述符是怎样编码的。 设备特定数据除了公共的属性之外我们可以添加任何属性以及子节点到节点。我们可以添加操作系统需要的任何数据只要遵守一些规则即可。首先新的设备特定的属性名字应该使用生产厂商的前缀从而它们不会与现存的标准属性名称冲突。其次属性以及子节点的意义必须以绑定的形式记录下来从而设备驱动作者了解怎样翻译数据。绑定记录一个特定的compatible值意味着什么它应该要有什么属性它可能会有什么样的子节点以及设备表示什么。每一个唯一的compatible值应该有它自己的绑定或者声明与其他compatible值得兼容性。新设备的绑定在这个wiki中被记录。请看主页描述文档格和审查过程。第三请将新的绑定提交到devicetree-discusslists.ozlabs.org邮件列表进行审查。审查新的绑定会抓住许多将来可能导致问题常见错误。特殊节点________________________________________________aliases节点一个特定的节点通常是以完整的路径来引用比如/external-bus/ethernet0,0不过当一个用户真的想知道“哪个设备是eth0”时这将会很繁琐。aliases节点可以用来为一个完整的设备路径分配一个短的别名。比如aliases { ethernet0 eth0; serial0 serial0; }; 当需要为设备指定一个标示符时操作系统欢迎大家使用别名。你将会注意到这里使用了一个新的语法。propert label; 语法分配由标签引用并作为字符串属性的的完整节点路径。这与早前使用的phandle label;不同它在单元中嵌入了phandle值。chosen节点chosen节点并不代表真实的设备不过充当为在固件和操作系统之间传递数据的地方比如启动参数。在chosen节点中的数据不代表硬件。典型情况下chosen节点在.dts源文件中留空并在启动时填充。在我们的系统中固件可能会添加下面的内容到chosen节点chosen { bootargs root/dev/nfs rw nfsroot192.168.1.1 consolettyS0,115200; }; 高级主题________________________________________________高级的样例机器现在我们已经理解了基本定义让我们添加一些硬件到样例机器中来讨论一些更复杂的使用案例。高级的样例机器添加了一个PCI主桥配有内存映射到0x10180000的控制寄存器和编程至从0x80000000地址以上开始的BARs。假设我们已经知道关于设备树以上内容我们可以从添加如下节点描述PCI主桥开始。pci10180000 { compatible arm,versatile-pci-hostbridge, pci; reg 0x10180000 0x1000; interrupts 8 0; }; 接下来的内容大部分为PCI设备相关不太常用由于本人精力有限留着以后再翻译了参考链接 http://blog.csdn.net/21cnbao/article/details/8457546