第五十二讲 DTS(设备树)
一、简介
随着硬件设备的种类逐年递增,板级platform平台设备文件越来越多。在过去的Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾。
官方对设备树的描述是,一种描述硬件资源的数据结构。它通过bootloader将硬件资源传给内核,使得内核和硬件资源描述相对独立。
设备树的主要优势:对于同一SOC的不同主板,只需更换设备树文件.dtb即可实现不同主板的无差异支持,而无需更换内核文件。
设备树结构:
设备树分类
设备树包含DTC(device tree compiler),DTS(device tree source和DTB(device tree blob)。
- DTS(device tree source):设备树源文件,ASCII格式
- DTC(device tree compiler):设备树编译工具
- DTB(device tree blob):二进制设备树
野火设备树
- 设备树由uboot负责加载到内核,内核解析使用
- 设备树源文件ebf-buster-linux/arch/arm/boot/dts/imx6ull-seeed-npi.dts(注意:这是野火pro开发板的,这里就不传上来了,csdn不能免费下载,这个文件在之前编译好的内核文件里面)
- ebf-buster-linux/arch/arm/boot/dts/imx6ull-seeed-npi.dtb(二进制设备文件,跟设备树源文件存放在同一文件下)
- /boot/dtbs/4.19.71-imx-r1/imx6ull-seeed-npi.dtb(将内核文件的二进制设备文件复制到开发板这个文件下,uboot就可以加载设备树了)
设备树编译
-
内核编译 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- npi_v7_defconfig 会生成一个config文件,记录了内核的详细配置信息 -
编译dts make ARCH=arm -j1 CROSS_COMPILE=arm-linux-gnueabihf- dtbs 生成dtb文件,如果之前没有编译,这里会生成多个文件 -
手工编译(手动调用Linux内核的工具) 将dts编译为dtb ./ scripts/dtc/dtc -I dts -O dtb -o xxx.dtb arch/arm/boot/dts/xxx.dts 将dtb反编译为dts ./scripts/dtc/dtc -I dtb -O dts -o xxx.dts arch/arm/boot/dts/xxx.dtb
二、编写设备树
头文件包含
#include <dt-bindings/input/input.h>
/*
这个文件存放的是一些常用的设备树
如果需要使用
可以直接包含这个文件
*/
#include "imx6ull.dtsi"
节点命名
方法1基本方法
node-name@unit-address
{
属性1=。。。
属性2=。。。
子节点。。。
}
node-name:指定节点名称
unit-address:指定“单元地址”
方法2节点标签
cpu0:cpu@0
{
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
}
与上一个的区别就是cpu0:,这就相当于给节点名称重新再取一个“昵称”,以后可以通过这个“昵称”去叫这个节点了
方法3别名子节点
aliases
{
can0=&flexcan1;
can1=&flexcan2;
ethernet0=&fec1;
ethernet1=&fec2;
...
}
批量为其他子节点取别名
常见节点属性
属性 | 值类型 | 使用方法 | 作用 |
---|
compatible | 字符串 | compatible = “manufacturer ,model” manufacturer :厂商 model:模块对应驱动的名字 例子:compatible = “arm,cortex-at-gic” | compatible 属性的值是一个字符串列表, compatible 属性用于将设备和驱动绑定起来。字符串列表用于选择设备所要使用的驱动程序。 | model | 字符串 | model=“embedfire i.MX6 ULL NPi Board” | 描述板子的型号或者芯片型号 | status | 字符串 | okay:设备正常运行 disable:该设备尚未运行,但是在未来可以变为可操作的,比如热插拔设备插入以后。至于 disabled 的具体含义还要看设备的绑定文档。 fail:表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作。 fail-sss:含义和“fail”相同,后面的 sss 部分是检测到的错误内容。 | 描述设备的状态信息 | reg | 一系列(地址长度)对 | reg = <>0x02000000 0x4000>; | reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息 | #address-cells | u32 | soc { #address-cells = <1>; #size-cells = <1>; compatible = “simple-bus”; interrupt-parent = <&gpc>; ranges; ocrams: sram@900000 { compatible = “fsl,lpm-sram”; reg = <0x900000 0x4000>; }; }; | 决定了子节点 reg 属性中地址信息所占用的字长(32 位) | #size-cells | u32 | 同上 | 决定了子节点 reg 属性中长度信息所占用的字长(32 位) | ranges | ranges 是一个地址映射/转换表 | soc { #address-cells = <1>; #size-cells = <1>; compatible = “simple-bus”; interrupt-parent = <&gpc>; ranges; } | ranges属性值可以为空或者按照(child-bus-address,parent-bus-address,length)格式编写的数字矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成:
child-bus-address:子总线地址空间的物理地址,由父节点的#address-cells 确定此物理地址所占用的字长。
parent-bus-address: 父总线地址空间的物理地址,同样由父节点的#address-cells 确定此物理地址所占用的字长。
length: 子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长。
如果 ranges 属性值为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换,对于我们所使用的 I.MX6ULL 来说,子地址空间和父地址空间完全相同,因此会在 imx6ull.dtsi中找到大量的值为空的 ranges 属性 | name | 字符串 | | name 属性用于记录节点名字, name 属性已经被弃用,不推荐使用name 属性,一些老的设备树文件可能会使用此属性 | device_type | 字符串 | imx6ull.dtsi 的 cpu0 节点用到了此属性 cpu0: cpu@0 { compatible = “arm,cortex-a7”; device_type = “cpu”; reg = <0>; … }; | IEEE 1275 会用到此属性,用于描述设备的 FCode,但是设备树没有 FCode,所以此属性也被抛弃了。此属性只能用于 cpu 节点或者 memory 节点 |
设备树示例
文件路径/sys/firmware/devicetree/base
可以通过cat 命令查看文件内容,对比野火设备树源文件
注意:视频中找的文件是imx6ull-seeed-npi.dts ,但是我在下载下来的内核里面并没有找到这个文件,不过不影响实验。在4.19.35这个内核里面对应的文件是imx6ull-mmc-npi.dts 。不过并不影响接下来的实验。
实验步骤
-
找到文件imx6ull-mmc-npi.dts 路径是ebf_linux_kernel/arch/arm/boot/dts/imx6ull-mmc-npi.dts -
在文件内加入以下代码(暂时可以不懂具体干啥的,不过看参考文档你也会知道是做什么的) test_led{
#address-cells = <1>;
#size-cells = <1>;
rgb_led_red@0x0209C000{
compatible = "fire,rgb_led_red";
reg = <0x0209C000 0x00000020>;
status = "okay";
};
};
再参考资料下面会放出整个文件内容 -
编译设备树(这里电脑太差了 没用多个线程编译) make ARCH=arm -j1 CROSS_COMPILE=arm-linux-gnueabihf- dtbs -
将编译好的文件复制到共享文件目录 cp arch/arm/boot/dts/imx6ull-mmc-npi.dtb ../../nfsshare/ -
打开开发板并且登陆 -
使用nfs连接共享目录 -
转移到dtb目录(这里我的dtb目录也不同于视频中的,所以根据自己的实际情况做这个实验) cd /usr/lib/linux-image-4.19.35-imx6/ -
将原有的dtb文件备份(为了实验完成恢复原有的dtb文件) sudo cp imx6ull-mmc-npi.dtb imx6ull-mmc-npi.dtbback -
将共享文件夹内dtb文件复制到开发板dtb目录下,并覆盖掉原始文件 sudo cp /mnt/imx6ull-mmc-npi.dtb usr/lib/linux-image-4.19.35-imx6/ -
重启开发板 sudo reboot -
登陆开发板 -
查看设备树文件 ls /sys/firmware/devicetree/base/ -
试验成功!!!记得恢复现场呀!!
参考资料列表:
知乎
CSDN
属性资料
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/dts-v1/;
#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"
/ {
model = "Embedfire i.MX6ULL Board";
compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
aliases {
pwm0 = &pwm1;
pwm1 = &pwm2;
pwm2 = &pwm3;
pwm3 = &pwm4;
};
chosen {
stdout-path = &uart1;
};
memory {
reg = <0x80000000 0x20000000>;
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
linux,cma {
compatible = "shared-dma-pool";
reusable;
size = <0x14000000>;
linux,cma-default;
};
};
regulators {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <0>;
reg_sd1_vmmc: regulator@1 {
compatible = "regulator-fixed";
regulator-name = "VSD_3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
off-on-delay = <20000>;
enable-active-high;
};
/*
reg_gpio_dvfs: regulator-gpio {
compatible = "regulator-gpio";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dvfs>;
regulator-min-microvolt = <1300000>;
regulator-max-microvolt = <1400000>;
regulator-name = "gpio_dvfs";
regulator-type = "voltage";
gpios = <&gpio5 3 GPIO_ACTIVE_HIGH>;
states = <1300000 0x1 1400000 0x0>;
};
*/
};
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_led>;
led0: cpu {
label = "cpu";
gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
default-state = "on";
linux,default-trigger = "heartbeat";
};
};
/* External sound card */
sound: sound {
status = "disabled";
};
spi4: 74hc595 {
compatible = "spi-gpio";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spi4>;
pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
status = "disabled";
gpio-sck = <&gpio5 11 0>;
gpio-mosi = <&gpio5 10 0>;
cs-gpios = <&gpio5 7 0>;
num-chipselects = <1>;
#address-cells = <1>;
#size-cells = <0>;
gpio_spi: gpio_spi@0 {
compatible = "fairchild,74hc595";
gpio-controller;
#gpio-cells = <2>;
reg = <0>;
registers-number = <1>;
registers-default = /bits/ 8 <0x57>;
spi-max-frequency = <100000>;
};
};
test_led{
#address-cells = <1>;
#size-cells = <1>;
rgb_led_red@0x0209C000{
compatible = "fire,rgb_led_red";
reg = <0x0209C000 0x00000020>;
status = "okay";
};
};
};
&cpu0 {
/*dc-supply = <®_gpio_dvfs>;*/
clock-frequency = <800000000>;
};
&clks {
assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
assigned-clock-rates = <786432000>;
};
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
status = "okay";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
micrel,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET_REF>;
clock-names = "rmii-ref";
};
ethphy1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
micrel,led-mode = <1>;
clocks = <&clks IMX6UL_CLK_ENET2_REF>;
clock-names = "rmii-ref";
};
};
};
&gpc {
fsl,cpu_pupscr_sw2iso = <0xf>;
fsl,cpu_pupscr_sw = <0x0>;
fsl,cpu_pdnscr_iso2sw = <0x1>;
fsl,cpu_pdnscr_iso = <0x1>;
fsl,ldo-bypass = <0>; /* DCDC, ldo-enable */
};
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog_1>;
pinctrl_hog_1: hoggrp-1 {
fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */
MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */
>;
};
pinctrl_enet1: enet1grp {
fsl,pins = <
MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0
MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0
MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031
>;
};
pinctrl_enet2: enet2grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031
>;
};
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
>;
};
/*
pinctrl_dvfs: dvfsgrp {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x79
>;
};
*/
pinctrl_usdhc1: usdhc1grp {
fsl,pins = <
MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059
MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10071
MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059
MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059
MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059
MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059
>;
};
pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
fsl,pins = <
MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9
MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9
MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9
>;
};
pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
fsl,pins = <
MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9
MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9
MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
>;
};
pinctrl_usdhc2: usdhc2grp {
fsl,pins = <
MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x10069
MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059
MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
>;
};
pinctrl_usdhc2_8bit: usdhc2grp_8bit {
fsl,pins = <
MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x10069
MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059
MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x17059
MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x17059
MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x17059
MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x17059
>;
};
pinctrl_usdhc2_8bit_100mhz: usdhc2grp_8bit_100mhz {
fsl,pins = <
MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100b9
MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170b9
MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170b9
MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170b9
MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170b9
MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170b9
MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170b9
MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170b9
MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170b9
MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170b9
>;
};
pinctrl_usdhc2_8bit_200mhz: usdhc2grp_8bit_200mhz {
fsl,pins = <
MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x100f9
MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x170f9
MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170f9
MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170f9
MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170f9
MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170f9
MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170f9
MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170f9
MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170f9
MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170f9
>;
};
pinctrl_led: ledgrp {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x1b0b0
>;
};
};
&iomuxc_snvs {
pinctrl-names = "default_snvs";
pinctrl-0 = <&pinctrl_hog_2>;
pinctrl_hog_2: hoggrp-2 {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x80000000
>;
};
pinctrl_spi4: spi4grp {
fsl,pins = <
MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1
MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1
MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1
MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000
>;
};
};
&snvs_pwrkey {
status = "okay";
};
&pxp {
status = "okay";
};
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
status = "okay";
};
&usbotg1 {
dr_mode = "otg";
srp-disable;
hnp-disable;
adp-disable;
status = "okay";
};
&usbotg2 {
dr_mode = "host";
disable-over-current;
status = "okay";
};
&usbphy1 {
fsl,tx-d-cal = <106>;
};
&usbphy2 {
fsl,tx-d-cal = <106>;
};
&usdhc1 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc1>;
pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
no-1-8-v;
/*cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;*/
keep-power-in-suspend;
/*non-removable;*/
enable-sdio-wakeup;
vmmc-supply = <®_sd1_vmmc>;
status = "okay";
};
&usdhc2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usdhc2_8bit>;
non-removable;
status = "okay";
};
rent; status = “okay”; };
&usbphy1 { fsl,tx-d-cal = <106>; };
&usbphy2 { fsl,tx-d-cal = <106>; };
&usdhc1 { pinctrl-names = “default”, “state_100mhz”, “state_200mhz”; pinctrl-0 = <&pinctrl_usdhc1>; pinctrl-1 = <&pinctrl_usdhc1_100mhz>; pinctrl-2 = <&pinctrl_usdhc1_200mhz>; no-1-8-v; /cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;/ keep-power-in-suspend; /non-removable;/ enable-sdio-wakeup; vmmc-supply = <®_sd1_vmmc>; status = “okay”; };
&usdhc2 { pinctrl-names = “default”; pinctrl-0 = <&pinctrl_usdhc2_8bit>; non-removable; status = “okay”; };
|