当前位置: 首页 > news >正文

深入解析 Linux Kernel 中的设备树:使用、修改与实际应用

目录

    • 什么是设备树?基础概念与结构
      • 核心组件
    • 设备树的使用:从加载到驱动绑定
      • 加载过程
      • 实际使用场景
    • 设备树的修改:自定义硬件配置
      • 修改步骤
      • 常见 pitfalls 与注意事项
    • 实际示例:常见设备的设备树配置
      • 示例 1: GPIO(通用输入输出)
      • 示例 2: CLK(时钟)
      • 示例 3: I2C(总线)
      • 示例 4: Flash(NAND 或 SPI Flash)
      • 示例 5: SD 卡(MMC/SD)
      • 示例 6: RGB 屏(LCD 显示,如 RGB40 接口)
    • 高级话题:兼容性与最佳实践

什么是设备树?基础概念与结构

设备树(Device Tree,简称 DT)是一种数据结构,用于描述硬件配置,而非通过代码硬编码。它源于 OpenFirmware 标准,后来被 Linux Kernel 采用,尤其在 ARM、PowerPC 和 RISC-V 等架构中广泛使用。

核心组件

  • 设备树源文件(.dts 文件):这是人类可读的文本文件,使用类似 C 的语法描述硬件。每个节点代表一个设备或总线,属性(properties)定义其特性,如地址、引脚和兼容字符串。
  • 设备树二进制文件(.dtb 文件):通过编译 .dts 生成的二进制 blob,内核在启动时加载它。
  • 设备树覆盖(.dtbo 文件):用于动态修改设备树,常用于插件模块或运行时调整。

设备树的结构是一个树状层次:

  • 根节点(/):代表整个系统。
  • 子节点:如 /cpus、/memory、/soc(System on Chip)。
  • 属性示例:
    • compatible:字符串列表,定义设备兼容的驱动(如 “ti,am335x-bone-black”)。
    • reg:寄存器地址和大小。
    • interrupts:中断号。
    • phandle:节点引用,用于交叉链接。

例如,一个简单的 .dts 片段:

/ {model = "My Custom Board";compatible = "mycompany,mycustomboard";chosen {bootargs = "console=ttyO0,115200n8";};memory@0 {device_type = "memory";reg = <0x80000000 0x20000000>;  /* 512MB RAM at 0x80000000 */};
};

这定义了板子型号、兼容性、引导参数和内存布局。

设备树的使用:从加载到驱动绑定

加载过程

  1. Bootloader 阶段:如 U-Boot,将 .dtb 加载到内存,并传递给内核(通过 ATAGS 或 DTB 指针)。
  2. 内核初始化:Kernel 解析 DT,构建设备模型(device model)。函数如 of_find_node_by_path() 用于查找节点。
  3. 驱动绑定:内核使用 compatible 属性匹配驱动。驱动通过 of_match_device() 获取配置。

实际使用场景

在嵌入式系统中,设备树简化了多板支持。例如,同一内核映像可通过不同 .dtb 运行在多种硬件上。调试时,用 dtc 工具反编译 .dtb:dtc -I dtb -O dts -o output.dts input.dtb

设备树的修改:自定义硬件配置

修改设备树是嵌入式开发的常态,尤其是添加新设备或调整引脚。过程包括编辑 .dts、编译和测试。

修改步骤

  1. 找到源文件:Kernel 源代码的 arch/arm/boot/dts/arch/arm64/boot/dts/ 目录下有 .dts 文件。复制一个相似的作为模板。
  2. 编辑节点
    • 添加设备:创建新节点,指定父总线(如 i2c@0)。
    • 修改属性:如更改 GPIO 引脚或时钟频率。
  3. 编译
    • 用 Device Tree Compiler(dtc):dtc -I dts -O dtb -o output.dtb input.dts
    • 在 Kernel 构建中:make dtbs 生成所有 .dtb。
  4. 测试:烧写到设备,检查 /proc/device-tree/ 或用 dtc 验证。

注意:修改后需确保兼容性。使用 #include 包含通用 .dtsi 文件,以复用代码。

常见 pitfalls 与注意事项

  • 兼容性实现compatible 属性是关键。它允许多级回退,例如 “mycompany,custom-gpu”, “generic-gpu”。内核优先匹配最具体的驱动,如果失败则回退。这对于 GPU 等复杂设备尤为重要——如 NVIDIA GPU 的 Tegra 系列,使用 DT 定义 VRAM 和中断,避免硬编码。
  • 引脚复用:许多 SoC 有 pinmux 系统,在 DT 中用 pinctrl 属性配置。
  • 调试工具:用 fdt 命令在 U-Boot 中查看/修改 DT;内核日志(dmesg)显示解析错误。

实际示例:常见设备的设备树配置

让我们通过具体例子讲解,如 GPIO、CLK、I2C,以及 MPU6050、Flash、SD 卡和 RGB 屏(假设 RGB40 指 RGB LCD 显示屏)。

示例 1: GPIO(通用输入输出)

GPIO 用于控制 LED、按钮等。

gpio-leds {compatible = "gpio-leds";pinctrl-names = "default";pinctrl-0 = <&led_pins>;status-led {label = "status";gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;default-state = "on";};
};
  • 修改:更改 gpios 的引脚号,编译后 LED 会自动点亮。
  • 驱动:内核的 gpio-leds 驱动自动绑定。

示例 2: CLK(时钟)

时钟管理确保设备同步。

clocks {#address-cells = <1>;#size-cells = <0>;osc: oscillator {compatible = "fixed-clock";#clock-cells = <0>;clock-frequency = <24000000>;};
};
  • 修改:调整 clock-frequency 以匹配晶振。
  • 使用:其他节点引用它,如 clocks = <&osc>;

示例 3: I2C(总线)

I2C 用于连接传感器。

i2c@7000c000 {compatible = "ti,omap4-i2c";reg = <0x7000c000 0x100>;interrupts = <56>;#address-cells = <1>;#size-cells = <0>;clock-frequency = <400000>;mpu6050@68 {compatible = "invensense,mpu6050";reg = <0x68>;interrupt-parent = <&gpio1>;interrupts = <18 IRQ_TYPE_EDGE_RISING>;};
};
  • MPU6050(IMU 传感器):添加此节点,定义地址和中断。修改:调整中断引脚以适配你的板子。
  • 驱动修改:如果需要自定义,编辑 drivers/iio/imu/mpu6050.c,使用 of_property_read_*() 读取 DT 属性。

示例 4: Flash(NAND 或 SPI Flash)

用于存储固件。

spi0 {flash@0 {compatible = "jedec,spi-nor";reg = <0>;spi-max-frequency = <40000000>;m25p,fast-read;partition@0 {label = "boot";reg = <0x00000000 0x00040000>;};};
};
  • 修改:更改分区大小,编译后用 mtd-utils 访问。

示例 5: SD 卡(MMC/SD)

mmc1 {compatible = "ti,omap4-hsmmc";reg = <0x4809c000 0x400>;interrupts = <83>;ti,needs-special-reset;dmas = <&sdma 61>, <&sdma 62>;dma-names = "tx", "rx";bus-width = <4>;cd-gpios = <&gpio6 27 GPIO_ACTIVE_LOW>;  /* Card detect */
};
  • 修改:调整 bus-width 为 8 以支持更快速度。

示例 6: RGB 屏(LCD 显示,如 RGB40 接口)

假设是一个并行 RGB 接口的 LCD。

panel {compatible = "simple-panel";power-supply = <&vcc_lcd>;backlight = <&backlight>;port {panel_in: endpoint {remote-endpoint = <&dpi_out>;};};
};dpi: dpi@0 {compatible = "ti,dpi";pinctrl-names = "default";pinctrl-0 = <&dpi_pins>;
};
  • 修改:定义分辨率如 display-timings { ... };。对于 GPU 兼容:如果使用 DRM 驱动,确保 compatible 匹配如 “rockchip,rk3288-mali”,DT 中添加 VRAM 分配。
  • 注意:GPU 如 Mali 或 Adreno,需要 DT 定义时钟、电源域和中断,以实现无缝集成。

这些示例基于常见 SoC 如 TI OMAP 或 Rockchip。实际中,从板子供应商的 .dts 开始修改。

高级话题:兼容性与最佳实践

  • 兼容性实现(如 GPU):DT 的 compatible 允许多厂商支持。例如,GPU 节点可有 “arm,mali-400”, “generic-gpu”,内核驱动使用列表匹配。修改时,优先添加具体字符串,避免破坏上游兼容。
  • 最佳实践
    • 用 .dtsi 抽象通用部分。
    • 验证:用 dtc -W 检查警告。
    • 版本控制:Kernel 5.x+ 支持更多绑定(如 YAML schema 检查)。
    • 安全:启用 DT 签名以防篡改。
http://www.dtcms.com/a/313646.html

相关文章:

  • 经典文献阅读之--ViNT(视觉导航的基础模型)
  • 《汇编语言:基于X86处理器》第11章 MS-Windows编程(3)
  • 8.3 Java Web(JavaScript P15-P28)
  • Leetcode——365. 水壶问题
  • 决策树模型知识点整理:从原理到实战(含可视化与调参)
  • [硬件电路-134]:模拟电路 - 运算放大器常见运算:两模拟信号相加、相减、单模拟信号的积分、微分...
  • HTTPS的概念和工作过程
  • Ollama模型库模型下载慢完美解决(全平台)
  • 模型学习系列之参数
  • pytorch深度学习全流程:以简易数据、模型介绍
  • linux火焰图
  • vuhub Noob靶场攻略
  • 雪花算法重复id问题
  • Maxscript在选择的可编辑多边形每个面上绘制一个内部圆形
  • 自动驾驶中的传感器技术19——Camera(10)
  • OS21.【Linux】环境变量
  • CMake 命令行参数完全指南(5)
  • graph TD的规则
  • Linux Deepin深度操作系统应用商店加载失败,安装星火应用商店
  • io_getevents 和 io_pgetevents 系统调用及示例
  • [硬件电路-145]:模拟电路 - 常见的电源芯片、用途、管脚定义
  • 深度学习-读写模型网络文件
  • 大模型设计
  • 学习方法论
  • 智能化设备维护:开启高效运维新时代
  • 前端异步任务处理总结
  • Maven - 依赖的生命周期详解
  • 服务端技术栈分类总结
  • 模型预估打分对运筹跟踪的影响
  • 数据结构:单向链表的函数创建