二十、设备树

前言

前面我们使用struct resource结构体来描述硬件资源,这是以前ARM Linux社区没有引入设备树时的做法,这种方法会在Linux内核源码里面引入大量的板级文件,使得内核源码臃肿。为了改变这种情况,ARM Linux社区后来引入设备树,使用设备树来描述板级硬件资源。

相关概念

设备树源文件为.dts(文本文件),经过设备树编译程序dtc编译后得到设备树文件.dtb(二进制文件)。设备树文件用于描述一个板子上的硬件资源(包括SOC以及外设等),所以一块板子对应着一个设备树文件。对于可复用的公共部分(比如SOC),可以将其设备树信息提取出来形成一个.dtsi(类似于C语言中的头文件),这样其它的.dts就可以直接使用#include对其进行包含。

设备树知识点

  1. 设备树从根节点/开始写,每个节点的格式如下:
    label:name@address {

    };

  2. 节点中可以包含属性和子节点,类似树形结构

  3. 如果想引用某个节点,可以使用&label

  4. 设备树里面相同的节点会自动合并

  5. 系统启动的时候,会去解析设备树,然后可在/proc/device-tree目录下查看设备树信息

一些常用属性

compatible: 兼容属性。设备节点下的compatible用于匹配驱动,根节点下的compatible用于查询内核是否支持此CPU。
#address-cells: 子节点中reg属性中地址的字长
#size-cells: 子节点中reg属性中大小的字长
reg: 用于描述地址空间
ranges:父地址空间映射到子地址空间(比如PCI),空间地址和大小的字长也遵循#address-cellssize-cells的规则;如果值为空,则不进行地址映射。

绑定文档

绑定文档可以提供设备树属性描述参考,位于Linux内核源码中Documentations/devicetree/bindings目录中。

设备树相关操作函数(OF操作函数)

OF函数是指Linux内核中一系列以of_开头的函数,可以用于从设备树中获取信息用于写驱动,它们的声明位于include/linux/of.h中。

  1. 查找设备节点常用函数
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);
  1. 提取属性的常用函数
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);
相关推荐
j_xxx404_1 小时前
Linux:静态链接与动态链接深度解析
linux·运维·服务器·c++·人工智能
_只道当时是寻常2 小时前
【Codex】Ubuntu 安装 Codex CLI 并解决 Clash 代理与账号认证问题
linux·ubuntu·chatgpt
brucelee1863 小时前
Claude Code 安装教程(Windows / Linux / macOS)
linux·windows·macos
jsons13 小时前
给每台虚拟机设置独立控制台密码
linux·运维·服务器
嵌入式×边缘AI:打怪升级日志3 小时前
全志T113 Tina-SDK 配套工具链开发应用(从Makefile到CMake再到Autotools)
linux
嵌入式×边缘AI:打怪升级日志3 小时前
全志T113嵌入式Linux开发环境搭建(VMware + Ubuntu 18.04)详细步骤
linux·ubuntu
云栖梦泽4 小时前
Linux内核与驱动:14.SPI子系统
linux·运维·服务器·c++
yipiantian5 小时前
在Claude项目中实现跨目录访问Skills
linux·运维·服务器
cen__y5 小时前
Linux07(信号01)
linux·运维·服务器·c语言·开发语言
MT5开发5 小时前
Linux安装MariaDB
linux·运维·mariadb