Skip to content

LV220-设备树插件简介 ​

设备树插件是什么?若笔记中有错误或者不合适的地方,欢迎批评指正 😃。

一、设备树插件? ​

1. 什么是设备树插件 ​

Linux4.4 以后引入了动态设备树(Dynamic DeviceTree) 。 设备树插件(Device Tree Overlay)是一种用于设备树(Device Tree) 的扩展机制。 设备树是一种用于描述硬件设备的数据结构,广泛应用于嵌入式系统中, 特别是基于 Linux 内核的系统中。

设备树插件 允许在运行时动态修改设备树的内容, 以便添加, 修改或删除设备节点和属性。它提供了一种灵活的方式来配置和管理硬件设备, 而无需重新编译整个设备树。 通过使用设备树插件, 开发人员可以在不重新启动系统的情况下对硬件进行配置更改。

设备树插件(Dynamic DeviceTree) 通常以一种文本格式定义, 称为设备树源文件(Device Tree Source, DTS) 。 DTS 文件描述了设备树的结构和属性, 包括设备节点, 寄存器地址, 中断信息等。 设备树插件可以通过加载和解析设备树文件, 并将其合并到现有的设备树中, 从而实现对设备树的动态修改。

设备树插件可以理解为主设备树的“补丁”它动态的加载到系统中,并被内核识别。 例如我们要在系统中增加 RGB 驱动,那么我们可以针对 RGB 这个硬件设备写一个设备树插件, 然后编译、加载到系统即可,无需从新编译整个设备树。

2. 应用场景 ​

使用设备树插件, 可以实现一些常见的配置变化, 比如添加外部设备, 禁用不需要的设备,修改设备属性等。 这对于嵌入式系统的开发和调试非常有用, 特别是面对多种硬件配置或需要频繁更改硬件配置的情况下。

二、基本语法 ​

设备树插件是在设备树基础上增加的内容,我们之前讲解的设备树语法完全适用, 甚至我们可以直接将之前编写的设备树节点复制到设备树插件里。但是也会有自己的一些语法,下面就来看一下。

1. 头部声明 ​

设备树插件有 插件头部声明, 它指定了插件的名称和版本等信息, 并指定了要修改的设备树的路径, 如下所示:

c
/dts-v1/;
/plugin/;
  • 第 1 行: 用于指定 dts 的版本。
  • 第 2 行: 表示允许使用未定义的引用并记录它们,设备树插件中可以引用主设备树中的节点,而这些“引用的节点”对于设备树插件来说就是未定义的,所以设备树插件应该加上“/plugin/”。

2. 节点 ​

插件节点名称用于定义要添加, 修改或删除的设备节点及其属性。 它使用与设备树源文件相同的语法, 但在节点名称前面使用特定的修饰符来指示插件的操作。

比如设备树中 rs485 节点为如下所示, rs485 节点位于根节点下:

c
/dts-v1/;
/ {
    model = "This is my devicetree!";
    #address-cells = <1>;
    #size-cells = <1>;
    chosen {
        bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
    };
    //......
    rk_485_ctl: rk-485-ctl {
        compatible = "topeet, rs485_ctl";
        gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
        pinctrl-names = "default";
        pinctrl-0 = <&rk_485_gpio>;
    };
};

那么我们如果在设备树插件中要为这个节点添加 overlay_node 节点, 可以有四种表达方式:

2.1 方式一:从根节点开始的绝对路径 ​

c
/dts-v1/;
/plugin/;

&{/rk-485-ctl} {
    overlay_node{
        status = "okay";
    };
};

2.2 方式二:使用节点的别名 ​

c
/dts-v1/;
/plugin/;

&rk_485_ctl {
    overlay_node{
        status = "okay";
    };
};

2.3 方式三 ​

固定写法,如果有多个节点,通过子节点 fragment@x 的序号区分,路径也是绝对路径:

c
/dts-v1/;
/plugin/;

/{
    fragment@0 {
        target-path = "/rk-485-ctl";
        __overlay__ {
            overlay_node{
            	status = "okay";
            };
        };
    };
};
  • 第 6 行: 指定设备树插件的加载位置,默认我们加载到根节点下,既“target-path =“/”。
  • 第 7-8 行: 我们要插入的设备及节点或者要引用(追加)的设备树节点放在__overlay__ {…};内。

方式一编译为 dtbo 后,再反编译就会得到这种格式的。

2.4 方式四 ​

固定写法,如果有多个节点,通过子节点 fragment@x 的序号区分,路径也可以用别名:

c
/dts-v1/;
/plugin/;

/{
    fragment@0 {
        target = <&rk_485_ctl>;
        __overlay__ {
            overlay_node{
            	status = "okay";
            };
        };
    };
};

方式二编译为 dtbo 后,再反编译就会得到这种格式的。

3. 总结 ​

设备树插件拥有相对固定的格式,甚至可以认为它只是把设备节点加了一个“壳”编译后内核能够动态加载它。

3.1 基本格式 1 ​

c
/dts-v1/;
/plugin/;

 / {
        fragment@0 {
            target-path = "/";
            __overlay__ {
                /*在此添加要插入的节点*/
                .......
            };
        };

        fragment@1 {
            target = <&XXXXX>;
            __overlay__ {
                /*在此添加要插入的节点*/
                .......
            };
        };
    .......
 };
  • 第 1 行: 用于指定 dts 的版本。
  • 第 2 行: 表示允许使用未定义的引用并记录它们,设备树插件中可以引用主设备树中的节点,而这些“引用的节点”对于设备树插件来说就是未定义的,所以设备树插件应该加上“/plugin/”。
  • 第 6 行: 指定设备树插件的加载位置,默认我们加载到根节点下,既“target-path =“/”, 或者使用 target = <&XXXXX >,增加节点或者属性到某个节点下。
  • 第 7-8 行: 我们要插入的设备及节点或者要引用(追加)的设备树节点放在__overlay__ {…}内,你可以增加、修改或者覆盖主设备树的节点。

3.2 基本格式 2 ​

c
/dts-v1/;
/plugin/;

&{/} {
    /*此处在根节点 "/" 下, 添加要插入的节点或者属性*/
};

&XXXXX {
    /*此处在节点 "XXXXX" 下, 添加要插入的节点或者属性*/
};

三、设备树插件编译 ​

1. DTC 编译 ​

使用 dtc 工具:

shell
./dtc -I dts -O dtb overlay.dts -o overlay.dtbo

2. DTC 反编译 ​

使用 dtc 工具:

shell
./dtc -I dtb -O dts overlay.dtbo -o overlay_dtb.dts