linux设备树

目录

一、文件

1、DTS 

2、DTSI

3、DTB

4、DTC

四者关系

二、编译命令

三、新建dtb

四、DTS语法

1 、.dtsi 头文件

2、设备节点

数据形式

3、向节点追加或修改内容

4、标准属性

①compatible 属性和model 属性

②status 属性

③reg属性、#address-cells 和#size-cells 属性

④ranges 属性

5、特殊属性

五、设备树在系统中的体现

 1、根节点“/”各个属性

 2、根节点“/”各子节点

六、特殊节点

1、aliases 子节点

 2、chosen 子节点

七、绑定信息文档


关于设备树历史由来可以自行百度

一、文件

1、DTS 

将这些描述板级硬件信息的内容都从 Linux 内中分离开来,用一个专属的文件格式来描述,这个专属的文件就叫做设备树(Device Tree),扩展名为.dts。这个 DTS 文件采用树形结构描述板级设备,也就是开发板上的设备信息,比如CPU 数量、 内存基地址、 IIC 接口上接了哪些设备、 SPI 接口上接了哪些设备等

2、DTSI

一个 SOC 可以作出很多不同的板子,这些不同的板子肯定是有共同的信息, 将这些共同的信息提取出来作为一个通用的文件,其他的.dts 文件直接引用这个通用文件即可,这个通用文件就是.dtsi 文件,类似于 C 语言中的头文件。一般.dtsi 文件用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UART、 IIC 等

3、DTB

 DTS 是设备树源码文件, DTB 是DTS 编译以后得到的二进制文件

4、DTC

.将dts 编译为.dtb的工具

四者关系

dtsi是通用的”头文件“,有同一个soc的共同信息;dts是采用树形结构的具体的描述板级设备源码;

用dtc工具把dts文件编译后得到dtb文件

二、编译命令

如果要编译 DTS 文件的话需要进入到 Linux 源码根目录下,然后执行如下命令:

make all    或   make dtbs

 “make all”命令是编译 Linux 源码中的所有东西,包括 zImage, .ko 驱动模块以及设备树

如果只是编译设备树的话建议使用“make dtbs”命令

三、新建dtb

如果使用 I.MX6ULL 新做了一个开发板,只需要新建一个开发板对应的.dts 文件
打开 arch/arm/boot/dts/Makefile
 

 将对应的.dtb 文件名添加到 dtb-$(CONFIG_SOC_IMX6ULL)下,这样在编译设备树的时候就会将对应的.dts 编译为二进制的.dtb文件,在移植的时候有具体的操作,这里不再过多描述

四、DTS语法

1 、.dtsi 头文件

和 C 语言一样,设备树也支持头文件,设备树的头文件扩展名为.dtsi

 这里 .dts 文件引用 C 语言中的.h 文件,甚至也可以引用.dts 文件

比如,打开 imx6ull-14x14-evk-gpmi-weim.dts

 这直接引用了.dts 文件,因此在.dts 设备树文件中,可以通过“#include”来引用.h、 .dtsi 和.dts 文件。在编写设备树头文件的时候最好选择.dtsi 后缀

imx6ull.dtsi 是描述 I.MX6ULL 这颗 SOC 内部外设情况信息的,部分如下

 图中cpu0 这个设备节点信息,这个节点信息描述了I.MX6ULL 这颗 SOC 所使用的 CPU 信息,比如架构是 cortex-A7,频率支持 996MHz、 792MHz、528MHz、396MHz 和 198MHz 等等。在 imx6ull.dtsi 文件中不仅仅描述了 cpu0 这一个节点信息,I.MX6ULL 这颗 SOC 所有的外设都描述的清清楚楚

2、设备节点

设备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息

比如,imx6ull.dtsi 文件中缩减出来的设备树文件内容如下

1 / {
2     aliases {
3         can0 = &flexcan1;
4     };
5 
6     cpus {
7         #address-cells = <1>;
8         #size-cells = <0>;
9
10         cpu0: cpu@0 {
11             compatible = "arm,cortex-a7";
12             device_type = "cpu";
13             reg = <0>;
14         };
15     };
16
17     intc: interrupt-controller@00a01000 {
18         compatible = "arm,cortex-a7-gic";
19         #interrupt-cells = <3>;
20         interrupt-controller;
21         reg = <0x00a01000 0x1000>,
22         <0x00a02000 0x100>;
23     };
24 }

第 1 行,“/”是根节点,每个设备树文件只有一个根节点。 imx6ull.dtsi和 imx6ull-alientek-emmc.dts 这两个文件都有一个“/”根节点,这两个“/”根节点的内容会合并成一个根节点
2、 6 和 17 行, aliases、 cpus 和 intc 是三个子节点,在设备树中节点命名格式如下:

node-name@unit-address

“node-name”是节点名字,为 ASCII 字符串,节点名字应该能够清晰的描述出节点的功能,比如“uart1”就表示这个节点是 UART1 外设。“unit-address”一般表示设备的地址或寄存器首地址,如果某个节点没有地址或者寄存器的话“unit-address”可以不要,比如“interrupt-controller@00a01000”
 和“cpu@0”,还有一种是添加了标签,用“:”隔开成了两部分,“:”前面的是节点标签(label),“:”后面的是节点名字,标签格式如下

label: node-name@unit-address

 引入 label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点,比如通过
&cpu0 就可以访问“cpu@0”这个节点,而不需要输入完整的节点名字,有些节点名字是很长的

第 10 行, cpu0 也是一个节点,只是 cpu0 是 cpus 的子节点。每个节点都有不同属性,不同的属性又有不同的内容,属性都是键值对,值可以为空或任意的字节流

数据形式

设备树源码中常用的几种数据形式如下所示:
①、字符串

compatible = "arm,cortex-a7";设置 compatible 属性的值为字符串“arm,cortex-a7”

②、 32 位无符号整数

reg = <0>;设置 reg 属性的值为 0
reg = <0 0x123456 100>;设置为一组值

③、字符串列表

compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand"
属性值也可以为字符串列表,字符串和字符串之间采用“,”隔开
属性 compatible 的值为“fsl,imx6ull-gpmi-nand”和“fsl, imx6ul-gpmi-nand”

3、向节点追加或修改内容

产品开发过程中可能面临着频繁的需求更改,一旦硬件修改了,就要同步的修改设备树文件,毕竟设备树是描述板子硬件信息的文件

假设现在有个六轴芯片fxls8471, fxls8471 要接到 I.MX6U-ALPHA 开发板的 I2C1 接口上,那么相当于需要在 i2c1 这个节点上添加一个 fxls8471 子节点

找开发板使用的设备树文件.dts,需要在.dts 文件中完成数据追加的内容,方式如下:


1  &i2c1 {
2      /* 要追加或修改的内容 */
3  };

第 1 行, &i2c1 表示要访问 i2c1 这个 label标签所对应的节点,也就是 imx6ull.dtsi 中的“i2c1:i2c@021a0000”,即会访问下图代码
  第 2 行,花括号内就是要向 i2c1 这个节点添加的内容,包括修改某些属性的值

向节点追加或修改内容,重点就是通过&label 来访问节点,然后在里面编写要追加或者修改的内容

4、标准属性

 节点是由一堆的属性组成,节点都是具体的设备,不同的设备需要的属性不同,用户可以自定义属性。除了用户自定义属性,有很多属性是标准属性, Linux 下的很多外设驱动都会使用这些标准属性

①compatible 属性和model 属性

compatible 属性也叫做“兼容性”属性,这是非常重要的一个属性! compatible 属性的值是一个字符串列表,model 属性是一个字符串, compatible 属性用于将设备和驱动绑定起来,一般 model 属性描述设备模块信息。字符串列表用于选择设备所要使用的驱动程序, compatible 属性值和model 属性值格式如下所示:

"manufacturer,model"        manufacturer 表示厂商, model 一般是模块对应的驱动名字

比如sound 节点的compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";

属性值有两个,分别为“fsl,imx6ul-evk-wm8960”和“fsl,imx-audio-wm8960”,其中“fsl”表示厂商是飞思卡尔,“imx6ul-evk-wm8960”和“imx-audio-wm8960”表示驱动模块名字。 sound这个设备首先使用第一个兼容值在 Linux 内核里面查找,看看能不能找到与之匹配的驱动文件,如果没有找到的话就使用第二个兼容值查

②status 属性

status 属性是和设备状态有关的, status 属性值也是字符串,字符串是设备的状态信息 

 ③reg属性、#address-cells 和#size-cells 属性

这两个属性的值都是无符号 32 位整形, #address-cells 和#size-cells 这两个属性可以用在任何拥有子节点的设备中,用于描述子节点的地址信息

reg前两个值是address的,后一个值是size的,它受#address-cells<>和#size-cells<>需要控制

再看,这是<2>和<0>,那么reg的两个值都是address的,size没有

 一般 reg 属性都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度, reg 属性的格式一为:reg = <address1 length1 address2 length2 address3 length3……>

 address 是起始地址, length 是地址长度, #address-cells 表明 address 这个数据所占用的字长, #size-cells 表明 length 这个数据所占用的字长

④ranges 属性

 ranges属性值可以为空或者按照(child-bus-address,parent-bus-address,length)格式编写的数字
矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度
这三部分组成:

 child-bus-address:子总线地址空间的物理地址,由父节点的#address-cells 确定此物理地址所占用的字长

parent-bus-address: 父总线地址空间的物理地址,同样由父节点的#address-cells 确定此物
理地址所占用的字长。

length: 子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长

比如reg = <0x4600 0x100>;ranges = <0x0 0xe0000000 0x00100000>;
serial 设备可以从 0xe0004600 开始进行读写操作,0xe0004600=0x4600+0xe0000000

5、特殊属性

 每个节点都有 compatible 属性,根节点“/”也有,.dts 文件中根节点的 compatible 属性内容如:

 通过根节点的 compatible 属性可以知道所使用的设备,一般第一个值描述了所使用的硬件设备名字,比如这里使用的是“imx6ull-14x14-evk”这个设备,第二个值描述了设备所使用的 SOC,比如这里使用的是“imx6ull”这颗 SOC。 Linux 内核会通过根节点的 compoatible 属性查看是否支持此设备,如果支持的话设备就会启动 Linux 内核。

如果将 imx6ull-alientek-emmc.dts 根节点的 compatible 属性改为其他的值,Linux 内核无法启动

五、设备树在系统中的体现

Linux 内核启动的时候会解析设备树中各个节点的信息,并且在根文件系统的/proc/devicetree 目录下根据节点名字创建不同文件夹

 1、根节点“/”各个属性

图中的“#address-cells”、“#size-cells”、“compatible”、“model”和“name”这 5 个文件,它们在设备树中就是根节点的 5个属性。既然是文件那么肯定可以查看其内容,输入cat 命令来查看 model
和 compatible 这两个文件的内容

 对应文件 imx6ull-alientek-emmc.dts如下

 2、根节点“/”各子节点

各个文件夹(图中粗字体文件夹)就是根节点“/”的各个子节点,比如“aliases”、“ backlight”、“chosen”和“ clocks”等。/proc/device-tree 目录就是设备树在根文件系统中的体现,同样是按照树形结构组织的,进入/proc/device-tree/soc 目录中就可以看到 soc 节点的所有子节点
 

 对应这些属性文件的内容和 imx6ull.dtsi 中 soc 节点的属性值相同

 其他的文件与文件夹都同理

六、特殊节点

 在根节点“/”中有两个特殊的子节点: aliases 和 chosen

1、aliases 子节点

打开 imx6ull.dtsi 文件, aliases 节点内容如下

 Linux启动的时候会扫描该文件,单词 aliases 的意思是“别名”,因此 aliases 节点的主要功能就是定义别名,定义别名的目的就是为了方便访问节点。比如soc有很多个i2c控制器,aliases就相当于给每个i2c控制器分配一个唯一的编号。比如i2c1=&i2c2,也就是通过i2c1访问i2c2,那么给编号就是1,可以在/dev下看到名为i2c-1的设备节点

 2、chosen 子节点

 chosen 并不是一个真实的设备, chosen 节点主要是为了 uboot 向 Linux 内核传递数据,重点是 bootargs 参数。

uboot 在启动 Linux 内核的时候会将 bootargs 的值传递给 Linux内核, bootargs 会作为 Linux 内核的命令行参数, Linux 内核启动的时候会打印出命令行参数(也就是 uboot 传递进来的 bootargs 的值)

 .dts 中 chosen 节点内容如下所示

这里没有bootargs 属性,说明chosen 节点的 bootargs 属性不是在设备树里面设置的,那么只有一种可能,那就是 uboot 自己在 chosen 节点里面添加了 bootargs 属性!并且设置 bootargs 属性的值为 bootargs环境变量的值。因为在启动 Linux 内核之前,只有 uboot 知道 bootargs 环境变量的值,并且uboot也知道.dtb 设备树文件在 DRAM 中的位置。

在 uboot 源码中全局搜索“ chosen”这个字符串,fdt_support.c 文件中有个 fdt_chosen 函数,uboot 中的 fdt_chosen 函数在设备树的 chosen 节点中加入 bootargs属性,并且还设置bootargs 属性值

fdt_chosen 函数调用流程

 do_bootm_linux 函数会通过一系列复杂的调用,最终通过 fdt_chosen 函数在 chosen 节点中加入
了 bootargs 属性。而我们通过 bootz 命令启动 Linux 内核的时候会运行 do_bootm_linux 函数

七、绑定信息文档

设备树是用来描述板子上的设备信息的,不同的设备其信息不同,反映到设备树中就是属性不同。在Linux 内核源码中有详细的.txt 文档描述了如何添加节点,这些.txt 文档叫做绑定文档,路径为:Linux 源码目录/Documentation/devicetree/bindings

 比如现在要想在 I.MX6ULL 这颗 SOC 的 I2C 下添加一个节点,那么就可以查看
Documentation/devicetree/bindings/i2c/i2c-imx.txt,此文档详细的描述了 I.MX 系列的 SOC 如何
在设备树中添加 I2C 设备节点。有时候使用的一些芯片在 Documentation/devicetree/bindings 目录下找不到对应的文档,这个时候就要咨询芯片的提供商,让他们给提供参考的设备树文件
 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设备树(Device Tree)是一种描述嵌入式系统硬件设备的文件格式,用于在Linux内核中动态配置和管理硬件。设备树采用树形结构,描述了开发板上的各种设备信息,比如CPU数量、内存基地址、接口上连接的设备等。设备树文件的扩展名为.dts,编译后得到.dtb文件。在引导Linux内核时,Bootloader会将.dtb文件的地址传递给内核,内核会根据设备树文件中描述的信息创建和注册相关设备。通过设备树开发者可以在不修改内核源代码的情况下配置和管理硬件设备。在编译Linux源码时,可以使用"make dtbs"命令来单独编译设备树文件,而不是编译整个源码。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Linux 设备树](https://blog.csdn.net/m0_69211839/article/details/130601344)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [linux设备树](https://blog.csdn.net/qq_27094347/article/details/121012569)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值