目录
设备树的引入
设备树具体框架
设备树的属性
label
address-cells和size-cells
compatible
model
status
reg
设备树的编译
内核对设备树的处理
plateform_device如何对应plateform_driver
设备树的引入
之前已经学习了解过了总线驱动模型的概念,也就是驱动的分层思想。上层驱动负责应用层调用的实现,下层驱动则包括两个文件,一个是设备资源文件,另一个则是驱动文件。一个驱动文件可能会存在对应多种设备资源文件的情况,而设备资源文件又存在很多,这造成了Linux内核十分的臃肿,对此,引入设备树来解决这个问题。
可以把所有需要用到的外设定义到设备树文件(dts)上面,当boot启动的时候,会把设备树上面的信息解析到内核当中。依靠这个文件,可以十分有效的避免了因为板子引脚资源不同,导致的产生的多余资源文件冗余的问题。
设备树具体框架
设备树是一种类似于树状的结构,最底层是根节点(/),然后根节点下又延伸出许多的分支,分支之下可以再次延伸出不同的分支。
设备树的语法如下
每个节点以 { 开始,以 }; 结束,/表示根节点,所有的节点都是在根节点之上
/{
子节点1{
子节点1的子节点{
};
};
子节点2{
};
};
设备树的属性
label
设备树的label属性相当于给这个节点取了另外一个名字,方便引用以及修改。
如下所示,给这个串口取了一个label属性,为uart0,此时uart0就可以表示是这个节点了,我们可以很方便的引用这个标签,来表示这个节点。
address-cells和size-cells
address-cells的意思是:用多少个32位的数据来表示一个地址
size-cells的意思是:用多少个32位的数据来表示大小
compatible
compatible属性的意思是兼容,在设备树中定义一般的意思是为了区分此设备兼容的驱动程序。该属性使用字符串来表示,可以有多个字符串,当使用的时候,会根据字符串的顺序优先级来匹配对应的驱动。
一般来说会按照 “ 厂家名,模块名 ” ,这样来使用该属性
model
model属性是一个字符串,它准确的定义出本身的硬件设备到底是什么。也就是说,model属性表明的就是自身到底是什么板子
status
status主要用来表示此节点是否可用。这个属性有一点重要的作用是,假如我这里有两块板子,板子A以及板子B,同时使用了一个公板的设备树节点XXX.dtsi(dtsi表示可以被设备树使用#include包含),此时我的板子A不需要使用到公板的uart节点,那么我们直接在板子A的设备树中,使用&uart来引用此节点,再把状态设置为disable即可
reg
reg的意思是register,意思就是寄存器的地址,在设备树中是成对存在的,reg属性的值,由address-cells和size-cells属性来决定。reg属性表示的是一段空间,如下的意思是,其实地址为0x80000000,大小为0x20000000的地址大小。
设备树的编译
设备树在内核中,一般在 /arc/arm/boot/dts 目录下,如果是64位,那么在/arc/arm64/boot/dts 这个目录下
设备树的编译,我们只需要在内核源码的目录下,输入如下命令 make dtbs ,即可进行编译。在编译前,我们需要先设置好环境变量。使用 make dtbs V=1 ,编译设备树,同时V=1 查看如何编译
编译完成后,拷贝新的设备树文件到板子的 /boot/ 目录下,重启板子,即可替换新的设备树
内核对设备树的处理
当我们把设备树编译为dtb文件并加载到内核后,当启动开发板,boot会解析设备树,传递给内核,内核会解析这些设备树节点,每一个节点都会转化为device_node结构体,而有些device_node结构体会被转化为plateform_device结构体
但是并不是每一个节点都可以被转化为plateform_device结构体,想要转化为plateform_device结构体需要如下要求:
一、根节点下的子节点存在compatible属性,这点很好理解,因为有了compatible属性才可以兼容驱动,如果连compatible属性都没有的话,那么就是没有兼容的驱动,那么也没必要转化为plateform_device了
二、假如某个子节点的父节点的compatible属性存在如下的特殊情况“simple-bus”、“simple-mfd”、“isa”、“arm,amba-bus”,那么它的子节点(子节点也需要存在compatible属性)也可以转化为plateform_device结构体
三、总线I2C、SPI节点下的子节点不会转化为plateform_device结构体,因为他们应该交给总线的驱动来处理,而不是单独拿出来处理
plateform_device如何对应plateform_driver
在plateform_device结构体下,存在一个of_node属性,里面的struct property *properties指向该设备节点的所有属性的链表,里面可以得到设备树节点信息,和platform_driver的of_match_table属性进行对比,如果相等,则是配对成功
of_match_table是一个结构体指针,里面可以有多个结构体,表示该驱动可以支持多个设备
当设备和驱动配对成功之后,platform_driver对调用probe函数,用来获取设备树节点的信息。设备树的属性如果不是自定的,那么可以直接获取,比如说reg属性,就是MEM资源,interrupts属性,就是IRQ资源,这些都是可以直接调用函数platform_get_resource获取。
那么对于不是标准的属性,我们应该如何去获取呢。/根节点会保存在of_root这个全局变量中,我们使用这个根节点,来遍历整个设备树(使用系统提供的函数),获取到自己想要的那个节点,就可以获取到非标准化属性的信息了(通过节点获取到属性也是通过系统提供的函数)。