做优品购类似网站,网站开发从入门到精通,个人网站托管,企业网站博客上如何推广在平台总线驱动模型中资源和驱动已经从逻辑上和代码组织上进行了分离#xff0c;但每次调整资源还是会涉及到内核#xff0c;所以现在更加流行的是设备树方式。设备树的好处是通过独立于内核存在#xff0c;这样如果设备上外设功能启用与否以及位置变动的话很多时候不用修改…在平台总线驱动模型中资源和驱动已经从逻辑上和代码组织上进行了分离但每次调整资源还是会涉及到内核所以现在更加流行的是设备树方式。设备树的好处是通过独立于内核存在这样如果设备上外设功能启用与否以及位置变动的话很多时候不用修改与编译内核只要重新处理设备树文件即可。 设备树代码或者都算不上代码只是一些树状的数据有点像JSON。 设备树源文件有两种尾缀分别是 dts 以及 dtsi。dtsi 常规意义上定义 SoC 级别的硬件 信息而 dts 常规意义上定义 board 级别的硬件信息。dts 通过#include 的方式包含进 dtsi 文件 通常每个系列的芯片厂家都会编写好后缀为 .dtsi 的设备树文件里面把芯片基本上的功能资源都定义了。而对于某个具体的电路板来说只要编写后缀为 .dts 的文件在其中引入前述的 .dtsi 文件然后在 .dts 文件中选择性启用 .dtsi 中已经定义好的并且电路中需要用到的功能。当然在 .dts 文件中也可以自定义新的功能。
.dts 文件最终可以编译为 .dtb 文件系统在启动的时候会通过Bootloader将该文件传递给内核内核就会解析取用其中的资源并与驱动进行匹配。如果资源需要调整通常只需要调整 .dts 文件生成新的 .dtb 文件即可。
设备树的概念 设备树只是用来给内核里的驱动程序 指定硬件的信息 。比如 LED 驱动在内核的驱动程序里去操作寄存器但是操作哪一个引脚这由设备树指定。 设备树 怎么描述这棵树 我们需要编写设备树文件 (dts: device tree source) 它需要编译为 dtb(device tree blob)文件内核使用的是 dtb 文件。 设备树在系统中的编译流程 一个单板启动时 u-boot 先运行它的作用是启动内核。 U-boot 会把内核 和设备树文件都读入内存然后启动内核。在启动内核时会把设备树在内存中的地址告诉内核。 当 U-Boot 通过 ARM 通用寄存器 r2 将设备树 dtb 文件 memory 地址传递给 kernel 之 后kernel 会将平滑的 FDT 文件解析成 EDT 文件kernel 将 dtb 进行加工处理、解析成device_node再将 device_node 转换成各色的 device 如 platform_device 供驱动代码使用。 将创建好的platform_device绑定到platform_bus上 将device 增加进 linux 系统 设备树文件不需要我们从零写出来内核支持了某款芯片比如 imx6ull在内核的arch/arm/boot/dts 目录下就有了能用的设备树模板一般命名为 xxxx.dtsi。“i”表示“include”被别的文件引用的。 我们使用某款芯片制作出了自己的单板所用资源跟 xxxx.dtsi 是大部分相同小部分不同所以需要引脚 xxxx.dtsi 并修改。 dtsi 文件跟 dts 文件的语法是完全一样的 编译、更换设备树 我们一般不会从零写 dts 文件而是修改。程序员水平有高有低怎么知道改得对不对需要编译一下。并且内核直接使用 dts 文件的话就太低效了它也需要使用二进制格式的 dtb 文件。 kernel 编译时使用 scritpts 下的 dtc 工具宿主机同样也有 dtc 工具根据 arch/arm/boot/dts/Makefile 中的规则将设备树源码编译成 dtb 格式的 ABI 文件。 在内核中直接 make 设置 ARCH 、 CROSS_COMPILE 、 PATH 这三个环境变量后进入 ubuntu 上板子内核源码的目录执行如下命令即可编译 dtb 文件make dtbs V1 内核对设备树的处理 从源代码文件 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/ 做得好的厂家也会提供设备树的说明文档 参考同类型单板的设备树文件 网上搜索 实在没办法时, 只能去研究驱动源码 原文链接https://blog.csdn.net/Naisu_kun/article/details/130860190