首页 > 编程知识 正文

linux查看设备树,数据库语法树

时间:2023-05-04 13:41:37 阅读:27544 作者:4615

概念Linux内核从3.x开始引入设备树的概念,在显示驱动代码与设备信息相分离设备树之前,有关设备的所有具体信息都将写入驱动程序中,当外围设备发生更改时,将重写驱动程序代码引入设备树后,驱动程序代码只处理驱动程序逻辑,有关设备的具体信息存储在设备树文件中。 这样,如果只有硬件接口信息的变化而没有驱动程序逻辑的变化,驱动程序开发人员只需要修改设备树文件信息,不需要改写驱动程序代码。 例如,在ARM Linux中,与.dts(device tree source)文件一个ARM相对应的machine位于内核的"arch/arm/boot/dts/"目录中, 例如,exynos4412参考板的板级设备树文件是http://www.Sina,该文件用"arch/arm/boot/dts/exynos4412-origen.dts"编译成二进制文件http://www.Sina.com

基于相同的软件分层设计思想,一个SoC可能支持多个machine,因此如果每个machine的设备树写为完全独立的$make dtbs命令,则相当多的http://www.Sina 为了解决这个问题,Linux设备树的目录这样每个3358www.Sina.com/只有自己不同的部分,公共部分只需要.dtb文件,可以更好地管理整个设备树下面以` Linux4.8.5源代码附带的dm9000网卡为例分析设备树的使用和移植。 该网卡的设备树节点信息在.dts文件中有详细说明,其网卡驱动程序源代码为.dts

设备树框架设备树以树结构描述设备信息,具有以下特征

每个设备树文件都有根节点,每个设备都是节点。 节点之间可以嵌套形成父子关系,由此可以容易地记述设备之间的关系。 每个设备的属性由一组密钥值对(键值对)描述。 用于说明各属性; 所以,一个设备树的基本框架可以写如下。.dtsi文件

//根节点node1{ //node1是节点名,/的子节点key=value; //node1属性. node2{ //node2是node1的子节点key=value; //node2的属性.//node2的说明到此为止node3{ key=value; }节点名称理论节点名称可以是31个字符以下的ASCII字符串,并且

Linux内核还承诺将设备名称写为name[@unit_address]。 其中,name是设备名称,长度最多可以为31个字符。 unit_address通常是设备地址,用于唯一标识节点。 以下是典型的节点名称的写法

上面的节点名称为firmware,节点路径为/firmware@0203f000。 请注意,从节点名称中查找节点的API参数没有名为“@xxx”的部分。

Linux设备树还包含特殊的节点,如chosen。 chosen节点不是描述实际设备,而是由firmware用于将数据传递到操作系统,如引导装载器将内核启动参数传递到内核

查找引用节点时,必须写为.dts。 这样做在节点嵌套得很深时就不方便了。 因此,在设备树中,为了省去冗馀路径,可以将引用标记为节点,如下所示: 这将产生类似于函数调用的效果。 编译设备树时,使用"include"相应的.dtsi文件、参考,可以避免移植者到处查找节点,直接在板级. dts进行更改即可。

以下示例直接引用dtsi中的节点,并添加/修改新的属性信息

>

KEY

在设备树中,键值对是描述属性的方式,比如,Linux驱动中可以通过设备节点中的"compatible"这个属性查找设备节点。
Linux设备树语法中定义了一些具有规范意义的属性,包括:compatible, address, interrupt等,这些信息能够在内核初始化找到节点的时候,自动解析生成相应的设备信息。此外,还有一些Linux内核定义好的,一类设备通用的有默认意义的属性,这些属性一般不能被内核自动解析生成相应的设备信息,但是内核已经编写的相应的解析提取函数,常见的有 "mac_addr""gpio""clock""power""regulator" 等等。

compatible

设备节点中对应的节点信息已经被内核构造成struct platform_device。驱动可以通过相应的函数从中提取信息。compatible属性是用来查找节点的方法之一,另外还可以通过节点名或节点路径查找指定节点。dm9000驱动中就是使用下面这个函数通过设备节点中的"compatible"属性提取相应的信息,所以二者的字符串需要严格匹配。
在下面的这个dm9000的例子中,我们在相应的板级dts中找到了这样的代码块:

然后我们取内核源码中找到dm9000的网卡驱动,从中可以发现这个驱动是使用的设备树描述的设备信息(这不废话么,显然用设备树好处多多)。我们可以找到它用来描述设备信息的结构体,可以看出,驱动中用于匹配的结构使用的compatible和设备树中一模一样,否则就可能无法匹配,这里另外的一点是struct of_device_id数组的最后一个成员一定是空,因为相关的操作API会读取这个数组直到遇到一个

address

(几乎)所有的设备都需要与CPU的IO口相连,所以其IO端口信息就需要在设备节点节点中说明。常用的属性有

#address-cells,用来描述子节点"reg"属性的地址表中用来描述首地址的cell的数量,#size-cells,用来描述子节点"reg"属性的地址表中用来描述地址长度的cell的数量。

有了这两个属性,子节点中的"reg"就可以描述一块连续的地址区域。下例中,父节点中指定了#address-cells = <2>;#size-cells = <1>,则子节点dev-bootscs0中的reg中的前两个数表示一个地址,即MBUS_ID(0xf0, 0x01)0x1045C,最后一个数的表示地址跨度,即是0x4

interrupts

一个计算机系统中大量设备都是通过中断请求CPU服务的,所以设备节点中就需要在指定中断号。常用的属性有

interrupt-controller 一个空属性用来声明这个node接收中断信号,即这个node是一个中断控制器。#interrupt-cells,是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符,用来描述子节点中"interrupts"属性使用了父节点中的interrupts属性的具体的哪个值。一般,如果父节点的该属性的值是3,则子节点的interrupts一个cell的三个32bits整数值分别为:<中断域 中断 触发方式>,如果父节点的该属性是2,则是<中断 触发方式>interrupt-parent,标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的interrupts,一个中断标识符列表,表示每一个中断输出信号

设备树中中断的部分涉及的部分比较多,interrupt-controller表示这个节点是一个中断控制器,需要注意的是,一个SoC中可能有不止一个中断控制器,这就会涉及到设备树中断组织的很多概念,下面是在文件"arch/arm/boot/dts/exynos4.dtsi"中对exynos4412的中断控制器(GIC)节点描述:

要说interrupt-parent,就得首先讲讲Linux设备管理中对中断的设计思路演变。随着linux kernel的发展,在内核中将interrupt controller抽象成irqchip这个概念越来越流行,甚至GPIO controller也可以被看出一个interrupt controller chip,这样,系统中至少有两个中断控制器了,另外,在硬件上,随着系统复杂度加大,外设中断数据增加,实际上系统可以需要多个中断控制器进行级联,形成事实上的硬件中断处理结构:

在这种趋势下,内核中原本的中断源直接到中断号的方式已经很难继续发展了,为了解决这些问题,linux kernel的dydxgz们就创造了irq domain(中断域)这个概念。domain在内核中有很多,除了irqdomain,还有power domain,clock domain等等,所谓domain,就是领域,范围的意思,也就是说,任何的定义出了这个范围就没有意义了。如上所述,系统中所有的interrupt controller会形成树状结构,对于每个interrupt controller都可以连接若干个外设的中断请求(interrupt source,中断源),interrupt controller会对连接其上的interrupt source(根据其在Interrupt controller中物理特性)进行编号(也就是HW interrupt ID了)。有了irq domain这个概念之后,这个编号仅仅限制在本interrupt controller范围内,有了这样的设计,CPU(Linux 内核)就可以根据级联的规则一级一级的找到想要访问的中断。当然,通常我们关心的只是内核中的中断号,具体这个中断号是怎么找到相应的中断源的,我们作为程序员往往不需要关心,除了在写设备树的时候,设备树就是要描述嵌入式软件开发中涉及的所有硬件信息,所以,设备树就需要准确的描述硬件上处理中断的这种树状结构,如此,就有了我们的interrupt-parant这样的概念:用来连接这样的树状结构的上下级,用于表示这个中断归属于哪个interrupt controller,比如,一个接在GPIO上的按键,它的组织形式就是:

中断源--interrupt parent-->GPIO--interrupt parent-->GIC1--interrupt parent-->GIC2--...-->CPU

有了parant,我们就可以使用一级一级的偏移量来最终获得当前中断的绝对编号,这里,可以看出,在我板子上的dm9000的的设备节点中,它的"interrupt-parent"引用了"exynos4x12-pinctrl.dtsi"(被板级设备树的exynos4412.dtsi包含)中的gpx0节点:

而在gpx0节点中,指定了"#interrupt-cells = <2>;",所以在dm9000中的属性"interrupts = <6 4>;"表示dm9000的的中断在作为irq parant的gpx0中的中断偏移量,即gpx0中的属性"interrupts"中的"<0 22 0>",通过查阅exynos4412的手册知道,对应的中断号是EINT[6]。

gpio

gpio也是最常见的IO口,常用的属性有

"gpio-controller",用来说明该节点描述的是一个gpio控制器"#gpio-cells",用来描述gpio使用节点的属性一个cell的内容,即 `属性 = <&引用GPIO节点别名 GPIO标号 工作模式>

GPIO的设置同样采用了上述偏移量的思想,比如下面的这个led的设备书,表示使用GPX2组的第7个引脚:

驱动自定义key

针对具体的设备,有部分属性很难做到通用,需要驱动自己定义好,通过内核的属性提取解析函数进行值的获取,比如dm9000节点中的下面这句就是自定义的节点属性,用以表示配置EEPROM不可用。

VALUE

dts描述一个键的值有多种方式,当然,一个键也可以没有值

字符串信息

32bit无符号整型数组信息

二进制数数组

字符串哈希表

混合形式

上述几种的混合形式

设备树/驱动移植实例

设备树就是为驱动服务的,配置好设备树之后还需要配置相应的驱动才能检测配置是否正确。比如dm9000网卡,就需要首先将示例信息挂接到我们的板级设备树上,并根据芯片手册和电路原理图将相应的属性进行配置,再配置相应的驱动。需要注意的是,dm9000的地址线一般是接在片选线上的,所以设备树中就应该归属与相应片选线节点,我这里用的exynos4412,接在了bank1,所以是"<0x50000000 0x2 0x50000004 0x2>"
最终的配置结果是:

勾选相应的选项将dm9000的驱动编译进内核。

make menuconfig[*] Networking support ---> Networking options ---> <*> Packet socket <*>Unix domain sockets [*] TCP/IP networking [*] IP: kernel level autoconfigurationDevice Drivers ---> [*] Network device support ---> [*] Ethernet driver support (NEW) ---> <*> DM9000 supportFile systems ---> [*] Network File Systems (NEW) ---> <*> NFS client support [*] NFS client support for NFS version 3 [*] NFS client support for the NFSv3 ACL protocol extension [*] Root file system on NFS

执行make uImage;make dtbs,tftp下载,成功加载nfs根文件系统并进入系统,表示网卡移植成功

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。