Linux 设备树 DTS 与 DTSI 入门指南

Linux 设备树 DTS 与 DTSI 入门指南

📌 什么是 DTS / DTSI?

  • DTS(Device Tree Source):主设备树源文件,定义某个具体设备或开发板的硬件结构,比如处理器、内存、外设等。
  • DTSI(Device Tree Source Include):设备树的包含文件,可被多个 DTS 文件共享,主要用于公用的硬件部分(如同系列 SoC)。

类似于 C 语言的 .h 头文件和 .c 源文件关系。


🧠 它们如何工作?

  1. 开发者编写 .dts.dtsi 文件;
  2. 使用 dtc 编译成 .dtb(Device Tree Blob);
  3. 内核启动时加载 .dtb,据此初始化硬件;
  4. Linux 内核用它来注册平台设备、加载驱动等。

📚 DTS / DTSI 基本语法

设备树是一种类似 C 结构体风格的描述语言。

✅ 示例结构

/ {
    compatible = "vendor,board-model";
    model = "My Device Board";

    memory@80000000 {
        device_type = "memory";
        reg = <0x80000000 0x10000000>;
    };

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

    soc {
        uart@40000000 {
            compatible = "vendor,uart";
            reg = <0x40000000 0x1000>;
            interrupts = <5>;
        };
    };
};

🧾 常用关键字说明

属性名含义
compatible匹配驱动
reg寄存器地址和大小
interrupts中断号
status启用状态(okay/disabled
#address-cells地址单元数
#size-cells大小单元数
include引用 dtsi 文件

🔧 DTS / DTSI 示例

dtsi 文件(通用 SoC)

// soc.dtsi
/soc {
    #address-cells = <1>;
    #size-cells = <1>;

    uart0: serial@40000000 {
        compatible = "vendor,uart";
        reg = <0x40000000 0x1000>;
        interrupts = <5>;
        status = "disabled";
    };
};

dts 文件(具体开发板)

// myboard.dts
/include/ "soc.dtsi"

/ {
    model = "Vendor MyBoard";
    compatible = "vendor,myboard";

    memory@80000000 {
        device_type = "memory";
        reg = <0x80000000 0x10000000>;
    };

    &uart0 {
        status = "okay";
    };
};

🛠️ 编译 DTS 到 DTB

dtc -I dts -O dtb -o myboard.dtb myboard.dts

参数说明:

  • -I dts:输入是 DTS 格式;
  • -O dtb:输出为 DTB 格式;
  • -o:指定输出文件。

🚀 使用场景

  • ARM SoC(Allwinner、NXP i.MX、Rockchip 等)平台;
  • 添加 SPI/I2C 传感器;
  • 配置 GPIO 中断、引脚复用;
  • 适配裸机驱动或 Linux 驱动。

✅ 开发流程总结

  1. 阅读芯片手册,了解硬件外设;
  2. 编写通用的 .dtsi 文件;
  3. 编写开发板专属的 .dts 文件;
  4. 使用 dtc 编译生成 .dtb
  5. 与 Bootloader 或内核一起部署。

通常linux 的arch/arm/dts中带有一些对应芯片平台通用的 DTS 文件, 可以根据SoC 型号和硬件信息(如 UART、SPI、LED 等)进行修改。


myboard.dts 文件解析与说明

以下是一个典型的设备树源文件 myboard.dts,用于描述某个开发板上的硬件信息,并引用了通用的 SoC 定义文件 soc.dtsi


📄 源码内容

// myboard.dts
/include/ "soc.dtsi"

/ {
    model = "Vendor MyBoard";
    compatible = "vendor,myboard";

    memory@80000000 {
        device_type = "memory";
        reg = <0x80000000 0x10000000>;
    };

    &uart0 {
        status = "okay";
    };
};

🧠 分段解析

#include "soc.dtsi"

  • 引入通用的 SoC 定义文件,提供基础硬件(如 UART、I2C 等)配置。
  • .dtsi 文件中一般包含 CPU、外设控制器等节点。

根节点 / { ... }

modelcompatible
  • model = "Vendor MyBoard";

    • 表示当前开发板的名称,仅用于标识。
  • compatible = "vendor,myboard";

    • Linux 内核用它来选择合适的驱动程序。

内存定义

memory@80000000 {
    device_type = "memory";
    reg = <0x80000000 0x10000000>;
};
  • 描述系统内存的起始地址和大小:
    • 起始地址:0x80000000
    • 大小:0x10000000(256MB)
  • device_type = "memory" 是必须的标准属性。

外设引用:&uart0

&uart0 {
    status = "okay";
};
  • &uart0 表示引用在 soc.dtsi 中定义的 UART 节点。
  • 设置其状态为 "okay",表示启用该设备(默认可能是 "disabled")。

🛠️ 编译方式

使用 dtc(Device Tree Compiler)将 dts 文件编译为内核可识别的 dtb 格式:

dtc -I dts -O dtb -o myboard.dtb myboard.dts
  • -I dts:输入格式为 dts;
  • -O dtb:输出格式为 dtb;
  • -o myboard.dtb:指定输出文件名。

✅ 总结

这个 myboard.dts 文件:

  • 定义了开发板的模型信息;
  • 配置了内存;
  • 启用了一个串口设备(通过引用 soc.dtsi 中的 uart0);
  • 是 Linux 启动过程中平台设备初始化的重要组成部分。

在 DTS 中自定义新的外设节点指南

在设备树(DTS)中,除了继承和修改 .dtsi 文件中已有的外设外,你也可以完全自定义新的设备节点,比如一个额外的 GPIO 接口、LED、I2C/SPI 传感器等。


✅ 示例:自定义一个 GPIO 控制的 LED

前提:SoC 的 GPIO 控制器定义在 soc.dtsi

gpio1: gpio@50000000 {
    compatible = "vendor,gpio";
    reg = <0x50000000 0x1000>;
    gpio-controller;
    #gpio-cells = <2>;
};

自定义 LED 外设节点(在 DTS 中添加)

/ {
    model = "Vendor MyBoard";
    compatible = "vendor,myboard";

    leds {
        compatible = "gpio-leds";

        status-led {
            label = "status";
            gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; // GPIO1 第5号管脚
            default-state = "off";
        };
    };
};

🧾 字段说明

字段说明
leds自定义的设备节点名,可任意命名
compatible使用内核中已有的 gpio-leds 驱动
status-ledLED 子节点名称
labelLED 的名字标签
gpios使用哪一个 GPIO 控制器和引脚,格式为 <控制器别名 管脚号 电平>
default-state初始状态(onoffkeep

🚀 其他常见的可自定义外设

SPI 设备示例

&spi0 {
    my_sensor@0 {
        compatible = "vendor,my-sensor";
        reg = <0>; // SPI 片选号
        spi-max-frequency = <1000000>;
    };
};

I2C 设备示例

&i2c1 {
    my_touch@14 {
        compatible = "vendor,my-touch";
        reg = <0x14>; // I2C 地址
    };
};

⚠️ 注意事项

  • 所有自定义节点必须挂载在正确的父节点下(如 SPI、I2C、GPIO 等控制器);
  • compatible 字符串必须与你的驱动支持的值一致;
  • 如果没有现成驱动,也可以基于 platform_driver 写你自己的 Linux 驱动。

如果 .dtsi 文件中没有定义父节点,但你想在 .dts 文件中添加新的外设节点,该怎么办呢?


⚠️ 设备树节点必须有父节点

设备树是树形结构,每个节点都必须有父节点。你不能直接在根节点之外放置孤立节点。

  • .dtsi 里通常定义了 SoC 的各种硬件总线(如 &uart0, &spi0, &gpio1)等父节点。
  • 如果 .dtsi 里没有这些父节点,你就得自己在 .dts 里补上。

🚀 如果 .dtsi 没有父节点怎么办?

方案 A:自己在 .dts 中定义父节点

你可以在 .dts 文件的根节点下,手动添加完整的父节点定义,例如:

/ {
    gpio1: gpio@50000000 {
        compatible = "vendor,gpio";
        reg = <0x50000000 0x1000>;
        gpio-controller;
        #gpio-cells = <2>;
    };

    leds {
        compatible = "gpio-leds";

        status-led {
            label = "status";
            gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
            default-state = "off";
        };
    };
};

这样你的设备树里就有了 gpio1 这个父节点,status-led 才能引用它。


方案 B:向 SoC DTSI 文件中添加父节点

如果你能修改 .dtsi,建议把父节点放进 .dtsi,然后在 .dts 里只写外设节点,结构更清晰。


方案 C:自定义新的父节点(如果是新硬件)

如果你的硬件平台全新设计,没有 .dtsi,你就需要在 .dts 里写完整的设备树,包括所有父节点和外设。


✅ 小结

  • 设备树节点必须在已有父节点下,不能孤立。
  • 父节点可以在 .dtsi 里,也可以自己在 .dts 中补上。
  • 如果没有父节点,设备树就不完整,内核驱动无法识别设备。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值