Linux驱动 2026年4月20日 36 分钟

设备树1-设备树的编译和反编译

这是一篇尽可能将设备树进行详细解释的一篇文章 主要参考的文件:讯为驱动开发手册、慕课网驱动视频、韦东山老版驱动大全视频、…

这是一篇尽可能将设备树进行详细解释的一篇文章

主要参考的文件:讯为驱动开发手册、慕课网驱动视频、韦东山老版驱动大全视频、内核笔记驱动视频、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需要在内核源码目录下进行编译,不然编译是无法成功的

上一篇 ALSA声卡子系统

下一篇 块设备驱动