个人笔记向
设备树(Device Tree)是一种描述硬件设备信息和配置的数据结构,通常用于嵌入式系统中,特别是用于描述复杂的硬件平台结构,如ARM架构的系统。设备树将硬件描述从操作系统内核中分离出来,使得内核可以更容易地适配不同的硬件平台
设备树由节点(node)和属性(property)组成,它们之间以层次结构进行组织。每个节点代表一个硬件设备或者一个设备集合,而每个属性描述了该节点的特定信息
例如,一个简化的设备树可能包含如下结构:
/ {
compatible = "manufacturer,model";
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0x0>;
clocks = <&clk_controller 0>;
interrupt-parent = <&intc>;
interrupts = <0 1>;
};
memory {
device_type = "memory";
reg = <0x40000000 0x10000000>;
};
uart@40001000 {
compatible = "vendor,uart";
reg = <0x40001000 0x100>;
interrupts = <0 2>;
};
};
- 根节点
/
包含了整个系统的描述信息。 cpu@0
节点描述了一个CPU设备,其中包含了处理器的类型、寄存器地址、时钟信息和中断信息等。memory
节点描述了系统的内存,其中包含了内存的地址范围。uart@40001000
节点描述了一个UART串口设备,其中包含了串口的寄存器地址和中断信息等。
设备树的编译和加载
设备树通常以 .dts
(设备树源文件)或 .dtb
(设备树二进制文件)的形式存在。在Linux内核启动时,Bootloader负责加载设备树二进制文件到内存中,然后将设备树传递给内核。内核根据设备树的信息进行硬件初始化和配置。
总的来说,设备树为嵌入式系统提供了一种灵活、可扩展的硬件描述和配置方式,使得系统可以轻松适应不同的硬件平台和设备组合。
读取设备树上的信息使用 of 函数
设备树描述了设备的详细信息,这些信息包括数字类型的、字符串类型的、数组类型的,
我们在编写驱动的时候需要获取到这些信息。比如设备树使用 reg 属性描述了某个外设的寄存
器地址为 0X02005482,长度为 0X400,我们在编写驱动的时候需要获取到 reg 属性的
0X02005482 和 0X400 这两个值,然后初始化外设。Linux 内核给我们提供了一系列的函数来获
取设备树中的节点或者属性信息,这一系列的函数都有一个统一的前缀“of_”,所以在很多资
料里面也被叫做 OF 函数。
1. of_find_node_by_name
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
函数参数和返回值含义如下:
from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
name:要查找的节点名字。
返回值:找到的节点,如果为 NULL 表示查找失败。
2.of_find_node_by_type
of_find_node_by_type 函数通过 device_type 属性查找指定的节点,函数原型如下:
struct device_node *of_find_node_by_type(struct device_node *from, const char *type)
函数参数和返回值含义如下:
from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
type:要查找的节点对应的 type 字符串,也就是 device_type 属性值。
返回值:找到的节点,如果为 NULL 表示查找失败。
3.of_find_property 函数
of_find_property 函数用于查找指定的属性,函数原型如下:
property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)
函数参数和返回值含义如下:
np:设备节点。
name: 属性名字。
lenp:属性值的字节数
4.of_property_read_u32_index 函数
of_property_read_u32_index 函数用于从属性中获取指定标号的 u32 类型数据值(无符号 32
位),比如某个属性有多个 u32 类型的值,那么就可以使用此函数来获取指定标号的数据值,此
函数原型如下:
int of_property_read_u32_index(const struct device_node *np,
const char *propname,
u32 index,
u32 *out_value)
函数参数和返回值含义如下:
np:设备节点。
proname: 要读取的属性名字。
index:要读取的值标号。
out_value:读取到的值
返回值:0 读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有
要读取的数据,-EOVERFLOW 表示属性值列表太小。
5.of_property_read_u32_array u8/u16/u64
int of_property_read_u32_array(const struct device_node *np,
const char *propname,
u32 *out_values,
size_t sz)
函数参数和返回值含义如下:
np:设备节点。
proname: 要读取的属性名字。
out_value:读取到的数组值,分别为 u8、u16、u32 和 u64。
sz:要读取的数组元素数量。
返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没
有要读取的数据,-EOVERFLOW 表示属性值列表太小。
6.of_property_read_u32
int of_property_read_u32(const struct device_node *np,
const char *propname,
u32 *out_value)
函数参数和返回值含义如下:
np:设备节点。
proname: 要读取的属性名字。
out_value:读取到的数组值。
返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没
有要读取的数据,-EOVERFLOW 表示属性值列表太小。
7、of_property_read_string 函数
of_property_read_string 函数用于读取属性中字符串值,函数原型如下:
int of_property_read_string(struct device_node *np,
const char *propname,
const char **out_string)
函数参数和返回值含义如下:
np:设备节点。
proname: 要读取的属性名字。
out_string:读取到的字符串值。
返回值:0,读取成功,负值,读取失败。
8、of_n_addr_cells 函数
of_n_addr_cells 函数用于获取#address-cells 属性值,函数原型如下:
int of_n_addr_cells(struct device_node *np)
函数参数和返回值含义如下:
np:设备节点。
返回值:获取到的#address-cells 属性值。
9、of_n_size_cells 函数
of_size_cells 函数用于获取#size-cells 属性值,函数原型如下:
int of_n_size_cells(struct device_node *np)
函数参数和返回值含义如下:
np:设备节点。
返回值:获取到的#size-cells 属性值。
还有更多 of 函数就不一一列举了。