设备树基础

DTB DTS DTC

DTB:编译的最终设备树文件

DTS:设备树描述文件,类似于C源码

DTC:设备树的编译器,类似于GCC

DTSI: 设备树的头文件,类似于.H头文件

设备树编写文档推荐:

《Devicetree SpecificationV0.2.pdf》

《Power_ePAPR_APPROVED_v1.12.pdf》

正常情况不需要开发人员从零开始写一个设备树文件,大多数都是在处理器厂商提供的信息上进行增删即可,因此这方面不需要特地学习的非常精通

DTS语法规则

  • 文件包含

image-20250309212811979

  • 节点命名格式为node-name@unit-address,unit-address可以省略

  • 节点标签,label: node-name@unit-address

  • DTS的信息以键值对的新式组织,值分为以下几类

    • 字符串、字符串列表

      image-20250309213218618

      image-20250309213519974

    • 32 位无符号整数、整数列表

      image-20250309213417880

      image-20250309213459954

标准属性

  • compatible属性,描述设备的匹配信息

    image-20250309213519974

  • model属性,描述设备模块信息,比如名称

image-20250309214122712

  • status属性
描述
okay 表明设备是可操作的。
disabled 表明设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备插入以后。至于 disabled 的具体含义还要看设备的绑定文档。
fail 表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作。
fail-sss 含义和“fail”相同,后面的 sss 部分是检测到的错误内容。
  • #address-cells 和#size-cells属性,#address-cells用于描述reg子节点的“地址”的长度(32位),#size-cells用于描述reg子节点中“长度”的长度;

image-20250309214915150

  • reg属性,描述地址信息,数据形式为整数列表,一般是(address,length)对

  • ranges 属性,属性值可以为空(子地址空间和父地址空间完全相同)或者按照(child-bus-address,parent-bus-address,length)格式编写的数字列表,其中长度同样由**#address-cells 和#size-cells属性**决定

    image-20250309215401882

    image-20250309215709974

  • name 属性(已弃用),用于记录节点名字

  • device_type 属性,用于记录节点FCode,只能用于 cpu 节点或者 memory 节点

向节点追加或修改内容

  • 直接在特定节点中添加/修改新的子节点
  • 使用&引用特定节点进行追加/修改

image-20250309220902267

将节点信息记录到设备树中

  • 原理很简单,本质就是抽取驱动中的关键信息,放在设备树中,驱动利用特定的函数访问设备树中的地址信息,从而达到驱动代码的复用

  • 可在/proc/device_tree 中观察驱动中的信息

  • 特殊节点 aliases 子节点,定义别名

  • chosen 子节点,主要是为了 uboot 向 Linux 内核传递数据(uboot do_bootz调用函数 fdt_chosen 向 chosen 节点添加 bootargs 属性)

image-20250309221931301

  • Linux 源码目录/Documentation/devicetree/bindings中查询绑定信息的文档

常用of函数获取dts中的信息

只列举常用的,全部的在of.h头文件中,使用方法不难,类似于cJson库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct device_node* of_find_node_by_name(struct device_node *from
const char *name)

inline struct device_node *of_find_node_by_path(const char *path)

static inline struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)

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

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

of_iomap 函数

功能类似于ioremap函数,但是兼容了设备树,可直接通过设备树节点访问其出错的地址信息,并进行一次内存映射

1
2
3
# linux/of_address.h
void __iomem *of_iomap(struct device_node *device, int index);