Linux驱动开发—设备树基本概念,语法详解

什么是设备树,为什么引入设备树?

设备树(Device Tree,简称DT)是一种数据结构,用于描述硬件的布局和连接方式。它最初由Open Firmware引入,后来被Linux社区采用,用于解决在嵌入式系统中硬件描述的问题。设备树通过一种独立于硬件平台的方式,向操作系统内核提供设备信息,使得内核不再需要内置具体的硬件配置代码,从而提高了系统的可移植性和灵活性

引入设备树的主要原因包括:

  1. 平台独立性:设备树使硬件描述从内核代码中分离出来,通过一份设备树文件(通常是.dts文件)来描述硬件。这样,同一内核可以运行在不同硬件平台上,只需提供相应的设备树文件。
  2. 简化内核代码:将硬件描述从内核代码中抽离出来,可以减少内核代码的复杂度和维护难度,特别是对于嵌入式系统和多平台支持的内核。
  3. 动态配置:设备树使得硬件配置可以在系统启动时动态加载和解析,而不需要重新编译内核。这样可以更方便地添加、删除和修改硬件配置。
  4. 硬件抽象:设备树提供了一种标准化的方式来描述硬件,使得硬件厂商和内核开发者可以更方便地沟通和协作。

设备树基本概念

相关术语解释

  1. DT(Device Tree,设备树):设备树是一种数据结构,用于描述计算机系统的硬件布局。它包含系统中的各种硬件组件及其连接关系,通过一个层次化的树结构来表示。设备树用于向操作系统内核提供硬件信息,使内核能够正确地初始化和操作这些硬件。

  2. FDT(Flattened Device Tree,扁平设备树):FDT是设备树的一种二进制表示形式,适用于在内核引导时使用。FDT由设备树编译器(dtc)生成,是dts(设备树源文件)编译后的产物。它以一种紧凑的方式存储设备树数据,使其更适合在系统启动时加载和解析。

  3. dts(Device Tree Source,设备树源文件):dts文件是设备树的源文件,以文本格式编写,描述了系统中的硬件设备及其属性。dts文件通常由硬件开发人员或系统集成商编写,并在系统启动前编译成dtb文件供内核使用。

  4. dtsi(Device Tree Source Include,设备树源包含文件):dtsi文件是设备树源文件的包含文件,类似于编程中的头文件。它们通常包含共享的硬件描述,用于不同的dts文件中,通过#include指令包含到具体的dts文件中。这样可以避免重复代码,并且便于管理和维护。

  5. dtb(Device Tree Blob,设备树二进制文件):dtb文件是由dts文件编译生成的二进制文件,包含了设备树的扁平表示形式(FDT)。dtb文件在系统启动时由引导加载程序(如U-Boot)加载,并传递给操作系统内核,以便内核根据其中描述的信息初始化硬件。

  6. dtc(Device Tree Compiler,设备树编译器):dtc是将dts文件编译为dtb文件的工具。dtc可以将设备树源文件(dts)编译成设备树二进制文件(dtb),也可以将dtb反编译为dts,以便进行调试和修改。

DTS,DTSI,DTB,DTC之间的关系

在这里插入图片描述

设备树源码所在地

在Linux内核源码中,设备树源码一般存放在,源码/arch/arm64/boot/dts 该目录下

在这里插入图片描述

如果是32位的话,设备树源码在 源码/arch/arm/boot/dts

在这里插入图片描述

使用DTC编译设备树

首先要找到DTC编译器,一般存放在内核目录下的 scripts/dtc文件夹

注:要先编译Linux内核源码之后,才能生成DTC编译器

在这里插入图片描述

写一个最简单的设备树源码

/dts-v1/;
/ {
    compatible = "simple-system";
    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu@0 {
            device_type = "cpu";
            reg = <0>;
            compatible = "simple-cpu";
        };
    };
};

基本的DTC编译命令

dtc -I dts -O dtb -o output_file.dtb input_file.dts

dtc: 调用设备树编译器。

-I dts: 指定输入文件的格式为设备树源文件(DTS)。

-O dtb: 指定输出文件的格式为设备树二进制文件(DTB)。

-o output_file.dtb: 指定输出文件的名称。

input_file.dts: 指定输入的设备树源文件。

基本的反编译命令

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

效果演示(编译与反编译)

在这里插入图片描述

设备树语法

设备树(Device Tree)基本语法如下:

1. 节点 (Node)

设备树的核心是节点,每个节点表示一个硬件设备或逻辑设备。每个节点有一个名称,并且可以包含属性和子节点。同级路径下节点名称不能相同,不同级路径的节点名称可以重复。对节点名称一般要体现设备的类型

节点名称格式:[标签]:<名称>[@<设备地址>] ,其中标签和设备地址是可选的,名称必须要有

/node_name {
    property_name = value;
    subnode_name {
        property_name = value;
    };
};

2. 属性 (Property)

属性是节点中的键值对,用于描述设备的特性。属性可以是字符串、整数、布尔值或字节数组。

典型属性:reg 属性

reg 属性可以用来描述地址信息。比如说寄存器的值

格式如下:

reg = <address1 len1 address2 len2 …>

举例:

reg = <0x2200000 0x4000>
reg = <0x2050000 0x4000
	   0x2150000 0x4000
 	   0x2170000 0x4000
		>

#address-cell 和 #size-cell 用来描述子节点中reg信息中的地址和长度信息

举例:

node_name {
    #address-cell  = <1>;
    #size-cell  = <1>;
    node_chird {
    	reg = <0x02000000 0x4000> /* 一个地址 一个长度 */
    }
};
node_name {
    #address-cell  = <2>;
    #size-cell  = <0>;
    node_chird {
    	reg = <0x02 0x40> /* 两个地址  没有长度 */
    }
};

model 属性 一般用来表述一些信息,比如说设备的名称和版本等等

status 属性 ,与设备状态有关系

属性值描述
okay设备为可用状态
disable设备为不可用状态
fall设备为不可用状态,并检测到了错误
fall xxx设备为不可用状态,并检测到了错误,错误内容为xxx

compatible 属性 :非常重要的属性,用来和驱动进行匹配的,匹配成功之后,会调用驱动中的probe函数。

compatible = "mixel,lvds-phy";

匹配的时候优先和第一个值mixel进行匹配,如果没有就使用第二个值进行匹配。

3. 包含文件 (Include Files)

dtsi文件是设备树的包含文件,可以用于共享和重用硬件描述。

#include "common.dtsi"

node_name {
    property_name = value;
};

4. 节点路径 (Node Path)

节点通过路径进行引用,路径用斜杠分隔。

/ {
    node1 {
        node2 {
            property = <0>;
        };
    };
};

5. 别名 (Alias)

别名用于为节点提供一个简短的名称,方便引用。一个特殊的节点,定义别名的目的就是为了方便引用节点,可以批量地定义节点,可以使代码更加整齐

/ {
    aliases {
        alias_name = &node_name;
    };
    
    node_name: node_label {
        property_name = value;
    };
};

6. 复合节点 (Phandle)

节点可以通过引用其他节点的方式进行关联,使用&符号引用节点标签。

/ {
    node1: node1_label {
        property_name = <&node2_label>;
    };

    node2: node2_label {
        property_name = value;
    };
};

7. 定义与引用 (Definition and Reference)

节点和属性的值可以定义为常量,并在其他地方引用。

#define MY_CONSTANT 0x12345678

node_name {
    property_name = <MY_CONSTANT>;
};

示例设备树

以下是一个完整的示例设备树:

/dts-v1/;

/ {
    compatible = "my,board";
    model = "My Custom Board";

    aliases {
        serial0 = &uart0;
    };

    cpu0: cpu@0 {
        device_type = "cpu";
        compatible = "arm,cortex-a9";
        reg = <0>;
    };

    memory {
        device_type = "memory";
        reg = <0x80000000 0x20000000>; /* 512MB at 0x80000000 */
    };

    uart0: serial@101f1000 {
        compatible = "ns16550a";
        reg = <0x101f1000 0x1000>;
        interrupt-parent = <&intc>;
        interrupts = <1 4>;
    };

    intc: interrupt-controller@10140000 {
        compatible = "arm,gic";
        reg = <0x10140000 0x1000>;
        interrupt-controller;
        #interrupt-cells = <3>;
    };
};

关键点总结

  • 节点用大括号 {} 包围。
  • 属性用键值对表示,键是属性名,值是属性值。
  • 使用 #include 引入外部 dtsi 文件。
  • 使用别名和 phandle 进行节点间的引用。
  • 使用定常量定义和引用来简化配置。

设备树通过这些语法元素,提供了一种灵活、可扩展的方式来描述硬件结构和配置,使得硬件描述与操作系统内核分离,提高了系统的可移植性和维护性。

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Trump. yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值