Linux 设备树

Linux设备树讲解(Device Tree)含设备树基本语法

前言

在内核源码中,存在大量对板级细节信息描述的代码。这些代码充斥在/arch/arm/plat-xxx和/arch/arm/mach-xxx目录,对内核而言这些platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data绝大多数纯属垃圾冗余代码。为了解决这一问题,ARM内核版本3.x之后引入了 Device Tree。
文章对设备树的组成、设备树的基本语法、标准属性、节点添加方式及Linux匹配设备树的方法,并且创建了一个小型设备树框架模板。

1. 设备树

设备树(Device Tree),将这个词分开就是“设备”和“树”,描述设备树的文件叫做 DTS(Device Tree Source),这个 DTS 文件采用树形结构描述板级设备,也就是开发板上的设备信息,比如CPU 数量、 内存基地址、IIC 接口上接了哪些设备、SPI 接口上接了哪些设备等等,如下图:

在这里插入图片描述
在上图中,树的主干就是系统总线,IIC 控制器、GPIO 控制器、SPI 控制器等都是接到系统主线上的分支。

例如,IIC 控制器分为 IIC1 和 IIC2 两种,其中 IIC1 上接了 FT5206 和 AT24C02这两个 IIC 设备,IIC2 上只接了 MPU6050 这个设备。

另外,设备树对于可热插拔的热备不进行具体描述,它只描述用于控制该热插拔设备的控制器。

设备树的主要优势:对于同一SOC的不同主板,只需更换设备树文件.dtb即可实现不同主板的无差异支持,而无需更换内核文件。

2. 设备树的组成

设备树包含DTC(device tree compiler)、DTS(device tree source)和DTB(device tree blob)。

2.1. dts和dtsi

xxx.dts文件是一种ASCII文本对Device Tree的描述,放置在内核的/arch/arm/boot/dts目录。一般而言,一个xxx.dts文件对应一个ARM的machine。

xxx.dtsi文件作用:由于一个SOC可能有多个不同的电路板,而每个电路板拥有一个 xxx.dts。这些dts势必会存在许多共同部分,为了减少代码的冗余,设备树将这些共同部分提炼保存在*.dtsi文件中,供不同的dts共同使用。*.dtsi的使用方法,类似于C语言的头文件,在dts文件中需要进行include *.dtsi文件。当然,dtsi本身也支持include 另一个dtsi文件。

2.2. DTB

DTC编译 xxx.dts 生成的二进制文件(xxx.dtb),bootloader在引导内核时,会预先读取xxx.dtb到内存,进而由内核解析。

2.3. DTC

dts和dtsi转换为二进制DTB文件需要使用DTC工具,DTC可以将.dts文件编译成.dtb文件。DTC的源码位于内核的scripts/dtc目录,scripts/dtc/Makefile 文件内容如下:

hostprogs-y := dtc
always	:= $(hostprogs-y)

dtc-objs:= dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
			srcpos.o checks.o util.o
dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o
......

变异DTS文件的活就只需要进入Linux根目录下,执行如下命令:

make all	// 全编译
make dtbs	// 编译设备树文件
  • 如何确定编译的DTS文件?

    基于 ARM 架构的 SOC 有很多种,一种 SOC 又可以制作出很多开发板,每个板子都有一个对应的 DTS 文件。

    下面就以imx6ull为例,arch/arm/boot/dts/Makefile,有如下内容:

    dtb-$(CONFIG_SOC_IMX6UL) += \
    	imx6ul-14x14-ddr3-arm2.dtb \
    	imx6ul-14x14-ddr3-arm2-emmc.dtb \
    ......
    dtb-$(CONFIG_SOC_IMX6ULL) += \
    	imx6ull-14x14-ddr3-arm2.dtb \
    	imx6ull-14x14-ddr3-arm2-adc.dtb \
    	imx6ull-14x14-ddr3-arm2-cs42888.dtb \
    	imx6ull-14x14-ddr3-arm2-ecspi.dtb \
    	imx6ull-14x14-ddr3-arm2-emmc.dtb \
    	imx6ull-14x14-ddr3-arm2-epdc.dtb \
    	imx6ull-14x14-ddr3-arm2-flexcan2.dtb \
    ......
    dtb-$(CONFIG_SOC_IMX6SLL) += \
    	imx6sll-lpddr2-arm2.dtb \
    	imx6sll-lpddr3-arm2.dtb \
    ......
    

    当选中IMX6ULL这个SOC后,该板子对应的.dts都会被编译为.dtb文件。

  • 如何在SOC下添加新的设备树病生成二进制文件?

    例如,在IMX6ULL此SOC新添加设备树 asu.dts 时 若想生成对应的 asu.dtb 需要在 dtb-$(CONFIG_SOC_IMX6ULL)下添加 asu.dtb ,编译时就会生产新的二进制文件。

3. 设备树基本语法

在 .dts 和 .dtsi 文件中包含了一些列节点,以及描述节点的属性。

3.1. dtsi头文件

因为 .dtsi 是描述 SOC 内部信息(即,同等SOC的通用信息),而 .dts 描述的是板级信息,所以 .dts

都会包含 .dtsi 文件。例如,imx6ull的头文件就包含imx6ull.dtsi.

#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"

3.2. 设备节点

备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息,属性就是键 —值对。下面是从imx6ull.dtsi中缩减的部分内容:

/ {					// “/” 根节点,每个设备树只有一个根节点(.dts和.dtsi的根节点最后会合并为一个)
	aliases {		// aliases node,子节点
		gpio0 = &gpio1;
	};
    
	/* 
	 * cpus node,子节点
	 * 格式:node-name@unit-address
	 * "node-name"是节点名字,"unit-address"设备地址活寄存器首地址,没有可以不要
	 */
	cpus {			
		#address-cells = <1>;
		#size-cells = <0>;
        
		/*
		 * cpu0, cpus的子节点
		 * cpu0:cpu@0,使用":"隔开,前面的是节点标签(label),":"后面是节点名字
		 * 格式:label:node-name@unit-address
		 */
		cpu0: cpu@0 {		
			compatible = "arm,cortex-a7";
			device_type = "cpu";
			reg = <0>;
		};
	};
    
    /*
     * intc node,子节点
     * intc:label,interrupt-controller@00a01000:节点名
     * 节点名太长,使用label更方便
     */
	intc: interrupt-controller@00a01000 {
		compatible = "arm,cortex-a7-gic";
		#interrupt-cells = <3>;
		interrupt-controller;
		reg = <0x00a01000 0x1000>,
		      <0x00a02000 0x100>;
	};c
};

3.3. 特殊节点

3.3.1. aliases node

aliases node用于定义别名,使节点引用变得方便。

{
	aliases {
		gpio0 = &gpio1;
		mmc0 = &usdhc1;
		mmc1 = &usdhc2;
		.......
	};
3.3.2. chosen node

chosen不是真实的节点,chosen节点是为了 uboot 向 Linux 内核传递 bootargs 参数。

chosen {
		stdout-path = &uart1;
	};

如上设置了 “stdout-path = &uart1;”,表示标准输出使用 uart1。在开发板 /proc/device-tree/chosen目录下查看,有 stdout-path和bootargs,如下图所示:
在这里插入图片描述

  • bootargs属性

    chosen中多了bootargs属性,查看该属性,发现掐红内容为uboot中设置的环境变量,如下:
    在这里插入图片描述
    uboot在启动Linux时会把bootargs的值传递给Linux内核,bootargs会作为Linux内核的命令行参数,Linux内核启动的时候会打印出命令行参数(即uboot传递的bootargs值),如下所示:
    在这里插入图片描述

  • uboot如何在chosen节点添加bootargs属性?

    全局搜索在common/fdt_support.c 文件中发现了“chosen”,fdt_support.c 文件中有个 fdt_chosen 函
    数,此函数内容如下所示:

    int fdt_chosen(void *fdt){
    	int nodeoffset;
    	int err;
    	char *str;		/* used to set string properties */
    
    	err = fdt_check_header(fdt);
    	if (err < 0) {
    	printf("fdt_chosen: %s\n", fdt_strerror(err));
    	return err;
    	}
    
    	/* find or create "/chosen" node. */
        /* 调用函数 fdt_find_or_add_subnode 从设备树(.dtb)中找到 chosen 节点,如果没有
    找到的话就会自己创建一个 chosen 节点 */
    	nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
    	if (nodeoffset < 0)
    		return nodeoffset;
        
    	/* 读取 uboot 中 bootargs 环境变量的内容 */
    	str = getenv("bootargs");
    	if (str) {
            /* 调用函数 fdt_setprop 向 chosen 节点添加 bootargs 属性,并且 bootargs 属性的值
    		   就是环境变量 bootargs 的内容 */
    		err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
    			strlen(str) + 1);
    		if (err < 0) {
                printf("WARNING: could not set bootargs %s.\n",
    					fdt_strerror(err));
    			return err;
    		}
    	}
    
    	return fdt_fixup_stdout(fdt, nodeoffset);
    }
    

    由fdt_support.c可知,uboot 中的 fdt_chosen 函数在设备树的 chosen 节点中加入了 bootargs 属性,并且还设置了 bootargs 属性值。

3.3.3. memory node

memory node是以0x80000000为起始地址,0x20000000 size的512MB的空间。

一般而言,在.dts中不对memory进行描述,而是通过bootargs中类似521M@0x80000000的方式传递给内核。

memory {
	reg = <0x80000000 0x20000000>;
};

3.4. 标准属性

节点是由属性组成,节点是具体的设备,不同的设备需要的属性不同。Linux 下很多外设驱动都会使用标准属性,下面讲解一些常用的标准属性。

3.4.1. compatible 属性

compatible 属性用于将设备和驱动绑定起来。字符串列表用于选择设备所要使用的驱动程序,compatible 属性的值格式如下所示:

"manufacturer,model"		// "厂商,驱动名"
compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";

例,“fsl”:表示厂商飞思卡尔;“imx6ul-evk-wm8960”和“imx-audio-wm8960”表示驱动模块名字。

  • 设备绑定驱动

    驱动程序文件会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,若设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。比如在文件 imx-wm8960.c 中有如下内容:

    /* imx_wm8960_dt_ids imx-wm8960.c 驱动的匹配表,
     * 此匹配表中的compatible属性与设备树中匹配就会绑定此驱动文件 */
    static const struct of_device_id imx_wm8960_dt_ids[] = {
    	{ .compatible = "fsl,imx-audio-wm8960", },
    	{ /* sentinel */ }
    };
    MODULE_DEVICE_TABLE(of, imx_wm8960_dt_ids);
    
    static struct platform_driver imx_wm8960_driver = {
    	.driver = {
    		.name = "imx-wm8960",
    		.pm = &snd_soc_pm_ops,
    		.of_match_table = imx_wm8960_dt_ids,
    	},
    	.probe = imx_wm8960_probe,
    	.remove = imx_wm8960_remove,
    };
    
3.4.2. model 属性

model 属性值是一个字符串,一般 model 属性描述设备模块信息,比如名字:

model = "wm8960-audio";
3.4.3. staus 属性

设备状态,属性值是字符串,字符串是设备的状态信息,可选的状态如下表所示:

描述
“okay”设备是可操作的
“disabled”设备当前不可操作,但在未来可以变为可操作的,比如热插拔设备插入以后。
“fail”表明设备不可操作,设备检测到了一系列的错误
“fail-sss”含义和“fail”相同,后面的 sss 部分是检测到的错误内容
3.4.4. #address-cells 、#size-cells 和 reg 属性

#address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位)。

#size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。

reg =< address,length >,一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息。

#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值:起始地址和地址长度,reg 属性的格式为:

reg = <address1 length1 address2 length2 address3 length3……>
aips2: aips-bus@02100000 {
			compatible = "fsl,aips-bus", "simple-bus";
			#address-cells = <1>;	/* 说明reg属性起始地址所占字长为1 */
			#size-cells = <1>;		/* reg属性地址长度所占字长为1 */
			reg = <0x02100000 0x100000>;	/* 起始地址为0x02100000,地址长度为0x100000 */
			ranges;

			usdhc1: usdhc@02190000 {
				compatible = "fsl,imx6ull-usdhc", "fsl,imx6sx-usdhc";
				reg = <0x02190000 0x4000>;	/* 起始地址为0x02100000,地址长度为0x4000 */
				......
                ......
				status = "disabled";
			};
3.4.5. rangs 属性

ranges 属性值可以为空或者按照(child-bus-address,parent-bus-address,length)格式编写的数字
矩阵,ranges 是一个地址映射/转换表,ranges 属性每个项目由子地址、父地址和地址空间长度
三部分组成:

  • child-bus-address:子总线地址空间的物理地址,由父节点的#address-cells 确定此物理地址所占字长
  • parent-bus-address:父总线地址空间的物理地址,由父节点的#address-cells 确定此物理地址所占字长
  • length:子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长

注:如果rangs属性值为空。说明子空间和父空间完全相同,不需要进行地址转换。

如下为rangs为空的代码示例:

soc {
	#address-cells = <1>;
	#size-cells = <1>;
	compatible = "simple-bus";
	interrupt-parent = <&gpc>;
	ranges;
	.....
	}

如下为rangs不为空的代码示例:

soc {
	compatible = "simple-bus";
	#address-cells = <1>;
	#size-cells = <1>;
	ranges = <0x0 0xe0000000 0x00100000>;
    /* 指定了一个 1024KB(0x00100000)的地址范围,子地址空间的物理起始地址为 0x0,父地址空间的物理起始地址为 0xe0000000*/

	serial {
		device_type = "serial";
		compatible = "ns16550";
		reg = <0x4600 0x100>;
        /* serial 是串口设备节点
         * reg 属性定义了 serial 设备寄存器的起始地址为 0x4600,寄存器长度为 0x100。
         * 经过地址转换,serial 设备可以从 0xe0004600 开始进行读写操作,				  
           0xe0004600=0x4600+0xe0000000 */
		clock-frequency = <0>;
		interrupts = <0xA 0x8>;
		interrupt-parent = <&ipic>;
	};
};
3.4.6. device_type 属性

device_type 属性值为字符串,IEEE 1275 会用到此属性,用于描述设备的 FCode,但是设备树没有 FCode,所以此属性被弃用了。此属性只能用于 cpu 节点或者 memory 节点。imx6ull.dtsi 的 cpu0 节点用到了此属性,内容如下所示:

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

4. Linux内核匹配设备树

4.1.根节点 compatible 属性

每个节点都有自己的compatible属性,根节点也有。

例如,imx6ull-alientek-emmc.dts 文件中根节点的 compatible 属性内容如下所示:

/ {
	model = "Freescale i.MX6 ULL 14x14 EVK Board";
	compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
	......	
}

根节点的 compatible 属性可以知道我们所使用的设备,第一个值描述了所使用的硬件设备名字,比如这里使用的是“imx6ull-14x14-evk”这个设备,第二个值描述设备所使用的 SOC,比如这里使用的是“imx6ull”这颗 SOC。

Linux 内核会通过根节点的 compoatible 属性查看是否支持此设备,支持的话设备就会启动 Linux 内核。

4.2. 使用设备树的匹配方法

Linux 内核引入设备树之后使用DT_MACHINE_START描述设备。

DT_MACHINE_START 宏定义在文件 arch/arm/include/asm/mach/arch.h里面,如下:

#define DT_MACHINE_START(_name, _namestr)			 \
static const struct machine_desc __mach_desc_##_name \
__used												 \
__attribute__((__section__(".arch.info.init"))) = {  \
.nr = ~0,											 \
.name = _namestr,

DT_MACHINE_START 函数在 arch/arm/mach-imx/mach-imx6ul.c,有如下所示内容:

static const char *imx6ul_dt_compat[] __initconst = {
	"fsl,imx6ul",
	"fsl,imx6ull",
	NULL,
};

DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)")
	.map_io		 = imx6ul_map_io,
	.init_irq	 = imx6ul_init_irq,
	.init_machine	= imx6ul_init_machine,
	.init_late = imx6ul_init_late,
	.dt_compat = imx6ul_dt_compat,
MACHINE_END

结构体中有个.dt_compat 成员变量,此成员变量保存着本设备兼容属性

如上所示 .dt_compat = imx6ul_dt_compat,imx6ul_dt_compat 表里面有"fsl,imx6ul"和 “fsl,imx6ull” 这 两 个 兼 容 值。 只 要 某 个 设备 ( 板子 ) 根 节 点 “ / ” 的 compatible 属性 值 与imx6ul_dt_compat 表中的任何一个值相等,那么就表示 Linux 内核支持此设备。

5. 创建小型模版设备树

通过上面对设备树的了解,这里以 I.MX6ULL 的 SOC 为例,编写一个小型设备树模版。

需要描述的内容如下:

  1. I.MX6ULL 这个 Cortex-A7 架构的 32 位 CPU。
  2. I.MX6ULL 内部 ocram,起始地址 0x00900000,大小为 128KB(0x20000)。
  3. I.MX6ULL 内部 aips1 域下的 ecspi1 外设控制器,寄存器起始地址为 0x02008000,大小为 0x4000。
  4. I.MX6ULL 内部 aips2 域下的 usbotg1 外设控制器,寄存器起始地址为 0x02184000,大小为 0x4000。
  5. I.MX6ULL 内部 aips3 域下的 rngb 外设控制器,寄存器起始地址为 0x02284000,大小为 0x4000。

首先搭建一个仅含有根节点的基础框架,然后逐步补充各个节点,创建 asu.dts 文件,如下:

/ {
	compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";
}

5.1. 添加 cpus 节点

I.MX6ULL 采用 Cortex-A7 架构,而且只有一个 CPU,因此只有一个cpu0 节点,完成以后如下所示:

/ {
	compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";
	cpus {
			#address-cells = <1>;
			#size-cells = <0>;

			//CPU0 节点
			cpu0: cpu@0 {
			compatible = "arm,cortex-a7";
			device_type = "cpu";
			reg = <0>;
		};
	};
}

5.2. 添加 soc 节点

像 uart,iic 控制器等等这些都属于 SOC 内部外设,因此一般会创建一个叫做 soc 的父节点来管理这些 SOC 内部外设的子节点,添加 soc 节点以后的 myfirst.dts 文件内容如下所示:

/ {
	compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";

	cpus {
		......
	};
    
	//soc 节点
	soc {
        /* reg 属性中起始地占用一个字长,地址空间长度也占用一个字长 */
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "simple-bus";
		ranges;		/* 子空间和父空间地址范围相同 */
	}
}

5.3. 添加 ocram 节点

ocram 是 I.MX6ULL 内部 RAM,因此 ocram 节点应该是 soc 节点的子节点。ocram 起始地址为 0x00900000,大小为 128KB(0x20000),如下所示:

/ {
	compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";

	cpus {
		......
	};
    
	//soc 节点
	soc {
        /* reg 属性中起始地占用一个字长,地址空间长度也占用一个字长 */
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "simple-bus";
		ranges;		/* 子空间和父空间地址范围相同 */
		
		//ocram 节点
		ocram: sram@00900000 {
		compatible = "fsl,lpm-sram";
		reg = <0x00900000 0x20000>;
		};
	}
}

5.4. 添加 aips1、aips2 和 aips3 子节点

I.MX6ULL 内部分三个域:aips13,三个域分管不同外设控制器,aips13 这三个域对应的内存范围如表 所示:

起始地址大小(16进制)
AIPS10X020000000X100000
AIPS20X021000000X100000
AIPS30X022000000X100000
/ {
	compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";

	cpus {
		......
	};
    
	//soc 节点
	soc {
        /* reg 属性中起始地占用一个字长,地址空间长度也占用一个字长 */
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "simple-bus";
		ranges;		/* 子空间和父空间地址范围相同 */
		
		//ocram 节点
		ocram: sram@00900000 {
		compatible = "fsl,lpm-sram";
		reg = <0x00900000 0x20000>;
		};
    
    	//aips1 节点
		aips1: aips-bus@02000000 {
			compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02000000 0x100000>;
            ranges;
        }
            
        //aips2 节点
        aips2: aips-bus@02100000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02100000 0x100000>;
            ranges;
    	};

        //aips3 节点
        aips3: aips-bus@02200000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02200000 0x100000>;
            ranges;
        };
    }
}

5.5. 添加 ecspi1、usbotg1 和 rngb 外设控制器节点

最后加入 ecspi1,usbotg1 和 rngb 这三个外设控制器对应的节点,其中 ecspi1 属于 aips1 的子节点,usbotg1 属于 aips2 的子节点,rngb 属于 aips3 的子节点。最终的 asu.dts 文件内容如下:

/ {
	compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";

	cpus {
		#address-cells = <1>;
		#size-cells = <0>;

		//CPU0 节点
		cpu0: cpu@0 {
			compatible = "arm,cortex-a7";
			device_type = "cpu";
			reg = <0>;
		};
    };
    
	//soc 节点
	soc {
        /* reg 属性中起始地占用一个字长,地址空间长度也占用一个字长 */
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "simple-bus";
		ranges;		/* 子空间和父空间地址范围相同 */
		
		//ocram 节点
		ocram: sram@00900000 {
		compatible = "fsl,lpm-sram";
		reg = <0x00900000 0x20000>;
		};
    
    	//aips1 节点
		aips1: aips-bus@02000000 {
			compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02000000 0x100000>;
            ranges;
            
            //ecspi1 节点
			ecspi1: ecspi@02008000 {
				#address-cells = <1>;
				#size-cells = <0>;
				compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";
				reg = <0x02008000 0x4000>;
				status = "disabled";
			};
        }
            
        //aips2 节点
        aips2: aips-bus@02100000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02100000 0x100000>;
            ranges;
            
            //usbotg1 节点
			usbotg1: usb@02184000 {
				compatible = "fsl,imx6ul-usb", "fsl,imx27-usb";
				reg = <0x02184000 0x4000>;
				status = "disabled";
    		};
        }
        
        //aips3 节点
        aips3: aips-bus@02200000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02200000 0x100000>;
            ranges;
            
            //rngb 节点
			rngb: rngb@02284000 {
				compatible = "fsl,imx6sl-rng", "fsl,imx-rng", "imx-rng";
				reg = <0x02284000 0x4000>;
			};
        }
    }
}

到这里 asu.dts 这个小型设备树就编写好了,和 imx6ull.dtsi 类似。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值