Linux Device Tree

Linux Device Tree,第1张

Linux Device Tree Linux设备树的起源

arch/arm/plat-xxx和arch/arm/mach-xxx中存在大量的板级信息,注册platform_device,绑定resource等,随着时间的推移,越来越多的板级信息加入,影响维护,这些具体的硬件信息应该和内核代码解耦。有了Device Tree后,大量的板级信息不再需要,都可以通过Device Tree api来做处理。Device Tree相当于一个硬件配置文件,kernel读取这个配置文件做对应的驱动初始化相关工作

DTS (device tree source)

内核目录

arch/arm/boot/dts/
arch/arm64/boot/dts/

.dts文件是Device Tree源文件,相当于配置文件,一个.dts文件对应一个具体的板级信息,公用的一部分提炼为.dtsi, 类似于C语言的头文件.

/dts-v1/;
#include "rk3328.dtsi"

DTC (device tree compiler)

将.dts编译为.dtb的工具.
.dtb是.dts被DTC编译后的二进制格式的Device Tree描述,可由uboot和Linux内核解析。

Device Tree组成和结构

Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。

  • Node节点。在DTS中使用一对花括号”node-name{}”来定义;
  • Property属性。在Node中使用”property-name=value”字符串来定义;
Property 常见值类型:
int
u32
u64
string
phandle(int)

compatible

“compatible”属性用来device和driver的适配,
推荐的格式为”manufacturer,model”,
fsl,mpc8641为特指的设备, ns16550类型更广泛

compatible = "fsl,mpc8641", "ns16550"; 

phandle

“phandle”属性通用一个唯一的id来标识一个Node,在property可以使用这个id来引用Node

pic@10000000 { 
    // 将处理值定义为 1
    phandle = <1>; 
    interrupt-controller; 
};
another-device-node { 
    // 引用phandle值为1的pic节点
    interrupt-parent = <1>;
};

定义一个“label:”来引用Node,在编译是系统会自动为node生成一个phandle属性。”backlight”是一个label,用来引用node”backlight”:

backlight: backlight {
	compatible = "pwm-backlight";
	enable-gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>;
	pwms = <&pwm0 0 25000 0>;
 }

使用”&”来引用“label”,即是引用phandle

edp-panel {
	compatible = "boe,nv101wxmn51", "simple-panel";
	backlight = <&backlight>;
	power-supply = <&pp3300_disp>;
}

#address-cells 、 #size-cells

“#address-cells, #size-cells”属性用来定义当前node的子node中”reg”属性的解析格式。

  • address-cells, 用几个数描述地址
  • size-cells, 用几个数描述地址长度
soc {
	// 1个值表示地址
	#address-cells = <1>;
	// 1个值表示长度
	#size-cells = <1>;
	serial {
		compatible = "ns16550";
		reg = <0x4600 0x100>;
		clock-frequency = <0>;
		interrupts = <0xA 0x8>;
		interrupt-parent = <&ipic>;
	};
};

reg

“reg”属性解析出”address,length”数字,解析格式依据父节点的”#address-cells、#size-cells”定义

soc {
	// 1个值表示地址
	#address-cells = <1>;
	// 1个值表示长度
	#size-cells = <1>;
	serial {
		compatible = "ns16550";
		reg = <0x4600 0x100>;
		clock-frequency = <0>;
		interrupts = <0xA 0x8>;
		interrupt-parent = <&ipic>;
	};
};

0x4600表示对应的基地址,0x100表示地址对应的大小为0x100

i2c@1,0 {
	compatible = "acme,a1234-i2c-bus";
	#address-cells = <1>;
	#size-cells = <0>;
	rtc@58 {
		compatible = "maxim,ds1338";
		reg = <58>;
	};
};

address-cells = <1>;size-cells = <0>;58表示i2c对应从设备地址,映射长度为0

aliases 节点

节点的别名

aliases {
	ethernet0 = &gmac;
	i2c0 = &i2c0;
	serial0 = &uart0;
	spi0 = &spi0;
};

memory 节点

用来传递内存布局

 memory {
	 device_type = "memory";
	 reg = <0x0 0x0 0x0 0x40000000>;
};


chosen 节点
  • “bootargs”属性用来传递cmdline参数
  • “stdout-path”属性用来指定标准输出设备
  • “stdin-path”属性用来指定标准输入设备
chosen { 
	bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"; 
};

常用OF API

判断设备结点的compatible属性是否包含compat指定的字符串

int of_device_is_compatible(const struct device_node *device,const char *compat);

根据compatible属性,获得设备结点。遍历Device Tree中所有的设备结点,看看哪个结点的类型、compatible属性与本函数的输入参数匹配,大多数情况下,from、type为NULL。

struct device_node *of_find_compatible_node(struct device_node *from,
    const char *type, const char *compatible);

读取设备结点np的属性名为propname,类型为8、16、32、64位整型数组的属性

int of_property_read_u8_array(const struct device_node *np,
    const char *propname, u8 *out_values, size_t sz);

int of_property_read_u16_array(const struct device_node *np, 
    const char *propname, u16 *out_values, size_t sz);

int of_property_read_u32_array(const struct device_node *np,
    const char *propname, u32 *out_values, size_t sz);

int of_property_read_u64(const struct device_node *np,
    const char *propname, u64 *out_value);

读取字符串属性

int of_property_read_string(struct device_node *np, const char *propname,
    const char **out_string);

读取字符串数组属性中的第index个字符串

int of_property_read_string_index(struct device_node *np,
    const char *propname, int index, const char **output);

如果设备结点np含有propname属性,则返回true,否则返回false。一般用于检查空属性是否存在

static inline bool of_property_read_bool(const struct device_node *np,
    const char *propname);

博客推荐

http://kernel.meizu.com/device-tree.html
https://blog.csdn.net/21cnbao/article/details/8457546
https://elinux.org/Device_Tree_Usage

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5693943.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存