前言
前面我们使用struct resource结构体来描述硬件资源,这是以前ARM Linux社区没有引入设备树时的做法,这种方法会在Linux内核源码里面引入大量的板级文件,使得内核源码臃肿。为了改变这种情况,ARM Linux社区后来引入设备树,使用设备树来描述板级硬件资源。
相关概念
设备树源文件为.dts(文本文件),经过设备树编译程序dtc编译后得到设备树文件.dtb(二进制文件)。设备树文件用于描述一个板子上的硬件资源(包括SOC以及外设等),所以一块板子对应着一个设备树文件。对于可复用的公共部分(比如SOC),可以将其设备树信息提取出来形成一个.dtsi(类似于C语言中的头文件),这样其它的.dts就可以直接使用#include对其进行包含。
设备树知识点
-
设备树从根节点
/开始写,每个节点的格式如下:
label:name@address{};
-
节点中可以包含属性和子节点,类似树形结构
-
如果想引用某个节点,可以使用
&label -
设备树里面相同的节点会自动合并
-
系统启动的时候,会去解析设备树,然后可在
/proc/device-tree目录下查看设备树信息
一些常用属性
compatible: 兼容属性。设备节点下的compatible用于匹配驱动,根节点下的compatible用于查询内核是否支持此CPU。
#address-cells: 子节点中reg属性中地址的字长
#size-cells: 子节点中reg属性中大小的字长
reg: 用于描述地址空间
ranges:父地址空间映射到子地址空间(比如PCI),空间地址和大小的字长也遵循#address-cells和size-cells的规则;如果值为空,则不进行地址映射。
绑定文档
绑定文档可以提供设备树属性描述参考,位于Linux内核源码中Documentations/devicetree/bindings目录中。
设备树相关操作函数(OF操作函数)
OF函数是指Linux内核中一系列以of_开头的函数,可以用于从设备树中获取信息用于写驱动,它们的声明位于include/linux/of.h中。
- 查找设备节点常用函数
c
//使用name属性查找
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
// 使用compatible属性查找
struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compat);
// 使用路径查找
struct device_node *of_find_node_by_path(const char *path);
// 查找父节点和子节点
struct device_node *of_get_parent(const struct device_node *node);
struct device_node *of_get_next_parent(struct device_node *node);
struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev);
- 提取属性的常用函数
c
// 获取给定节点的给定属性
struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp);
// 获取给定节点的给定属性的元素数量(比如数组中元素的个数)
int of_property_count_elems_of_size(const struct device_node *np,
const char *propname, int elem_size);
// 从u32数组中读取给定索引号元素的值
int of_property_read_u32_index(const struct device_node *np,
const char *propname,
u32 index, u32 *out_value);
// 读取整个数组
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_string(struct device_node *np,
const char *propname,
const char **out_string);
这里再补充一个跟内存映射相关的OF函数,其定义位于include/linux/of_address.h中:
c
// 从reg属性中获取寄存器地址并映射为虚拟地址
void __iomem *of_iomap(struct device_node *np, int index);