设备树的概念:
设备树只是用来给内核里的驱动程序, 指定硬件的信息 。比如 LED 驱动,在内核的驱动程序里去操作寄存器,但是操作哪一个引脚?这由设备树指定。
一个单板启动时, u-boot 先运行,它的作用是启动内核。 U-boot 会把内核 和设备树文件都读入内存,然后启动内核。在启动内核时会把设备树在内存中的 地址告诉内核。
设备树:
怎么描述这棵树?
我们需要编写设备树文件 (dts: device tree source) ,它需要编译为 dtb(device tree blob)文件,内核使用的是 dtb 文件。
dts文件包含dtsi 文件
设备树文件不需要我们从零写出来,内核支持了某款芯片比如 imx6ull,在内核的arch/arm/boot/dts 目录下就有了能用的设备树模板,一般命名为 xxxx.dtsi。“i”表示“include”,被别的文件引用的。
我们使用某款芯片制作出了自己的单板,所用资源跟 xxxx.dtsi 是大部分相同,小部分不同,所以需要引脚 xxxx.dtsi 并修改。
dtsi 文件跟 dts 文件的语法是完全一样的
编译、更换设备树
我们一般不会从零写 dts 文件,而是修改。程序员水平有高有低,怎么知道改得对不对?需要编译一下。并且内核直接使用 dts 文件的话,就太低效了,它也需要使用二进制格式的 dtb 文件。
在内核中直接 make
设置 ARCH 、 CROSS_COMPILE 、 PATH 这三个环境变量后,进入 ubuntu 上板子内核源码的目录,执行如下命令即可编译 dtb 文件:make dtbs V=1
内核对设备树的处理
从源代码文件 dts 文件开始,设备树的处理过程为:
- dts 在 PC 机上被编译为 dtb 文件;
- u-boot 把 dtb 文件传给内核;
- 内核解析 dtb 文件,把每一个节点都转换为 device_node 结构体;
- 对于某些 device_node 结构体,会被转换为 platform_device 结构体。
哪些设备树节点会被转换为 platform_device
a)根节点下含有compatile 属性的子节点
b)含有特定compatile 属性的节点的子节点
如果一个节点的 compatile 属性,它的值是这 4 者之一:"simple-bus","simple-mfd","isa","arm,amba-bus", 那 么 它 的 子结点 ( 需 含 compatile 属性)也可以转换为 platform_device。
c)总线 I2C、SPI 节点下的子节点:不转换为 platform_device
某个总线下到子节点,应该交给对应的总线驱动程序来处理, 它们不应该被 转换为 platform_device。
怎么转换为 platform_device
内核处理设备树的函数调用过程,这里不去分析;我们只需要得到如下结论:
◼ platform_device 中含有 resource 数组 , 它来自 device_node 的 reg, interrupts 属性 ;
◼ platform_device.dev.of_node 指向 device_node, 可以通过它获得其他属性
platform_device 如何与 platform_driver 配对
从设备树转换得来的 platform_device 会被注册进内核里,以后当我们每 注册一个 platform_driver 时,它们就会两两确定能否配对,如果能配对成功 就调用 platform_driver 的 probe 函数。
1 最先比较:是否强制选择某个 driver
⚫ 比较 : platform_device.driver_override 和 platform_driver.driver.name
可以设置 platform_device 的 driver_override ,强制选择某个 platform_driver 。
2 然后比较:设备树信息
⚫ 比较: platform_device.dev.of_node 和 p latform_driver.driver.of_match_table 。
由设备树节点转换得来的 platform_device 中,含有一个结构体: of_node 。
它的类型如下
如果一个 platform_driver 支 持 设 备 树 , 它 的 platform_driver.driver.of_match_table 是一个数组,类型如下:
使用设备树信息来判断 dev 和 drv 是否配对时 :
首先 ,如果 of_match_table 中含有 compatible 值,就跟 dev 的 compatile 属性比较,若一致则成功,否则返回失败;
其次 ,如果 of_match_table 中含有 type 值,就跟 dev 的 device_type 属性 比较,若一致则成功,否则返回失败;
最后 ,如果 of_match_table 中含有 name 值,就跟 dev 的 name 属性比 较,若一致则成功,否则返回失败。
而设备树中建议不再使用 devcie_type 和 name 属性,所以基本上只使用设 备节点的 compatible 属性来寻找匹配的 platform_driver 。
3 接下来比较:platform_device_id
⚫ 比较 :platform_device. name 和 platform_driver.id_table[i].name ,id_table 中可能有多项。
platform_driver.id_table 是“ platform_device_id ”指针,表示该 drv 支持若干个 device,它里面列出了各个 device 的 {.name, .driver_data} , 其中的“name ”表示该 drv 支持的设备的名字, driver_data 是些提供给该 device 的私有数据。
4 最后比较
⚫ 比较:platform_device.name 和 platform_driver.driver.name
platform_driver.id_table 可能为空, 这 时 可 以 根 据 platform_driver.driver.name 来 寻 找 同 名 的 platform_device。
怎么修改设备树文件
一个写得好的驱动程序 , 它会尽量确定所用资源。只把不能确定的资源留给 设备树, 让设备树来指定。根据原理图确定 " 驱动程序无法确定的硬件资源 ", 再在设备树文件中填写对应内容。那么 , 所填写内容的格式是什么 ?
使用芯片厂家提供的工具
有些芯片,厂家提供了对应的设备树生成工具,可以选择某个引脚用于某些 功能,就可以自动生成设备树节点。 再把这些节点复制到内核的设备树文件里即可。
看绑定文档
内核文档 Documentation/devicetree/bindings/ 做得好的厂家也会提供设备树的说明文档