设备树

一、什么是设备树

  1. uboot启动内核用到zImage,imx6ull-alientek-emmc.dtb。bootz 80800000 – 83000000.
  2. 设备树:设备和树。Device Tree
  3. 在单片机驱动里面比如W25QXX,SPI,速度都是在.c文件里面写死。板级信息都写到.c里面,导致linux内核臃肿。因此 将板子信息做成独立的格式,文件扩展名为.dts。一个平台或者机器对应一个.dts。

使用设备树的特点在于,在设备树dts文件指定硬件资源,dts被编译为dtb文件, 在启动单板时,U-boot会将dtb文件传给内核,使得驱动程序与硬件分离,我们只需要修改dts文件,便能实现需求。这就是设备树易于扩展的特点. 硬件有变动时不需要重新编译内核或驱动程序,只需要提供不一样的dtb文件

二、DTS、DTB和DTC的关系

DTS 就是Device Tree Source,是一个文本形式的文件,用于描述硬件信息,文件后缀名 .dst,一般在如下路径

/arch/arm/boot/dts

.dts相当于.c,,就是DTS源码文件。
DTC工具相当于gcc编译器,将.dts编译成.dtb
.dtb相当于bin文件,或可执行文件。

通过make dtbs编译所有的dts文件。如果要编译指定的dtbs

make imx6ull-alientek-emmc.dtb

三、DTS基本语法

  1. 设备树也有头文件,扩展名为.dtsi。可以将一款SOC他的其他所有设备/平台的共有的信息提出来,作为一个通用的.dtsi文件。

  2. DTS也是/开始,根节点

  3. 从/根节点开始描述设备信息

  4. 在/根节点外有一些&cpu0这样的语句是追加

  5. 节点名字,完整的要求,参见Power_ePAPR_APPROVED_v1.12.pdf2.2.1小节

	node-name@unit-address

unit-address一般都是外设寄存器的起始地址,有时候是I2C的设备地址,或者其他含义,具体节点具体分析。设备树里面常常遇到如下所示节点名字:

intc: interrupt-controller@00a01000

:前面是标签label,后面才是名字。intc,完整的名字是interrupt-controller@00a01000。&intc
lable的目的是方便访问节点,感觉就是名字的简化。

四、创建小型的设备树模板

设备树例子:

/dts-v1/;
#include .h
#include .dtsi

/{
	/*不同的/根节点内容会合并更新*/
	/*skeletondtsi文件*/
	#address-cells = <1>;
	#size-cells = <1>;
	chosen { stdout-path = &uart1;};
	aliases { 
		can0 = &flexcan1;
		。。。
	};
	memory { 
		device_type = "memory";
		reg = <0x80000000 0x20000000>; 
	};

	/*imx6ull-aliente-emmc.dts中文件*/
	model = "Freescale i.MX6 ULL 14x14 EVK Board";
	compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
	
	chosen {
	};
	memory {
	};
	reserved-memory {
	};
	...
};
&cpu0{

}

五、设备树在系统中的体现

系统启动以后可以在根文件系统里面看到设备树的节点信息。在/proc/device-tree/目录下存放着设备树信息。
内核启动的时候会解析设备树,然后在/proc/device-tree/目录下呈现出来。

六、特殊节点

  1. aliases (翻译:别名)
    主要功能就是定义别名,定义别名的目的就是为了方便访问节点,不过一般用label访问
  2. chosen节点,主要目的就是将uboot里面bootargs环境变量值,传递给Linux内核作为命令行参数。cmdline;uboot里面bootargs值为:
bootargs=console=ttymxc0,115200 rw root=/dev/nfs nfsroot=192.168.1.249:/home/zzk/linux/nfs/rootfs ip=192.168.1.50:192.168.1.249:192.168.1.1:255.255.255.0::eth0:off

linux内核cmdline值为:

Kernel command line: console=ttymxc0,115200 rw root=/dev/nfs nfsroot=192.168.1.249:/home/zzk/linux/nfs/rootfs ip=192.168.1.50:192.168.1.249:192.168.1.1:255.255.255.0::eth0:off

uboot是如何向kernel传递bootargs?
经过查看发现chosen节点中包含bootargs属性,属性值和uboot的bootargs一致。

uboot接触过dtb,最终通过bootz 80800000 – 83000000 来启动内核。经过分析判断uboot拥有bootargs环境变量和dtb,因此最有可能“作案”。
最终发现在uboot的fdt_chosen函数中会查找chosen节点,并且在里面添加bootargs属性,属性值为bootargs变量值。

七、特殊的属性

  1. compatible属性,值是字符串。很重要
    设备节点下的compatible用来匹配Linux内核中的驱动程序
    根节点/下面的compatible,内核启动的时候会检查是否支持此平台

不使用设备树的时候通过machine id来判断内核是否支持此机器。

#define MACHINE_START(_type,_name)			\
static const struct machine_desc __mach_desc_##_type	\
 __used							\
 __attribute__((__section__(".arch.info.init"))) = {	\
	.nr		= MACH_TYPE_##_type,		\
	.name		= _name,

#define MACHINE_END				\
};

MACHINE_START(MX35_3DS, "Freescale MX35PDK")
	/* Maintainer: Freescale Semiconductor, Inc */
	.atag_offset = 0x100,
	.map_io = mx35_map_io,
	.init_early = imx35_init_early,
	.init_irq = mx35_init_irq,
	.init_time	= mx35pdk_timer_init,
	.init_machine = mx35_3ds_init,
	.reserve = mx35_3ds_reserve,
	.restart	= mxc_restart,
MACHINE_END

展开以后:

static const struct machine_desc __mach_desc_MX35_3DS __used						
 __attribute__((__section__(".arch.info.init"))) = {	
	.nr		= MACH_TYPE_MX35_3DS,			//机器ID	
	.name		= "Freescale MX35PDK",
	.atag_offset = 0x100,
	.map_io = mx35_map_io,
	.init_early = imx35_init_early,
	.init_irq = mx35_init_irq,
	.init_time	= mx35pdk_timer_init,
	.init_machine = mx35_3ds_init,
	.reserve = mx35_3ds_reserve,
	.restart	= mxc_restart,
};

使用设备树的时候不使用机器ID,而是使用根节点/下的compatible。

#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(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

展开以后就是:

static const struct machine_desc __mach_desc_IMX6UL __used					
 __attribute__((__section__(".arch.info.init"))) = {	
	.nr		= ~0,				
	.name		= "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,
};
  1. model 描述设备模块信息
  2. status 设备属性,表示设备状态
  3. #address-cells和#size-cells属性
    #address-cells 属性值决定了子节点 reg 属
    性中地址信息所占用的字长(32 位),#size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)

八、Linux内核的OF操作函数

  1. 驱动如何获取到设备树中节点信息。在驱动中使用OF函数获取设备树属性内容。
  2. 驱动要想获取到设备树节点内容,首先要找到节点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值