Linux设备树

本文详细介绍了设备树源文件DTS的使用,包括如何通过DTC编译工具生成DTB二进制文件,以及设备树语法示例,涉及兼容性声明、节点类型、内存映射等。还涵盖了Linux内核解析DTB的过程以及常用的OF操作函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

扫盲知识

DTS:设备树源文件

DTSI:设备树头文件(.dts 文件引用 C 语言中的.h 文件,甚至也可以引用.dts 文 件)

DTC:编译设备树的工具

DTB:设备树被编译之后的二进制文件

如果要编译 DTS 文件的话只需要进入到 Linux 源码根目录下,然后执行如下命 令:
make all   或者: make dtbs。
当选中 I.MX6ULL 这个 SOC 以后(CONFIG_SOC_IMX6ULL=y),所有使用到
I.MX6ULL 这个 SOC 的板子对应的.dts 文件都会被编译为.dtb

设备树语法

1 / {
2    compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";//厂商,板子名称(会和内核匹配是否对应得上)
3 }
cpu0: cpu@0 {// @cpu0相当于@cpu,cpu0是标签,cpu是节点名称
10    compatible = "arm,cortex-a7";
11    device_type = "cpu";
12    reg = <0>;
13};
范例:
1 / {
2     compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";
3 
4     cpus {
5         #address-cells = <1>;
6         #size-cells = <0>;
7
8         //CPU0 节点
9         cpu0: cpu@0 {
10             compatible = "arm,cortex-a7";
11             device_type = "cpu";
12             reg = <0>;
13         };
14     };
15 
16     //soc 节点
17     soc {
18         #address-cells = <1>;
19         #size-cells = <1>;
20         compatible = "simple-bus";
21         ranges;
22 
23         //ocram 节点
24         ocram: sram@00900000 {
25             compatible = "fsl,lpm-sram";
26             reg = <0x00900000 0x20000>;//起始地址,大小
27         };
29         //aips1 节点
30         aips1: aips-bus@02000000 {
31             compatible = "fsl,aips-bus", "simple-bus";
32             #address-cells = <1>;
33             #size-cells = <1>;
34             reg = <0x02000000 0x100000>;
35             ranges;

37             //ecspi1 节点
38             ecspi1: ecspi@02008000 {
39                 #address-cells = <1>;
40                 #size-cells = <0>;
41                 compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";
42                 reg = <0x02008000 0x4000>;
43                 status = "disabled";
44             };
36         }

38         //aips2 节点
39         aips2: aips-bus@02100000 {
40             compatible = "fsl,aips-bus", "simple-bus";
41             #address-cells = <1>;
42             #size-cells = <1>;
43             reg = <0x02100000 0x100000>;
44             ranges;

               //usbotg1 节点
56             usbotg1: usb@02184000 {
57                 compatible = "fsl,imx6ul-usb", "fsl,imx27-usb";
58                 reg = <0x02184000 0x4000>;
59                 status = "disabled";
                };
45         }
46 
47         //aips3 节点 
48         aips3: aips-bus@02200000 {
49             compatible = "fsl,aips-bus", "simple-bus";
50             #address-cells = <1>;
51             #size-cells = <1>;
52             reg = <0x02200000 0x100000>;
53             ranges;

71             //rngb 节点
72             rngb: rngb@02284000 {
73                 compatible = "fsl,imx6sl-rng", "fsl,imx-rng", "imxrng";
74                 reg = <0x02284000 0x4000>;
75             };
54         }
55    }
29 }

设备树在系统中的体现

Linux 内核启动的时候会解析设备树中各个节点的信息,并且在根文件系统的/proc/device
tree 目录下根据节点名字创建不同文件夹
使用cat命令查看model和compatible内容,正是设备树文件根节点的对应属性值。
进一步查看子节点里面的节点

特殊节点

aliases 子节点

18 aliases {
19     can0 = &flexcan1;
20     can1 = &flexcan2;
21     ethernet0 = &fec1;
22     ethernet1 = &fec2;
23     gpio0 = &gpio1;
24     gpio1 = &gpio2;
        ......
42     spi0 = &ecspi1;
43     spi1 = &ecspi2;
44     spi2 = &ecspi3;
45     spi3 = &ecspi4;
46     usbphy0 = &usbphy1;
47     usbphy1 = &usbphy2;
48 };
aliases 节点的主要功能就是定义别名。

chosen节点

1chosen {
2    stdout-path = &uart1;
};
chosen 节点仅仅设置了属性“stdout-path”,表示标准输 出使用 uart1。但是当我们进入到/proc/device-tree/chosen 目录里面,会发现多了 bootargs 这个 属性,如图:
进一步查看bootargs这个属性的值:
这个属性的值和uboot里面设置的bootargs一样。
chosen节点是uboot添加的。

Linux 内核解析 DTB 文件

绑定信息文档

在设备树中添加一个硬件对应的节点的时候从如下路径查找对应稳定说明:
Linux 源码目录/Documentation/devicetree/bindings

设备树常用 OF 操作函数

查找节点的 OF 函数
struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
name:要查找的节点名字。
返回值:找到的节点,如果为 NULL 表示查找失败。
struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
函数参数和返回值含义如下:
from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
type:要查找的节点对应的 type 字符串,也就是 device_type 属性值。
返回值:找到的节点,如果为 NULL 表示查找失败。
struct device_node *of_find_compatible_node(struct device_node *from,
    const char *type, const char *compatible)
from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
type:要查找的节点对应的 type 字符串,也就是 device_type 属性值,可以为 NULL,表示
忽略掉 device_type 属性。
compatible要查找的节点所对应的 compatible 属性列表。
返回值:找到的节点,如果为 NULL 表示查找失败
struct device_node *of_find_matching_node_and_match(struct device_node
    *from, const struct of_device_id *matches, const struct of_device_id **match);
from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
matchesof_device_id 匹配表,也就是在此匹配表里面查找节点。
match找到的匹配的 of_device_id
inline struct device_node *of_find_node_by_path(const char *path);
path:带有全路径的节点名,可以使用节点的别名,比如“/backlight”就是 backlight 这个
节点的全路径。
返回值:找到的节点,如果为 NULL 表示查找失败
查找父/子节点的 OF 函数
struct device_node *of_get_parent(const struct device_node *node)
node:要查找的父节点的节点。
struct device_node *of_get_next_child(const struct device_node *node,  struct device_node     *prev)
node:父节点。
prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子节点。可以设置为
NULL,表示从第一个子节点开始。
返回值:找到的下一个子节点。
提取属性值的 OF 函数
property *of_find_property(const struct device_node *np, const char *name, int *lenp);
np
设备节点。
name: 属性名字。
lenp:属性值的字节数
返回值:找到的属性。
int of_property_count_elems_of_size(const struct device_node *np,
    const char *propname,intelem_size);
np:设备节点。
proname: 需要统计元素数量的属性名字。
elem_size:元素长度。
返回值:得到的属性元素数量。
int of_property_read_u32_index(const struct device_node *np, const char *propname,
    u32 index, u32 *out_value);
np:设备节点。
proname: 要读取的属性名字。
index:要读取的值标号。
out_value:读取到的值
返回值:0 读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有
要读取的数据,-EOVERFLOW 表示属性值列表太小。
...
<think>首先,用户的问题是:“我想了解Linux设备树的相关信息或配置方法请问Linux设备树配置及使用教程”。用户要求了解Linux设备树的相关信息或配置方法,并询问配置和使用教程。根据系统级指令:-所有行内数学表达式必须使用$...$格式。但在用户问题中,没有数学表达式,所以可能不需要。-独立公式必须使用$$...$$格式并单独成段。同样,用户问题不涉及数学,所以可能不需要。-LaTeX语法正确:确保在回答中使用正确的LaTeX语法。-使用中文回答:整个回答必须用中文。-生成相关问题:在回答末尾生成相关问题。-回答中引用的段落末尾自然地添加引用标识,例如[^1]。用户可见层指令:-回答结构清晰,帮助用户逐步解决问题。-尽量保证回答真实可靠。-参考站内引用:提供了四个引用,我需要参考这些引用,并在回答中自然地添加引用标识。提供的引用:-[^1]:关于Android内核日志和设备树中bootargs的信息。-[^2]:关于IMX6ULL配置设备树和SPIDEV驱动SPI配置的教程。-[^3]:关于将IRQ映射到GPIO引脚的问题。-[^4]:关于Linux设备树配置指南,特别是ES8388音频编解码器集成。用户的问题是关于Linux设备树的配置和使用教程,所以我应该基于这些引用构建一个清晰的教程。回答结构:1.**介绍设备树**:简要解释什么是Linux设备树。2.**设备树的基本结构**:描述设备树文件的结构。3.**配置方法**:逐步解释如何配置设备树,包括引用中的例子。4.**使用教程**:提供示例或步骤。5.**常见问题和优化**:基于引用中的信息。6.**添加引用标识**:在相关段落末尾添加[^1],[^2]等。7.**生成相关问题**:在末尾添加相关问题。确保回答真实可靠:基于提供的引用和一般知识。引用不是用户真正的需求,但可以参考。大纲:-**引言**:什么是设备树?为什么使用它?-**设备树文件结构**:解释.dts,.dtsi,.dtb文件。-**配置步骤**:-编辑.dts文件。-添加节点和属性。-使用compatible属性。-编译设备树。-加载设备树。-**示例**:基于引用[^2]和[^4],提供SPI配置和音频编解码器集成的例子。-**常见问题**:基于引用[^3],讨论IRQ映射问题。-**总结**。-**相关问题**:生成几个相关问题。添加引用标识:-在引用到特定内容时添加,例如在提到bootargs时加[^1],在SPIDEV配置时加[^2],在IRQ映射时加[^3],在音频编解码器时加[^4]。用中文回答。生成相关问题:基于主题,如优化、调试、具体应用等。</think>### Linux设备树配置及使用教程 Linux设备树(Device Tree)是一种描述硬件资源的数据结构,用于在启动过程中将硬件配置传递给Linux内核。它取代了传统的硬编码硬件描述方式,使内核更具可移植性。设备树文件通常以 `.dts`(设备树源文件)或 `.dtsi`(包含文件)格式编写,编译后生成 `.dtb`(设备树二进制)文件供内核加载。下面我将逐步介绍设备树的基本概念、配置方法和使用教程,确保内容真实可靠,并基于实际开发经验。 #### 1. 设备树基本概念 设备树的核心是描述硬件节点(node),每个节点代表一个硬件组件(如CPU、外设)。节点包含属性(property)来描述硬件特性,例如内存地址、中断号、时钟频率等。设备树文件的结构类似树状: - **根节点**:以 `/` 表示,包含全局属性。 - **子节点**:代表具体硬件,如处理器、GPIO控制器。 - **属性**:键值对,例如 `compatible = "厂商,设备名"` 用于匹配驱动程序。 设备树的主要优点是简化内核移植:硬件变更只需修改设备树文件,而无需重新编译内核。在启动过程中,引导加载器(如U-Boot)会将设备树传递给内核[^1]。 #### 2. 设备树文件结构 设备树文件使用文本格式,语法基于DTS(Device Tree Source)。以下是关键部分: - **头信息**:定义版本和兼容性。 - **节点定义**:使用花括号 `{}` 包裹。 - **常用属性**: - `compatible`:指定驱动程序匹配字符串,如 `compatible = "fsl,imx6ull";`。 - `reg`:描述硬件寄存器地址范围。 - `interrupts`:定义中断号。 - `status`:启用或禁用节点(如 `status = "okay";`)。 示例代码(简单设备树片段): ```dts /dts-v1/; / { model = "My Board"; compatible = "fsl,imx6ull"; chosen { bootargs = "console=ttyS0,115200"; // 引导参数,由U-Boot传递给内核[^1] }; gpio0: gpio@20a0000 { compatible = "fsl,imx6ul-gpio"; reg = <0x20a0000 0x4000>; interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>; }; }; ``` #### 3. 设备树配置方法 配置设备树涉及编辑 `.dts` 文件、编译和加载。以下是详细步骤: **步骤1: 创建或修改设备树文件** - 定位目标平台的设备树文件(通常在Linux源码的 `arch/arm/boot/dts/` 目录)。 - 使用文本编辑器(如Vim)添加或修改节点。例如,添加一个SPI设备节点: ```dts &spi1 { status = "okay"; spidev@0 { compatible = "vernon,st7701s"; // 自定义兼容字符串,用于驱动匹配[^2] reg = <0>; spi-max-frequency = <10000000>; }; }; ``` 这里,`compatible` 属性必须与驱动代码中的定义一致(如引用[^2]中的 `of_device_id` 结构)。 **步骤2: 配置硬件属性** - **中断映射**:处理IRQ与GPIO映射时,确保中断号正确。例如,将GPIO引脚映射到IRQ: ```dts gpio-keys { compatible = "gpio-keys"; button@0 { gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; // 使用GPIO0引脚0 interrupts = <0 24 IRQ_TYPE_EDGE_FALLING>; // 映射到IRQ 24[^3] label = "User Button"; }; }; ``` 如果映射失败,检查中断控制器节点是否正确定义(常见问题如引用[^3]所述)。 - **音频设备集成**:配置音频编解码器时,引用CPU和CODEC节点: ```dts sound { compatible = "simple-audio-card"; simple-audio-card,format = "i2s"; rockchip,cpu = <&i2s0_8ch>; // 引用CPU端I2S控制器 rockchip,codec = <&es8388>; // 引用CODEC设备[^4] }; ``` 这确保音频数据流正确路由。 **步骤3: 编译设备树** - 在Linux源码目录中,使用 `dtc`(设备树编译器)编译 `.dts` 文件: ```bash dtc -I dts -O dtb -o my_board.dtb my_board.dts ``` 或在内核构建时编译: ```bash make ARCH=arm dtbs ``` **步骤4: 加载设备树** - 在U-Boot中,将 `.dtb` 文件加载到内存并传递给内核: ```bash load mmc 0:1 ${loadaddr} my_board.dtb bootz ${kerneladdr} - ${loadaddr} ``` 内核启动后,使用 `dmesg | grep -i device_tree` 验证加载状态[^1]。 #### 4. 使用教程:实际示例 以在IMX6ULL平台配置SPIDEV驱动为例(基于引用[^2]): 1. **编辑设备树**:添加SPI节点,如步骤1的代码。 2. **修改驱动代码**:在Linux驱动中,更新 `of_device_id` 表以匹配 `compatible`: ```c static const struct of_device_id spidev_dt_ids[] = { { .compatible = "rohm,dh2228fv" }, { .compatible = "lineartechnology,ltc2488" }, { .compatible = "vernon,st7701s" }, // 新添加的兼容字符串 {}, }; ``` 3. **编译和加载**: - 编译内核:`make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs modules` - 复制 `.dtb` 到目标板。 4. **测试**:在Linux用户空间,使用 `spidev_test` 工具验证SPI通信。 #### 5. 常见问题与调试 - **中断映射失败**:如引用[^3]所述,确保中断控制器节点正确,并使用 `cat /proc/interrupts` 检查IRQ状态。 - **兼容性问题**:`compatible` 属性不匹配会导致驱动无法加载,检查 `dmesg` 日志。 - **引导参数冲突**:U-Boot可能覆盖设备树中的 `bootargs`,需在U-Boot环境变量中协调[^1]。 - **音频设备不工作**:验证时钟和DMA设置,如引用[^4]的CPU-CODEC引用是否正确。 #### 6. 总结 Linux设备树通过描述硬件资源,实现内核与硬件的解耦。配置过程包括编辑 `.dts` 文件、定义节点属性、编译和加载。关键点包括: - 使用 `compatible` 属性匹配驱动。 - 正确映射中断和寄存器。 - 编译时确保语法无误(可用 `dtc` 验证)。 设备树配置是嵌入式Linux开发的基础,掌握它可显著提升系统移植效率。如需深入学习,推荐参考Linux内核文档(`Documentation/devicetree/bindings/`)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值