Skip to content

LV250-设备树插件的应用

怎么在 linux 系统中使用设备树插件?若笔记中有错误或者不合适的地方,欢迎批评指正 😃。

一、移植设备树插件

1. 挂载 configfs 虚拟文件系统

1.1 内核配置

configfs 虚拟文件系统是什么?这个我们后面会学习,现在主要是学习设备树插件的使用。首先我们打开 Linux 内核源码, 输入以下命令打开 menuconfig 配置界面。

shell
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v6_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
img

界面打开之后,按以下菜单找到对应的配置

shell
	File systems  --->
         Pseudo filesystems  --->
            {M} Userspace-driven configuration filesystem
img

将这一项从 M 改为 *。修改完进行保存。

1.2 编译验证

将编译之后的内核镜像烧写到开发板上, 接着可以使用 mount 命令检查 configfs 虚拟文件系统是否挂载成功:

shell
mount
image-20250304194052713

没有 configfs 相关的内容就说明没有自动挂载上,我们可以用 mount 命令手动挂载:

shell
mount -t configfs none /sys/kernel/config

挂载成功如下图:

image-20250304194212262

2. 配置内核支持设备树插件

我们打开 Linux 内核源码, 还是输入以下命令打开 menuconfig 配置界面。

shell
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v6_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

2.1 Device Tree overlay

界面打开之后,按以下菜单找到对应的配置项

shell
    Device Drivers  --->
         -*- Device Tree and Open Firmware support  --->
             [*]   Device Tree overlays
img

2.2 Overlay filesystem support

按以下菜单找到对应的配置项

shell
    File systems  --->
        <*> Overlay filesystem support
        -*-   Overlayfs: turn on redirect directory feature by default
        [*]   Overlayfs: follow redirects even if redirects are turned off (NEW)
        [*]   Overlayfs: turn on inodes index feature by default 
        [*]   Overlayfs: auto enable inode number mapping
        [*]   Overlayfs: turn on metadata only copy up feature by default
img

3. 移植驱动

如果已经学完了 configfs 虚拟文件系统的数据结构。其实完全可以自己编写驱动实现一个设备树插件。 但是我们没有必要重复造轮子, github 上有大神编写好的设备树插件驱动,例如 GitHub - ikwzm/dtbocfg: Device Tree Blob Overlay Configuration File System

image-20250304190241625

这就是一个驱动模块的源码,我们修改 Makefile 配置好源码的路径和编译工具,直接编译就可以了,编译完毕会得到一个 ko 文件,这个后面会用到。

4. 总结

移植设备树插件主要包括以下几个步骤 :

(1)配置内核支持挂载 configfs 虚拟文件系统。

(2)配置内核支持设备树插件。

(3)移植设备树插件驱动。

其中(1)和(2)完成后要注意重新编译内核,再把开发板中的内核更新一下。

二、设备树插件实例

1. 设备树插件中添加节点

1.1 设备树插件

1.1.1 设备树源码

我们用 imx6ull-alpha-emmc.dts 中 led 灯的这个设备节点:

c
/dts-v1/;

#include "imx6ull.dtsi"
#include "imx6ull-alpha-emmc.dtsi"

/ {
	model = "Freescale i.MX6 UlltraLite ALPHA EMMC Board";
	compatible = "fsl,imx6ull-alpha-emmc", "fsl,imx6ull";
    //把这个节点删掉,移到设备树插件中
    sdev_led {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "sdev_led";
        status = "okay";
        reg = < 0X020C406C 0X04 /* CCM_CCGR1_BASE */
            0X020E0068 0X04 /* SW_MUX_GPIO1_IO03_BASE */
            0X020E02F4 0X04 /* SW_PAD_GPIO1_IO03_BASE */
            0X0209C000 0X04 /* GPIO1_DR_BASE */
            0X0209C004 0X04 >; /* GPIO1_GDIR_BASE */
	};
};

&clks {
	assigned-clocks = <&clks IMX6UL_CLK_PLL3_PFD2>;
	assigned-clock-rates = <320000000>;
};

我们写一个设备树插件 imx6ull-alpha-emmc-overlay.dts 如下:

c
/dts-v1/;
/plugin/;

&{/} {
    overlay_node{
        sdev_led {
            #address-cells = <1>;
            #size-cells = <1>;
            compatible = "sdev_led";
            status = "okay";
            reg = < 0X020C406C 0X04 /* CCM_CCGR1_BASE */
                0X020E0068 0X04 /* SW_MUX_GPIO1_IO03_BASE */
                0X020E02F4 0X04 /* SW_PAD_GPIO1_IO03_BASE */
                0X0209C000 0X04 /* GPIO1_DR_BASE */
                0X0209C004 0X04 >; /* GPIO1_GDIR_BASE */
        };
    };
};

我们把主设备树中的 sdev_led 节点移动到设备树插件中去。需要注意的是,这样在设备树插件中添加节点的操作似乎并不会自动取生成 platform_device,所以如果用的平台设备驱动的话可能会有问题。

1.1.2 编译设备树插件

我们使用以下命令进行编译设备树插件:

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

设备树的编译可以看 demo 中的 makefile,它包含了一些其他的设备树和头文件,所以编译会复杂一点。

1.2 更新内核和设备树

我们按照前面的更新内核和设备树,然后重启设备。然后将 imx6ull-alpha-emmc-overlay.dtbo 和 dtbocfg.ko 放到开发板中。

1.3 环境准备

1.3.1 configfs 文件系统挂载

在内核根文件系统中,有一个文件 /proc/filesystems , 它表示当前内核支持的文件系统,通常是编入内核的文件系统类型,但也可以通过模块加入新的类型。可以通过命令 cat /proc/filesystems 检查 configfs 是否支持。 支持的话就会有如下信息 :

image-20250304194430956

不支持的话可以看前面的笔记对内核进行配置。支持之后,我们可以用 mount 命令看一下有没有挂载上,若是没挂载的话,后面加载驱动是不会生成对应的目录的。可以使用以下命令挂载:

shell
mount -t configfs none /sys/kernel/config
1.3.2 加载 dtbocfg.ko

我们通过以下命令加载:

shell
insmod dtbocfg.ko

会有如下打印信息:

image-20250316110056630

加载成功应该会生成 /sys/kernel/config/device-tree/overlays 目录:

image-20250316110142985

要是没有的话,就注意用 mount 看一下是不是成功挂载了 configfs。

1.4 设备树插件测试

  • (1)查看未添加设备树插件的时候的设备树情况
shell
ls /proc/device-tree/
image-20250316110402857
  • (2)我们进入 /sys/kernel/config/device-tree/overlays 目录
shell
cd /sys/kernel/config/device-tree/overlays
  • (3)新建一个 dtbo_demo 目录
shell
mkdir dtbo_demo

image-20250316110241369

然后进入这个目录就会发现这个目录下自动生成了两个文件:dtbo 和 status。

  • (4)将设备树插件的内容写入到 dtbo 中
shell
cd /sys/kernel/config/device-tree/overlays/dtbo_demo
cat /drivers_demo/imx6ull-alpha-emmc-overlay.dtbo > dtbo
  • (5)使能 dtbo
shell
cd /sys/kernel/config/device-tree/overlays/dtbo_demo
echo 1 > status
  • (6)查看设备树插件加载的节点
shell
ls /proc/device-tree/overlay_node/
image-20250316110717161
  • (7)删除使用 dtbo 修改的节点
shell
cd /sys/kernel/config/device-tree/overlays
rmdir dtbo_demo
# 或者
cd /sys/kernel/config/device-tree/overlays/dtbo_demo
echo 0 > status

然后我们再查看一下 /proc/device-tree,就会发现没有 overlay_node 节点了:

image-20250316110936568

2. 修改后设备树节点属性

2.1 设备树插件

我们用 imx6ull-alpha-emmc.dts 中 led 灯的这个设备节点:

c
/dts-v1/;

#include "imx6ull.dtsi"
#include "imx6ull-alpha-emmc.dtsi"

/ {
	model = "Freescale i.MX6 UlltraLite ALPHA EMMC Board";
	compatible = "fsl,imx6ull-alpha-emmc", "fsl,imx6ull";

    sdev_led {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "sdev_led";
        //status = "disable";
        reg = < 0X020C406C 0X04 /* CCM_CCGR1_BASE */
            0X020E0068 0X04 /* SW_MUX_GPIO1_IO03_BASE */
            0X020E02F4 0X04 /* SW_PAD_GPIO1_IO03_BASE */
            0X0209C000 0X04 /* GPIO1_DR_BASE */
            0X0209C004 0X04 >; /* GPIO1_GDIR_BASE */
	};
};

&clks {
	assigned-clocks = <&clks IMX6UL_CLK_PLL3_PFD2>;
	assigned-clock-rates = <320000000>;
};

我们写一个设备树插件 imx6ull-alpha-emmc-overlay.dts 如下:

c
/dts-v1/;
/plugin/;

//修改设备树节点属性的 demo
/{
    fragment@0 {
        target-path = "/alpha/sdev_led";
        __overlay__ {
            overlay_node{
            	status = "okay";
            };
        };
    };
};

我们把主设备树中的 sdev_led 节点移动到设备树插件中去。需要注意的是,这样在设备树插件中添加节点的操作似乎并不会自动取生成 platform_device,所以如果用的平台设备驱动的话可能会有问题。

2.2 开发板测试

  • (1)加载设备树插件之前节点的情况
image-20250316114743941
  • (2)加载设备树插件之前加载驱动
image-20250316114835680

看到会报一个状态读取失败,然后我们运行测试 demo,发现可以正常操作,这个应该是因为我内部判断了,但是没有返回错误的原因,不过这里不影响测试。测完卸载驱动。

  • (3)加载设备树插件
shell
# 挂载 configfs 文件系统
mount -t configfs none /sys/kernel/config

# 加载设备树插件驱动
insmod dtbocfg.ko

# 创建目录
cd /sys/kernel/config/device-tree/overlays
mkdir dtbo_demo

# 将设备树插件的内容写入到 dtbo 中
cd /sys/kernel/config/device-tree/overlays/dtbo_demo
cat /drivers_demo/imx6ull-alpha-emmc-overlay.dtbo > dtbo

# 使能 dtbo  
cd /sys/kernel/config/device-tree/overlays/dtbo_demo
echo 1 > status
image-20250316115228837

可以看到这里生成了一个 overlay_node 目录,里面包含了 name 和 status 属性。

  • 重新加载设备的驱动
shell
insmod sdriver_demo.ko
image-20250316115355677

发现还是报错的,这是因为 status 属性并不是在 /alpha/sdev_led/status,而是 alpha/sdev_led/overlay_node/status 所以获取的时候出现了问题,这个大概了解就可以了,后续使用设备树插件的话需要注意这个事情。