DTS是Device Tree Source的缩写,用来描述设备的硬件细节。在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data。为了去掉这些垃圾代码,Linux采用DTS这种新的数据结构来描述硬件设备。采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。

有关DTS的语法格式,网上有很多资料,这里我就不再赘述了。本文主要讲Linux是怎样加载DTS设备节点的流程。下面以高通QCT8974平台(Linux内核)为例进行讲解:

(1)使用DTS注册平台总线的过程

在讲注册过程之前,我们先看看DTS是怎样描述平台总线结构的,以i2c总线为例:

[c] view plaincopyprint?
  1. / {
  2. model = "Qualcomm MSM 8974";
  3. compatible = "qcom,msm8974";
  4. interrupt-parent = <&intc>;
  5. aliases {
  6. spi0 = &spi_0;
  7. spi7 = &spi_7;
  8. sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
  9. sdhc2 = &sdhc_2; /* SDC2 SD card slot */
  10. sdhc3 = &sdhc_3; /* SDC3 SDIO slot */
  11. sdhc4 = &sdhc_4; /* SDC4 SDIO slot */
  12. };
  13. memory {
  14. secure_mem: secure_region {
  15. linux,contiguous-region;
  16. reg = <0 0x7800000="">;
  17. label = "secure_mem";
  18. };
  19. adsp_mem: adsp_region {
  20. linux,contiguous-region;
  21. reg = <0 0x2000000="">;
  22. label = "adsp_mem";
  23. };
  24. };
  25. intc: interrupt-controller@F9000000 {
  26. compatible = "qcom,msm-qgic2";
  27. interrupt-controller;
  28. #interrupt-cells = <3>;
  29. reg = <0xf9000000 0x1000="">,
  30. <0xf9002000 0x1000="">;
  31. };
  32. msmgpio: gpio@fd510000 {
  33. compatible = "qcom,msm-gpio";
  34. gpio-controller;
  35. #gpio-cells = <2>;
  36. interrupt-controller;
  37. #interrupt-cells = <2>;
  38. reg = <0xfd510000 0x4000="">;
  39. ngpio = <146>;
  40. interrupts = <0 208="" 0="">;
  41. qcom,direct-connect-irqs = <8>;
  42. };
  43. wcd9xxx_intc: wcd9xxx-irq {
  44. compatible = "qcom,wcd9xxx-irq";
  45. interrupt-controller;
  46. #interrupt-cells = <1>;
  47. interrupt-parent = <&msmgpio>;
  48. interrupts = <72 0="">;
  49. interrupt-names = "cdc-int";
  50. };
  51. timer {
  52. compatible = "arm,armv7-timer";
  53. interrupts = <1 2="" 0="" 1="" 3="" 0="">;
  54. clock-frequency = <19200000>;
  55. };
  56. i2c_0: i2c@f9967000 { /* BLSP#11 */
  57. cell-index = <0>;
  58. compatible = "qcom,i2c-qup";
  59. reg = <0xf9967000 0x1000="">;
  60. #address-cells = <1>;
  61. #size-cells = <0>;
  62. reg-names = "qup_phys_addr";
  63. interrupts = <0 105="" 0="">;
  64. interrupt-names = "qup_err_intr";
  65. qcom,i2c-bus-freq = <100000>;
  66. qcom,i2c-src-freq = <50000000>;
  67. };
  68. i2c_2: i2c@f9924000 {
  69. cell-index = <2>;
  70. compatible = "qcom,i2c-qup";
  71. reg = <0xf9924000 0x1000="">;
  72. #address-cells = <1>;
  73. #size-cells = <0>;
  74. reg-names = "qup_phys_addr";
  75. interrupts = <0 96="" 0="">;
  76. interrupt-names = "qup_err_intr";
  77. qcom,i2c-bus-freq = <100000>;
  78. qcom,i2c-src-freq = <50000000>;
  79. };
  80. spi_0: spi@f9923000 {
  81. compatible = "qcom,spi-qup-v2";
  82. reg = <0xf9923000 0x1000="">;
  83. interrupts = <0 95="" 0="">;
  84. spi-max-frequency = <19200000>;
  85. #address-cells = <1>;
  86. #size-cells = <0>;
  87. gpios = <&msmgpio 3 0>, /* CLK  */
  88. <&msmgpio 1 0>, /* MISO */
  89. <&msmgpio 0 0>; /* MOSI */
  90. cs-gpios = <&msmgpio 9 0>;
  91. };
  92. };

从上面可知,系统平台上挂载了很多总线,如i2c、spi、uart等等,每一个总线分别被描述为一个节点。Linux在启动后,到C入口时,会执行以下操作,加载系统平台上的总线和设备:

start_kernel() --> setup_arch() --> unflatten_device_tree()

unflatten_device_tree()的代码如下:

[c] view plaincopyprint?
  1. void __init unflatten_device_tree(void)
  2. {
  3. __unflatten_device_tree(initial_boot_params, &allnodes,
  4. early_init_dt_alloc_memory_arch);
  5. /* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */
  6. of_alias_scan(early_init_dt_alloc_memory_arch);
  7. }

在执行完unflatten_device_tree()后,DTS节点信息被解析出来,保存到allnodes链表中,allnodes会在后面被用到。

随后,当系统启动到board文件时,会调用.init_machine,高通8974平台对应的是msm8974_init()。接着调用of_platform_populate(....)接口,加载平台总线和平台设备。至此,系统平台上的所有已配置的总线和设备将被注册到系统中。注意:不是dtsi文件中所有的节点都会被注册,在注册总线和设备时,会对dts节点的状态作一个判断,如果节点里面的status属性没有被定义,或者status属性被定义了并且值被设为“ok”或者“okay”,其他情况则不被注册到系统中。

(2)使用DTS注册总线设备的过程

上面讲了Linux怎样使用DTS注册平台总线和平台设备到系统中,那么其他设备,例如i2c、spi设备是怎样注册到系统中的呢?下面我们就以i2c设备为例,讲解Linux怎样注册i2c设备到系统中。

以高通8974平台为例,在注册i2c总线时,会调用到qup_i2c_probe()接口,该接口用于申请总线资源和添加i2c适配器。在成功添加i2c适配器后,会调用of_i2c_register_devices()接口。此接口会解析i2c总线节点的子节点(挂载在该总线上的i2c设备节点),获取i2c设备的地址、中断号等硬件信息。然后调用request_module()加载设备对应的驱动文件,调用i2c_new_device(),生成i2c设备。此时设备和驱动都已加载,于是drvier里面的probe方法将被调用。后面流程就和之前一样了。

简而言之,Linux采用DTS描述设备硬件信息后,省去了大量板文件垃圾信息。Linux在开机启动阶段,会解析DTS文件,保存到全局链表allnodes中,在掉用.init_machine时,会跟据allnodes中的信息注册平台总线和设备。值得注意的是,加载流程并不是按找从树根到树叶的方式递归注册,而是只注册根节点下的第一级子节点,第二级及之后的子节点暂不注册。Linux系统下的设备大多都是挂载在平台总线下的,因此在平台总线被注册后,会根据allnodes节点的树结构,去寻找该总线的子节点,所有的子节点将被作为设备注册到该总线上。

Linux加载DTS设备节点的过程(以高通8974平台为例)相关推荐

  1. 高通平台msm8953 Linux DTS(Device Tree Source)设备树详解之二(DTS设备树匹配过程)

    本系列导航: 高通平台8953  Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...

  2. 高通SDX12平台:LINUX上MBIM功能异常

    高通SDX12平台 LINUX上MBIM功能异常 1. 问题描述 按照高通SDX12平台产品规格,其支持RMNET.ECM.RNDIS.PPP.MBIM等拨号:但经测试,发现Windos下MBIM功能 ...

  3. Linux驱动(11)--生成设备节点

    生成设备节点 1. 生成设备节点 1.1 杂项设备 1.2 注册文件 1.3 生成设备节点源代码 1.4 生成设备节点步骤 1.5 需要注意的问题 2. 调用设备节点 1. 生成设备节点 1.1 杂项 ...

  4. linux 加载u盘、光盘、软盘 mount使用指南

    <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />  一.Linu ...

  5. linux ntfs 密码,linux 加载ntfs和fat32分区

    原标题:linux 加载ntfs和fat32分区 纯手工打造每一篇开源资讯与技术干货,数十万程序员和Linuxer已经关注. 导读 关于加载ntfs和fat文件系统的文章极多,但写的不太明确,新手上路 ...

  6. CH340驱动问题,由于 Windows 无法加载这个设备所需的驱动程序,导致这个设备工作异常。 (代码 31)

    -------------------------------------以下是2022.11.8更新 现在可以了,把端口名称换了后(同学告诉我的),刚开始还是不行,换了个单片机烧可以,再换回之前的也 ...

  7. 如何让linux加载当前目录的动态库

    debian从7.0开始支持multiarch,64位库的路径改到/usr/lib/x86_64-linux-gnu了,mint.ubuntu这些衍生版有没有跟着改我就不清楚了. deepin lin ...

  8. zTree 异步加载 添加子节点重复问题 .

    最近写程序需要一颗可以一步加载的树,发现ztree功能很强大.搞了好久才知道怎么实现树节点的异步加载, 在这里记录下来以方便以后自己忘记了.代码如下: <spanstyle="font ...

  9. Linux Shell 判断块设备节点是否存在

    /************************************************************************** Linux Shell 判断块设备节点是否存在* ...

最新文章

  1. linux打开bash后报错:~/.bashrc: 没有那个文件或目录
  2. 父元素 高度固定,如何使其中的文字垂直居中?
  3. OSSemPend()--等待一个信号量
  4. MySQL的SQL预处理(Prepared)
  5. CNBlog客户端--第一阶段记录
  6. 3dmax导出fbx事项注意
  7. 445端口的简单利用
  8. 无线路灯项目——SIM900A调试
  9. Android等宽字体
  10. Pyecharts之折线图与柱状图组合绘制
  11. EXCEL的去重去除某个字段后全部操作
  12. win10微软官网地址
  13. operator int()用法
  14. 深度学习应用于脑电信号处理
  15. 第015篇:ArcGIS中标注的使用方法(二)
  16. 关于ZETag云标签你了解多少?
  17. html做键盘,用html+js+css做一个模拟键盘
  18. 尘锋信息scrm与企鲸客的功能差别
  19. MAC 下 CocoaPods 安装与使用来管理项目第三方框架
  20. stm32F105的Canable开源usb-can项目

热门文章

  1. 007_ServletConfig
  2. php设置文件权限问题,关于.user.ini以及php访问上级文件权限问题
  3. coreldraw 导入面料_Coreldraw文件导入Photoshop方法
  4. Git常用命令和Git团队使用规范指南
  5. Android多媒体编程
  6. java捕获定时器抛出的异常_详细了解Java中定时器Timer的使用及缺陷分析
  7. 计算机控制系统如何设计,计算机控制系统设计
  8. firefox如何不让网站登录失效_Firefox Preview 4开放下载:引入登录管理、热门网站等功能...
  9. Java设计模式(十五):桥接设计模式
  10. mysql创建函数1418_Mysql中创建函数报“ERROR 1418 ”的解决方法