0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

简单地学习一下设备树的一些知识

倩倩 来源:一口Linux 作者:一口Linux 2022-09-09 15:29 次阅读

	

在platform_device部分有简单说明描述设备有两种方法:一种是使用platform_device结构体来指定;另一种是使用设备树来描述。

本篇笔记我们就来简单地学习一下设备树的一些知识。

什么是设备树

a676b120-2fcf-11ed-ba43-dac502259ad0.png

设备树简单理解就是描述设备信息(资源)的一棵树。设备树(Device Tree)用代码体现如下:

a682d180-2fcf-11ed-ba43-dac502259ad0.png

这些代码被保存在.dts/dtsi后缀文件中,也即设备树源文件 DTS(DeviceTree Source)。

这些源文件同我们的C代码一样,并不能直接使用的,而是得经过一个编译过程生成机器可运行的二进制文件,如:

a68f9168-2fcf-11ed-ba43-dac502259ad0.png

dts文件使用dtc工具编译生成dtb文件,这个dtb文件就是内核可以使用的文件。例如我们的板子跑起来之后,我们系统使用的设备树文件就存在目录/boot下:

a69b3b12-2fcf-11ed-ba43-dac502259ad0.png

Linux为什么会引入设备树?

在上一个实验:【Linux笔记】LED驱动实验(总线设备驱动模型)中我们使用了platform_device结构体来描述led设备(硬件资源)。既然已经有了描述设备的方法了,为什么还要引入设备树呢?

因为Linux内核中有很多BSP(板级支持包),不同的BSP会包含着不同的描述设备的代码(.c或.h文件)。

随着芯片的发展,Linux内核中就包含着越来越多这些描述设备的代码,导致Linux内核代码会很臃肿。

这导致Linux之父Linus 大发雷霆:"this whole ARM thing is a f*cking pain in the ass"。

因此引入了设备树文件,从而可精简一些臃肿的C代码。除此之外,.dts编译生成.dtb文件的过程要比.c编译生成驱动模块、加载驱动模块的过程要简单很多,也更方便我们进行开发。

设备树的语法

设备树源文件也是需要根据一定规则来编写的,同C语言一样,也要遵循一些语法规则。下面简单看一下设备树的源码结构及语法。

先看一个设备树示例:

a6b00128-2fcf-11ed-ba43-dac502259ad0.png

1、节点格式

label:node-name@unit-address

其中:

label:标号

node-name:节点名字

unit-address:单元地址

label 是标号,可以省略。label 的作用是为了方便地引用 node。比如:

a6bccfde-2fcf-11ed-ba43-dac502259ad0.png

可以使用下面 2 种方法来修改 uart@fe001000 这个 node:

a6cc16ce-2fcf-11ed-ba43-dac502259ad0.png

2、属性格式 简单地说, properties 就是“name=value”, value 有多种取值方式。示例:

  • 一个32位的数据,用尖括号包围起来,如

interrupts=<170xc>;

  • 一个64位数据(使用2个32位数据表示),用尖括号包围起来,如:

clock-frequency=<0x000000010x00000000>;

  • 有结束符的字符串,用双引号包围起来,如:

compatible="simple-bus";

  • 字节序列,用中括号包围起来,如:

local-mac-address=[000012345678];//每个byte使用2个16进制数来表示
local-mac-address=[000012345678];//每个byte使用2个16进制数来表示

  • 可以是各种值的组合,用逗号隔开,如:

compatible="ns16550","ns8250";
example=<0xf00f000019>,"astrangepropertyformat";

3、一些标准属性(1) compatible 属性

“compatible”表示“兼容”,对于某个LED,内核中可能有A、B、C三个驱动都支持它,那可以这样写:

led{
compatible=“A”,“B”,“C”;
};

内核启动时,就会为这个LED按这样的优先顺序为它找到驱动程序:A、B、C。

(2)model 属性

model属性与compatible属性有些类似,但是有差别。compatible属性是一个字符串列表,表示可以你的硬件兼容A、B、C等驱动;model用来准确地定义这个硬件是什么。

比如根节点中可以这样写:

/{
compatible="samsung,smdk2440","samsung,mini2440";
model="jz2440_v3";
};

它表示这个单板,可以兼容内核中的“smdk2440”,也兼容“mini2440”。

从compatible属性中可以知道它兼容哪些板,但是它到底是什么板?用model属性来明确。

(3)status 属性

status 属性看名字就知道是和设备状态有关的, status 属性值也是字符串,字符串是设备的状态信息,可选的状态如下所示:

a6d98a0c-2fcf-11ed-ba43-dac502259ad0.png

(4)#address-cells 和#size-cells 属性

格式:

address-cells:address要用多少个32位数来表示;
size-cells:size要用多少个32位数来表示。

比如一段内存,怎么描述它的起始地址和大小?

下例中,address-cells为1,所以reg中用1个数来表示地址,即用0x80000000来表示地址;size-cells为1,所以reg中用1个数来表示大小,即用0x20000000表示大小:

/{
#address-cells=<1>;
#size-cells=<1>;
memory{
reg=<0x800000000x20000000>;
};
};

(5)reg 属性

reg属性的值,是一系列的“address size”,用多少个32位的数来表示address和size,由其父节点的# address-cells、#size-cells决定。示例:

/dts-v1/;
/{
#address-cells=<1>;
#size-cells=<1>;
memory{
reg=<0x800000000x20000000>;
};
};

(7)name 属性

过时了,建议不用。它的值是字符串,用来表示节点的名字。在跟platform_driver匹配时,优先级最低。compatible属性在匹配过程中,优先级最高。

(8)device_type 属性

过时了,建议不用。它的值是字符串,用来表示节点的类型。在跟platform_driver匹配时,优先级为中。compatible属性在匹配过程中,优先级最高。

3、常用的节点(1)根节点

用 / 标识根节点,如:

/dts-v1/;
/{
model="SMDK24440";
compatible="samsung,smdk2440";

#address-cells=<1>;
#size-cells=<1>;
};

(2)CPU节点

一般不需要我们设置,在 dtsi 文件中都定义好了,如:

cpus{
#address-cells=<1>;
#size-cells=<0>;

cpu0:cpu@0{
.......
}
};

(3)memory 节点

芯片厂家不可能事先确定你的板子使用多大的内存,所以 memory 节点需要板厂设置,比如:

memory{
reg=<0x800000000x20000000>;
};

(4)chosen 节点

我们可以通过设备树文件给内核传入一些参数,这要在chosen节点中设置bootargs属性:

chosen{
bootargs="noinitrdroot=/dev/mtdblock4rwinit=/linuxrcconsole=ttySAC0,115200";
};

操作设备树的函数

Linux 内核给我们提供了一系列的函数来获取设备树中的节点或者属性信息,这一系列的函数都有一个统一的前缀“of_”(“open firmware”即开放固件。),所以在很多资料里面也被叫做 OF 函数。

1、节点相关操作函数 Linux 内核使用 device_node 结构体来描述一个节点,此结构体定义在文件 include/linux/of.h 中,定义如下:

a6f4f274-2fcf-11ed-ba43-dac502259ad0.png

与查找节点有关的 OF 函数有 5 个:

(1) of_find_node_by_name 函数

of_find_node_by_name 函数通过节点名字查找指定的节点,函数原型如下:

structdevice_node*of_find_node_by_name(structdevice_node*from,
constchar*name);

(2) of_find_node_by_type 函数

of_find_node_by_type 函数通过 device_type 属性查找指定的节点,函数原型如下:

structdevice_node*of_find_node_by_type(structdevice_node*from,constchar*type);

(3) of_find_compatible_node 函数

of_find_compatible_node 函数根据 device_type 和 compatible 这两个属性查找指定的节点,函数原型如下:

structdevice_node*of_find_compatible_node(structdevice_node*from,constchar*type,
constchar*compatible);

(4)of_find_matching_node_and_match 函数

of_find_matching_node_and_match 函数通过 of_device_id 匹配表来查找指定的节点,函数原型如下:

structdevice_node*of_find_matching_node_and_match(structdevice_node*from,conststructof_device_id*matches,conststructof_device_id**match);

(5)of_find_node_by_path 函数

of_find_node_by_path 函数通过路径来查找指定的节点,函数原型如下:

inlinestructdevice_node*of_find_node_by_path(constchar*path);

2、提取属性值的 OF 函数 Linux 内核中使用结构体 property 表示属性,此结构体同样定义在文件 include/linux/of.h 中,内容如下:

a7036b42-2fcf-11ed-ba43-dac502259ad0.png

Linux 内核也提供了提取属性值的 OF 函数 :(1) of_find_property 函数

of_find_property 函数用于查找指定的属性,函数原型如下:

property*of_find_property(conststructdevice_node*np,constchar*name,int*lenp);

(2)of_property_count_elems_of_size 函数

of_property_count_elems_of_size 函数用于获取属性中元素的数量,比如 reg 属性值是一个数组,那么使用此函数可以获取到这个数组的大小,此函数原型如下:

intof_property_count_elems_of_size(conststructdevice_node*np,constchar*propname,intelem_size);

(3)读取 u8、 u16、 u32 和 u64 类型的数组数据

a713b09c-2fcf-11ed-ba43-dac502259ad0.png

(4)读取 u8、 u16、 u32 和 u64 类型属性值

a735718c-2fcf-11ed-ba43-dac502259ad0.png

(5)of_property_read_string 函数

of_property_read_string 函数用于读取属性中字符串值,函数原型如下:

intof_property_read_string(structdevice_node*np,constchar*propname,constchar**out_string)

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11230

    浏览量

    208937
  • 代码
    +关注

    关注

    30

    文章

    4751

    浏览量

    68358
  • 设备树
    +关注

    关注

    0

    文章

    38

    浏览量

    3110

原文标题:整理了一份Linux设备树基础知识,建议收藏!

文章出处:【微信号:良许Linux,微信公众号:良许Linux】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    一些常见的动态电路

    无论是模电还是数电,理论知识相对来说还是比较枯燥,各种电路原理理解清楚不算容易,换种生动形象的方式或许会增加一些趣味性,也更容易理解这些知识。下面整理了
    的头像 发表于 11-16 09:26 199次阅读
    <b class='flag-5'>一些</b>常见的动态电路

    分享一些常见的电路

    理解模电和数电的电路原理对于初学者来说可能比较困难,但通过一些生动的教学方法和资源,可以有效地提高学习兴趣和理解能力。 下面整理了一些常见的电路,以动态图形的方式展示。 整流电路 单相桥式整流
    的头像 发表于 11-13 09:28 210次阅读
    分享<b class='flag-5'>一些</b>常见的电路

    如何学习ARM?

    ARM 处理器的程序。此外,还需要了解一些常用的开发工具和调试工具,如交叉编译器、调试器等。 4.实践项目: 在学习的过程中进行一些实践项目是很有帮助的。你可以尝试使用开发板或模拟器进行
    发表于 10-11 10:42

    有朋友愿意业余时间教我一下瑞萨编程吗?付费的

    本人要用到瑞萨单片机,但是引脚设置,编程等都不熟,如果有朋友帮助学习,愿意付费!就是一些简单的入门知识。谢了
    发表于 08-20 22:47

    如何成为名嵌入式C语言高手?

    相关教材、参加在线课程或者参考编程书籍来系统地学习C语言的基础知识,并通过编写简单的程序进行实践。 二、深入了解嵌入式系统的硬件架构和工作原理嵌入式系统通常包含微控制器或微处理器等硬件设备
    发表于 04-07 16:03

    细谈SolidWorks教育版的一些基础知识

    SolidWorks教育版是款广泛应用于工程设计和教育领域的三维建模软件。它具备直观易用的操作界面和强大的设计功能,为学生提供了学习和实践的平台。在本文中,我们将详细探讨SolidWorks教育版的
    的头像 发表于 04-01 14:35 319次阅读

    如何成为名嵌入式C语言高手?

    相关教材、参加在线课程或者参考编程书籍来系统地学习C语言的基础知识,并通过编写简单的程序进行实践。 二、深入了解嵌入式系统的硬件架构和工作原理嵌入式系统通常包含微控制器或微处理器等硬件设备
    发表于 03-25 14:12

    晶振电路中电容电阻的一些基本原理和作用解析

    晶振电路中的电容和电阻是调整和维持晶振振荡稳定性的关键元件。KOAN凯擎小妹带大家了解一下晶振电路中电容电阻的一些基本原理和作用。
    的头像 发表于 02-20 16:22 1648次阅读
    晶振电路中电容电阻的<b class='flag-5'>一些</b>基本原理和作用解析

    简单介绍一下电源纹波与电容啸叫

    简单介绍一下电源纹波与电容啸叫  电源纹波与电容啸叫是在电源系统中常见的两种问题,它们会影响电子设备的性能和稳定性。本篇文章将详细介绍电源纹波和电容啸叫的定义、原因、对设备的影响以及常
    的头像 发表于 02-04 09:42 980次阅读

    QT串口通信的简单使用

    QT串口通信是上位机和下位机通信常用的通信方式, 也是学习QT必须学会的基础知识, 这篇就简单介绍一下QT串口通信的简单使用.
    的头像 发表于 01-15 09:27 1834次阅读
    QT串口通信的<b class='flag-5'>简单</b>使用

    免费学习鸿蒙(HarmonyOS)开发,一些地址分享

    课|应用开发视频教程学习|HarmonyOS应用开发官网 官网是一些比较基础性的东西,学起来可能没那么好理解。下面再推荐个B站博主:HarmonyOS天天分享;里面有鸿蒙4.0的基础到高阶的
    发表于 01-12 20:48

    如何修改内核设备

    时,份完整的配置可以包括三个部分: ●soc级配置文件:定义了SOC级配置,如设备时钟、中断等资源,如图sun50iw9p1.dtsi。 ●board级配置文件:定义了板级配置,包含一些板级差异信息
    发表于 12-14 13:42

    大功率插件电感损坏的一些常见表现

    大功率插件电感是电子电路中非常重要的种电子元器件,它对于设备的稳定运行有直接的影响的。如果在设备的日常运行中遇到故障,如何辨别是否是大功率插件电感损坏造成的呢?本篇我们就来简单探讨
    发表于 12-11 16:22 3次下载

    提高嵌入式代码质量的一些方法

    的事情搞复杂,我希望这些文字能给迷惑中的人们指出一些正确的方向,让他们少走一些弯路,基本做到一分耕耘一分收获。
    的头像 发表于 11-30 09:15 436次阅读

    【米尔-TIAM62开发板-接替335x-试用评测】+(三)手把手创建Uboot设备与内核设备实战

    层级结构更为复杂,它包括个主设备文件和其他一些设备文件。这些文件描述了各种硬件
    发表于 11-28 09:54