这是一篇尽可能将设备树进行详细解释的一篇文章
主要参考的文件:讯为驱动开发手册、慕课网驱动视频、韦东山老版驱动大全视频、内核笔记驱动视频、AI生成的设备手册,争取通过这篇文章可以将设备树相关的知识全部讲清楚
1.迅为驱动开发手册中关于设备树的知识汇总
DTS(Device Tree Source):DTS 是设备树的源文件采用一种类似于文本的语法来描述硬
件设备的结构、属性和连接关系。DTS 文件以.dts 为扩展名,通常由开发人员编写。DTSI(Device Tree Source Include):DTSI 文件是设备树源文件的包含文件、它扩展了DTS文件的功能,用于定义可重用的设备树片段。DTSI 文件以.dtsi 为扩展名,可以在多个DTS 文件中包含和共享。DTB(Device Tree Blob):DTB 是设备树的二进制表示形式。DTB 文件是通过将DTS 或DTSI文件编译而成的二进制文件,以.dtb 为扩展名。DTC(Device Tree Compiler):DTC 是设备树的编译器。它是一个命令行工具,用于将DTS和DTSI 文件编译成DTB 文件。

设备树文件在Linux内核中的位置
/home/eh/linux/xuexi1/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/boot/dts

接下来解释设备树的编译控制
arch/arm/boot/dts/
├── Makefile ← 关键文件:控制哪些 .dtb 被编译
├── imx6ull-alientek.dts
├── imx6ull-alientek-emmc.dts
├── imx6ull-alientek-nand.dts
└── ...其他开发板的 .dts
arch/arm/boot/dts/Makefile 的作用
# arch/arm/boot/dts/Makefile 典型内容
# 每行格式: 目标 .dtb 依赖的 .dts 文件
dtb-$(CONFIG_SOC_IMX6ULL) += imx6ull-alientek-emmc.dtb
dtb-$(CONFIG_SOC_IMX6ULL) += imx6ull-alientek-nand.dtb
dtb-$(CONFIG_SOC_IMX6ULL) += imx6ull-mini.dtb
# 这些变量最终汇总到顶层 Makefile 中

编译流程
1. 内核配置阶段(make xxx_defconfig / make menuconfig)
↓
生成了 .config 文件
→ CONFIG_SOC_IMX6ULL = y
↓
2. 编译阶段
↓
读取 arch/arm/boot/dts/Makefile
→ 根据 $(CONFIG_SOC_IMX6ULL) 决定哪些 .dtb 需要编译
↓
3. 只编译依赖该 SoC 的 .dtb 文件


完整调用链
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig
↓
生成 .config,其中 CONFIG_SOC_IMX6ULL = y
↓
make ARCH=arm dtbs
↓
读取 arch/arm/boot/dts/Makefile
↓
遍历所有 dtb-y 变量(包含 imx6ull-alientek-emmc.dtb)
↓
只编译这个 .dtb(以及它的依赖)
接下来讲解一下设备树目录下这个makefile文件作用,文件位置:/home/eh/linux/xuexi1/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/boot/dts
makefile整体结构概览
第 1 行:ifeq ($(CONFIG_OF),y) ← 整个文件被 CONFIG_OF 包裹(设备树启用才编译)
第 3~810 行:按 SoC/平台分类,列出所有 .dtb 文件
第 813 行:always := $(dtb-y) ← 最终汇总
第 814 行:clean-files := *.dtb ← make clean 时删除这些文件
第 811 行:endif ← 闭合 CONFIG_OF
编译行为图解
make imx_alientek_nand_defconfig ↓ .config 中 CONFIG_SOC_IMX6ULL = y ↓ arch/arm/boot/dts/Makefile 解析: dtb-$(CONFIG_SOC_IMX6ULL) += imx6ull-alientek-nand.dtb dtb-$(CONFIG_SOC_IMX6ULL) += imx6ull-alientek-emmc.dtb … ↓ dtb-y = imx6ull-alientek-nand.dtb imx6ull-alientek-emmc.dtb … ↓ 只有这 2 个 .dtb 被编译 其他 SoC(IMX7D, IMX6Q 等)的 .dtb 完全不参与编译
小技巧再ubuntu桌面如何查看隐藏文件
快捷键(临时显示)
在文件管理器(Nautilus)中按:
Ctrl + H
H代表 Hidden- 再次按
Ctrl + H可隐藏回来
在Linux内核编译的时候生成了.config文件,接下来结合AI的回答对这个文件进行详细的解释
┌──────────────────────────────────────────────────────────────┐
│ .config 文件的作用 │
│ │
│ 6000+ 行配置项,告诉你: │
│ │
│ ① 平台信息 │
│ → ARM 架构,IMX6ULL 芯片 │
│ │
│ ② 内核功能 │
│ → 中断、定时器、内存管理、文件系统、网络协议栈… │
│ │
│ ③ 硬件驱动 │
│ → GPIO、UART、I2C、SPI、SDMA、GIC… │
│ → 每个外设对应一个 CONFIG_XXX │
│ │
│ ④ 编译方式 │
│ → =y → 编译进内核 │
│ → =m → 编译为模块 │
│ → is not set → 不编译 │
│ │
│ 生成的 .config + Kbuild → 最终编译出只属于你的内核镜像 │
└──────────────────────────────────────────────────────────────┘
三种配置形式
CONFIG_ARM=y # 形式1:启用,编译进内核
CONFIG_SOC_IMX6ULL=y # 形式1:启用
# CONFIG_COMPILE_TEST is not set # 形式2:禁用,不编译
CONFIG_MXC_TZIC=m # 形式3:模块化编译,生成 .ko 文件
| 形式 | 写法 | 含义 | 编译产物 |
|---|---|---|---|
| 启用 | CONFIG_XXX=y | 功能编译进内核 | 集成在 zImage 中 |
| 禁用 | # CONFIG_XXX is not set | 不编译 | 无 |
| 模块 | CONFIG_XXX=m | 编译为模块 | 独立的 .ko 文件 |
1. 架构和启动(第5~25行)
CONFIG_ARM=y # ARM 架构支持
CONFIG_FIQ=y # 快速中断(Fast Interrupt Request)
CONFIG_VECTORS_BASE=0xffff0000 # 中断向量表基地址
CONFIG_ARM_PATCH_PHYS_VIRT=y # 物理地址到虚拟地址的动态转换
CONFIG_PGTABLE_LEVELS=2 # 二级页表(ARMv7 默认)
解释:
FIQ:快速中断,比普通 IRQ 优先级更高、响应更快VECTORS_BASE:ARM 异常向量的起始地址,0xffff0000是高地址向量表ARM_PATCH_PHYS_VIRT:在内核启动时动态计算虚拟地址,兼容不同内存布局
2. 通用设置(General setup)
#
# General setup
#
CONFIG_INIT_ENV_ARG_LIMIT=32 # 环境变量参数数量限制
CONFIG_CROSS_COMPILE="" # 交叉编译器前缀(空=使用默认)
CONFIG_DEFAULT_HOSTNAME="(none)" # 默认主机名
CONFIG_SWAP=y # 启用 swap 交换分区
CONFIG_SYSVIPC=y # System V 进程间通信
CONFIG_POSIX_MQUEUE=y # POSIX 消息队列
解释:
CROSS_COMPILE:交叉编译工具链前缀,如arm-linux-gnueabihf-SYSVIPC:经典的 System V IPC 机制(信号量、共享内存、消息队列)POSIX_MQUEUE:POSIX 标准的消息队列
3. 中断子系统(IRQ subsystem)
#
# IRQ subsystem
#
CONFIG_GENERIC_IRQ_PROBE=y # 通用中断探测
CONFIG_GENERIC_IRQ_SHOW=y # 中断状态显示支持
CONFIG_IRQ_DOMAIN=y # 中断域管理
CONFIG_IRQ_DOMAIN_HIERARCHY=y # 层次化中断域(支持中断控制器级联)
CONFIG_SPARSE_IRQ=y # 稀疏中断号(动态分配中断号)
关键概念:
IMX6ULL 的中断控制器(GIC):
GIC
├── 32 个 PPI(私有外设中断,如定时器)
├── 128 个 SPI(共享外设中断,如 GPIO、UART)
└── 每个 SPI 分配到不同的 CPU 核心
IRQ_DOMAIN 的作用:
- 硬件中断号(如 GPIO1 的中断号是 33)
- 经过中断控制器映射后,变成 Linux 虚拟中断号
- 驱动使用虚拟中断号,不需要关心硬件细节
4. 定时器子系统(Timers subsystem)
#
# Timers subsystem
#
CONFIG_TICK_ONESHOT=y # 单次定时器
CONFIG_NO_HZ_IDLE=y # 空闲时停止周期性时钟
CONFIG_NO_HZ=y # 动态时钟(无时钟节拍时停止)
CONFIG_HIGH_RES_TIMERS=y # 高精度定时器
解释:
传统方式:固定 100Hz 或 1000Hz 时钟中断
→ CPU 每秒被打断 100~1000 次
→ 即使 CPU 空闲也要处理时钟中断
→ 功耗较高
动态时钟(CONFIG_NO_HZ):
→ CPU 空闲时,停止周期性时钟中断
→ 需要定时器时再唤醒
→ 功耗降低(IMX6ULL 这种嵌入式芯片很重要)
→ 移动设备省电的关键技术
5. RCU 子系统(Read-Copy-Update)
#
# RCU Subsystem
#
CONFIG_PREEMPT_RCU=y # 可抢占 RCU(提高响应性)
CONFIG_SRCU=y # 睡眠 RCU(可在睡眠上下文中使用)
RCU 是什么?
- 一种高性能的同步机制
- 读操作不加锁(非常快)
- 写操作复制+替换(需要多个 CPU 协调)
- 适合读多写少的场景(如路由表、文件系统缓存)
6. SoC 芯片配置(最关键部分)
CONFIG_SOC_IMX6=y # IMX6 系列通用代码
CONFIG_SOC_IMX6Q=y # IMX6Q/QP(四核/四核 Plus)
CONFIG_SOC_IMX6SL=y # IMX6SL(低功耗版)
CONFIG_SOC_IMX6SX=y # IMX6SX(增强版)
CONFIG_SOC_IMX6UL=y # IMX6UL
CONFIG_SOC_IMX6ULL=y # IMX6ULL ← 你的芯片
CONFIG_SOC_IMX6SLL=y # IMX6SLL
重要说明:
- 这里启用了所有 IMX6 系列的支持,但实际编译时会根据实际硬件选择
.config是全集,设备树(.dtb)才是具体选择
7. IMX 特定外设驱动
CONFIG_IMX_WEIM=y # WEIM 总线(外部存储接口)
CONFIG_IMX_SEMA4=y # SEMA4 信号量(多核同步)
CONFIG_IMX_THERMAL=y # 温控驱动
CONFIG_IMX2_WDT=y # 看门狗定时器
CONFIG_MXC_IPU_V3=y # IPUv3 图像处理单元
CONFIG_MXC_VPU=y # VPU 视频处理单元
CONFIG_IMX_SDMA=y # SDMA 智能 DMA 控制器
这些配置的作用:
┌──────────────────────────────────────────────────────────────┐
│ IMX6ULL 芯片内部框图 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ ARM │ │ ARM │ │ ARM │ │ ARM │ │
│ │ Cortex- │ │ Cortex- │ │ Cortex- │ │ Cortex- │ │
│ │ A7 │ │ A7 │ │ A7 │ │ A7 │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
│ ┌────┴─────────────┴─────────────┴─────────────┴────┐ │
│ │ AXI/ARM 总线 │ │
│ └────┬─────────────┬─────────────┬─────────────┬────┘ │
│ │ │ │ │ │
│ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ │
│ │ GPIO │ │ UART │ │ I2C │ │ SPI │ │
│ │ (IO口) │ │ (串口) │ │ (I2C) │ │ (SPI) │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ SDMA │ │ GPT │ │ WDOG │ │ GIC │ │
│ │ (DMA) │ │ (定时器) │ │(看门狗) │ │ (中断) │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└──────────────────────────────────────────────────────────────┘
.config 中的 CONFIG_XXX 控制是否编译对应外设的驱动
与设备树(.dts)的关系
.config arch/arm/boot/dts/Makefile
│ │
│ CONFIG_SOC_IMX6ULL=y │
│ │ │
│ ↓ │
│ 告诉编译器: │
│ "启用了 IMX6ULL 支持" │
│ │ │
│ ↓ │
│ Makefile 解析: │
│ dtb-$(CONFIG_SOC_IMX6ULL) += xxx.dtb
│ │ │
│ ↓ │
│ 编译 imx6ull-*.dtb │
│ │ │
│ ↓ │
│ 最终只有 IMX6ULL 的设备树被编译 │
常用查看命令
# 1. 搜索 IMX6ULL 相关配置
grep -E "CONFIG_SOC_IMX6" .config
# 2. 搜索启用的驱动
grep "=y" .config | head -20
# 3. 搜索模块化的驱动
grep "=m" .config | head -20
# 4. 统计配置项数量
echo "启用的功能:" && grep "=y" .config | wc -l
echo "禁用的功能:" && grep "is not set" .config | wc -l
echo "模块化的功能:" && grep "=m" .config | wc -l
# 5. 搜索具体外设
grep "CONFIG_MXC" .config
grep "CONFIG_IMX" .config
单独编译某个设备树文件的方法
# 编译所有设备树
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs
# 编译单个设备树文件 (在 arch/arm/boot/dts/ 目录)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx6ull-alientek-emmc.dtb
# 或者直接用 dtc 命令
arm-linux-gnueabihf-dtc -I dts -O dtb -o output.dtb input.dts
快速编译命令(推荐)
# 在内核源码根目录执行
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx6ull-alientek-emmc.dtb -j16
使用dtc编译似乎需要解决依赖的问题,反编译结果如下

反编译的好处是可以快速了解一个设备树有哪些外设
直接编译产生的错误原因解释
这是因为 .dts 文件通常会 include 其他 .dtsi 文件,直接用 dtc 无法解析。正确方法:
方法一:使用内核构建系统(推荐)
cd /home/eh/linux/xuexi1/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
# 编译单个设备树
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx6ull-alientek-emmc.dtb -j16
方法二:使用 dtc 的 include 路径
cd /home/eh/linux/xuexi1/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
# 使用 -i 指定 include 目录(dtc 1.4.3+ 支持)
dtc -I dts -O dtb \
-i arch/arm/boot/dts/ \
-o test.dtb \
arch/arm/boot/dts/imx6ull-alientek-emmc.dts
方法三:预处理后再编译
cd /home/eh/linux/xuexi1/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
# 1. 先用 gcc 预处理(解析 #include)
arm-linux-gnueabihf-gcc -E -P \
-Iarch/arm/boot/dts/ \
-D__DTS__ \
arch/arm/boot/dts/imx6ull-alientek-emmc.dts > /tmp/preprocessed.dts
# 2. 再用 dtc 编译
dtc -I dts -O dtb -o test.dtb /tmp/preprocessed.dts
方法四:查看 dtc 版本并使用内核目录的版本
# 内核源码目录有修正版的 dtc
cd /home/eh/linux/xuexi1/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
# 使用内核提供的 dtc(支持更多特性)
scripts/dtc/dtc -I dts -O dtb \
-i arch/arm/boot/dts/ \
-o test.dtb \
arch/arm/boot/dts/imx6ull-alientek-emmc.dts
总结
| 方法 | 命令复杂度 | 适用场景 |
|---|---|---|
| 内核构建系统 | 简单 | 推荐,自动处理依赖 |
| dtc -i | 简单 | dtc 版本 >= 1.4.3 |
| gcc 预处理 | 复杂 | dtc 版本较旧 |
| 内核 dtc 脚本 | 简单 | 推荐,版本最兼容 |
推荐用第一种方法,内核构建系统会自动处理所有 include 依赖:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx6ull-alientek-emmc.dtb -j16需要在内核源码目录下进行编译,不然编译是无法成功的
