ARM Linux 设备树

Linux 设备驱动开发详解:基于最新的Linux 4.0内核, 机械工业出版社, 宋宝华, 2015

1. 设备树的起源

• 背景: ARM架构中大量板级代码冗余,硬编码在mach-xxx目录,设备树(Device Tree)引入结构化描述硬件。

• 目的: 减少内核冗余代码,通过设备树文件(.dts)传递硬件信息,由Bootloader加载至内核。

• 核心思想: 设备树以节点和属性形式描述硬件拓扑,如CPU、内存、外设、中断等。


2. 设备树的组成与结构
2.1 核心文件

• DTS (Device Tree Source): 文本格式描述硬件,支持.dtsi包含(类似C头文件)。

• DTC (Device Tree Compiler): 编译工具,将DTS转换为DTB。

• DTB (Device Tree Blob): 二进制文件,由内核解析。

• 绑定文档(Binding): 说明节点属性规范(如Documentation/devicetree/bindings)。

2.2 设备树结构

• 节点(Node): 表示设备或总线,如根节点/,子节点cpu@0

• 属性(Property): 键值对描述硬件特性,如reg = <地址 长度>interrupts

• 标签(Label)与Phandle: 通过&label引用节点,如&gpio0表示GPIO控制器。

2.3 设备树示例

dts 复制代码
/ {
    compatible = "acme,coyotes-revenge"; // 根节点兼容性
    #address-cells = <1>; // 地址占1个cell
    #size-cells = <1>;    // 长度占1个cell

    cpus {
        cpu@0 { compatible = "arm,cortex-a9"; reg = <0>; };
        cpu@1 { compatible = "arm,cortex-a9"; reg = <1>; };
    };

    serial@101f0000 {
        compatible = "arm,pl011";
        reg = <0x101f0000 0x1000>; // 寄存器地址和长度
        interrupts = <1 0>;        // 中断号及触发方式
    };
};

3. 关键概念解析
3.1 兼容性(Compatible)

• 根节点兼容性: 匹配机器类型,如vexpress-v2p-ca9

c 复制代码
// 内核中匹配设备
if (of_machine_is_compatible("arm,vexpress")) { ... }

• 设备节点兼容性: 驱动匹配依据,如compatible = "arm,pl011"

3.2 地址编码

• reg属性: 格式reg = <地址1 长度1 地址2 长度2 ...>

• #address-cells和#size-cells: 定义子节点地址/长度的cell数量。

dts 复制代码
external-bus {
    #address-cells = <2>; // 地址占2个cell(片选+偏移)
    #size-cells = <1>;     // 长度占1个cell
    ethernet@0,0 { reg = <0 0 0x1000>; };
};

3.3 中断连接

• 中断控制器: 声明interrupt-controller#interrupt-cells

• 中断属性: 使用interrupt-parentinterrupts指定中断号和触发方式。

dts 复制代码
intc: interrupt-controller@10140000 {
    compatible = "arm,pl190";
    #interrupt-cells = <2>; // 2个cell(中断号+标志)
};
serial@101f0000 {
    interrupts = <1 0>; // 中断号1,触发方式0
};

3.4 GPIO、时钟、Pinmux

• GPIO控制器: 声明gpio-controller#gpio-cells

• GPIO使用: 通过gpios属性引用控制器。

dts 复制代码
gpio@101f3000 {
    gpio-controller;
    #gpio-cells = <2>; // GPIO号+极性
};
button {
    gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
};

4. BSP和驱动的变更
4.1 平台设备的替代

• 旧方式: 手动注册platform_device,硬编码资源。

• 新方式: 设备树自动展开platform_device,资源来自.dts

4.2 驱动匹配机制

• OF匹配表: 驱动通过.of_match_table匹配设备节点。

c 复制代码
static const struct of_device_id my_drv_of_match[] = {
    { .compatible = "vendor,device" },
    {},
};
MODULE_DEVICE_TABLE(of, my_drv_of_match);

4.3 平台数据的属性化

• 旧方式: 通过platform_data结构传递数据。

• 新方式: 从设备树属性读取,如of_property_read_u32()

c 复制代码
// 读取属性值示例
of_property_read_u32(np, "clock-frequency", &clk_freq);

4.4 实例:GPIO按键驱动

dts 复制代码
gpio-keys {
    compatible = "gpio-keys";
    button {
        label = "Up";
        gpios = <&gpio0 1 0>;
        linux,code = <KEY_UP>;
    };
};

驱动通过OF API解析属性:

c 复制代码
of_get_gpio_flags(pp, 0, &flags); // 获取GPIO号和极性
of_property_read_u32(pp, "linux-code", &key_code); // 读取键值

5. 常用OF API

• 节点操作:

of_find_compatible_node(): 查找兼容节点。

of_get_child_count(): 获取子节点数量。

• 属性读取:

of_property_read_u32_array(): 读取32位数组。

of_property_read_string(): 读取字符串。

• 资源解析:

of_get_named_gpio(): 获取GPIO号。

of_irq_get(): 获取中断号。


6. 总结

• 设备树优势:解耦硬件描述与内核代码,提升可维护性。

• 核心元素:节点、属性、兼容性、地址编码、中断连接。

• 驱动适配:通过OF匹配表和API解析设备树数据。

通过设备树,ARM Linux实现了硬件描述的标准化,降低了BSP开发复杂度,成为嵌入式开发的必备知识。

相关推荐
虾..19 小时前
Linux 软硬链接和动静态库
linux·运维·服务器
Evan芙19 小时前
Linux常见的日志服务管理的常见日志服务
linux·运维·服务器
hkhkhkhkh12321 小时前
Linux设备节点基础知识
linux·服务器·驱动开发
HZero.chen1 天前
Linux字符串处理
linux·string
张童瑶1 天前
Linux SSH隧道代理转发及多层转发
linux·运维·ssh
汪汪队立大功1231 天前
什么是SELinux
linux
石小千1 天前
Linux安装OpenProject
linux·运维
柏木乃一1 天前
进程(2)进程概念与基本操作
linux·服务器·开发语言·性能优化·shell·进程
Lime-30901 天前
制作Ubuntu 24.04-GPU服务器测试系统盘
linux·运维·ubuntu
百年渔翁_肯肯1 天前
Linux 与 Unix 的核心区别(清晰对比版)
linux·运维·unix