ARM Linux 设备树详细介绍(2)共二篇

news2025/1/12 7:54:17

承接上文,第一篇

        3. Device&Tree 引发的 BSP 和驱动变更

        有了 Device Tree 后,大量的板级信息都不再需要,譬如过去经常在 arch/arm/plat-xxx 和 arch/arm/mach-xxx 实施的如下事情:

        1. 注册 platform_device,绑定 resource,即内存、IRQ 等板级信息。

        透过 Device Tree 后,形如

                

       之类的 platform_device 代码都不再需要,其中 platform_device 会由 kernel 自动展开。而这 些 resource 实际来源于.dts 中设备结点的 reg、interrupts 属性。

        典型地,大多数总线都与“simple_bus”兼容,而在 SoC 对应的 machine 的.init_machine 成员函数中,调用 of_platform_bus_probe(NULL, xxx_of_bus_ids, NULL);即可自动展开所有 的 platform_device。譬如,假设我们有个 XXX SoC,则可在 arch/arm/mach-xxx/的板文件 中透过如下方式展开.dts 中的设备结点对应的 platform_device:

                        

        2. 注册 i2c_board_info,指定 IRQ 等板级信息。 形如

                        

        之类的 i2c_board_info 代码,目前不再需要出现,现在只需要把 tlv320aic23、fm3130、 24c64 这些设备结点填充作为相应的 I 2 C controller 结点的子结点即可,类似于前面的

                        

        之类的 spi_board_info 代码,目前不再需要出现,与 I 2 C 类似,现在只需要把 mtd_dataflash 之类的结点,作为 SPI 控制器的子结点即可,SPI host 驱动的 probe 函数透过 spi_register_master()注册 master 的时候,会自动展开依附于它的 slave。

        4. 多个针对不同电路板的 machine,以及相关的 callback。

        过去,ARM Linux 针对不同的电路板会建立由 MACHINE_START 和 MACHINE_END 包围起来的针对这个 machine 的一系列 callback,譬如:

                        

        这些不同的 machine 会有不同的 MACHINE ID,Uboot 在启动 Linux 内核时会将 MACHINE ID 存放在 r1 寄存器,Linux 启动时会匹配 Bootloader 传递的 MACHINE ID 和 MACHINE_START 声明的 MACHINE ID,然后执行相应 machine 的一系列初始化函数。

        引入 Device Tree 之后,MACHINE_START 变更为 DT_MACHINE_START,其中 含有一个.dt_compat 成员,用于表明相关的 machine 与.dts 中 root 结点的 compatible 属性兼 容关系。如果 Bootloader 传递给内核的 Device Tree 中 root 结点的 compatible 属性出现在某 machine 的.dt_compat 表中,相关的 machine 就与对应的 Device Tree 匹配,从而引发这一 machine 的一系列初始化函数被执行。

                        

        Linux 倡导针对多个 SoC、多个电路板的通用 DT machine,即一个 DT machine 的.dt_compat 表含多个电路板.dts 文件的 root 结点 compatible 属性字符串。之后,如果的电 路板的初始化序列不一样,可以透过 int of_machine_is_compatible(const char *compat) API 判断具体的电路板是什么。

        譬如 arch/arm/mach-exynos/mach-exynos5-dt.c 的 EXYNOS5_DT machine 同时兼容 "samsung,exynos5250"和"samsung,exynos5440":

                

        它的.init_machine 成员函数就针对不同的 machine 进行了不同的分支处理:

                        

        使用 Device Tree 后,驱动需要与.dts 中描述的设备结点进行匹配,从而引发驱动的 probe()函数执行。对于 platform_driver 而言,需要添加一个 OF 匹配表,如前文的.dts 文件 的"acme,a1234-i2c-bus"兼容 I 2 C 控制器结点的 OF 匹配表可以是:

                        

        对于 I2C 和 SPI 从设备而言,同样也可以透过 of_match_table 添加匹配的.dts 中的 相关结点的 compatible 属性,如 sound/soc/codecs/wm8753.c 中的:

                        

        不过这边有一点需要提醒的是,I 2 C 和 SPI 外设驱动和 Device Tree 中设备结点的 compatible 属性还有一种弱式匹配方法,就是别名匹配。compatible 属性的组织形式为 ,,别名其实就是去掉 compatible 属性中逗号前的 manufacturer 前缀。 关于这一点,可查看 drivers/spi/spi.c 的源代码,函数 spi_match_device()暴露了更多的细节, 如果别名出现在设备 spi_driver 的 id_table 里面,或者别名与 spi_driver 的 name 字段相同, SPI 设备和驱动都可以匹配上:

                

        4. 常用 OF&API

        在 Linux 的 BSP 和驱动代码中,还经常会使用到 Linux 中一组 Device Tree 的 API, 这些 API 通常被冠以 of_前缀,它们的实现代码位于内核的 drivers/of 目录。这些常用的 API 包括:

        int of_device_is_compatible(const struct device_node *device,const char *compat);

        判断设备结点的 compatible 属性是否包含 compat 指定的字符串。当一个驱动支持 2 个或多个设备的时候,这些不同.dts 文件中设备的 compatible 属性都会进入驱动 OF 匹配 表。因此驱动可以透过 Bootloader 传递给内核的 Device Tree 中的真正结点的 compatible 属 性以确定究竟是哪一种设备,从而根据不同的设备类型进行不同的处理。如 drivers/pinctrl/pinctrl-sirf.c 即兼容于"sirf,prima2-pinctrl",又兼容于"sirf,prima2-pinctrl",在驱 动中就有相应分支处理:

       

        struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible);

        根据 compatible 属性,获得设备结点。遍历 Device Tree 中所有的设备结点,看看 哪个结点的类型、compatible 属性与本函数的输入参数匹配,大多数情况下,from、type 为 NULL。

        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_u64(const struct device_node *np, const char *propname, u64 *out_value);

        读取设备结点 np 的属性名为 propname,类型为 8、16、32、64 位整型数组的属性。 对于 32 位处理器来讲,最常用的是 of_property_read_u32_array()。如在 arch/arm/mm/cachel2x0.c 中,透过如下语句读取 L2 cache 的"arm,data-latency"属性:

        ​​​​​​​                

        在 arch/arm/boot/dts/vexpress-v2p-ca9.dts 中,含有"arm,data-latency"属性的 L2 cache 结点如下:

                        

        有些情况下,整形属性的长度可能为 1,于是内核为了方便调用者,又在上述 API 的基础上封装出了更加简单的读单一整形属性的 API,它们为 int of_property_read_u8()、 of_property_read_u16()等,实现于 include/linux/of.h:

                        

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

        int of_property_read_string_index(struct device_node *np, const char *propname, int index, const char **output);

        前者读取字符串属性,后者读取字符串数组属性中的第 index 个字符串。如 drivers/clk/clk.c 中的 of_clk_get_parent_name()透过 of_property_read_string_index()遍历 clkspec 结点的所有"clock-output-names"字符串数组属性。

                        

                        

        static inline bool of_property_read_bool(const struct device_node *np, const char *propname);

        如果设备结点 np 含有 propname 属性,则返回 true,否则返回 false。一般用于检查 空属性是否存在。

        void __iomem *of_iomap(struct device_node *node, int index);

        通过设备结点直接进行设备内存区间的 ioremap(),index 是内存段的索引。若设备 结点的 reg 属性有多段,可通过 index 标示要 ioremap 的是哪一段,只有 1 段的情况,index 为 0。采用 Device Tree 后,大量的设备驱动通过 of_iomap()进行映射,而不再通过传统的 ioremap。         unsigned int irq_of_parse_and_map(struct device_node *dev, int index);

        透过 Device Tree 或者设备的中断号,实际上是从.dts 中的 interrupts 属性解析出中 断号。若设备使用了多个中断,index 指定中断的索引号。 还有一些 OF API,这里不一一列举,具体可参考 include/linux/of.h 头文件。

        5. 总结

        ARM 社区一贯充斥的大量垃圾代码导致 Linus 盛怒,因此社区在 2011 年到 2012 年进 行了大量的工作。ARM Linux 开始围绕 Device Tree 展开,Device Tree 有自己的独立的语 法,它的源文件为.dts,编译后得到.dtb,Bootloader 在引导 Linux 内核的时候会将.dtb 地址 告知内核。之后内核会展开 Device Tree 并创建和注册相关的设备,因此 arch/arm/mach-xxx 和 arch/arm/plat-xxx 中大量的用于注册 platform、I 2 C、SPI 板级信息的代码被删除,而驱动 也以新的方式和.dts 中定义的设备结点进行匹配。

ARM Linux 设备树详细介绍(2)共二篇《全篇结束》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1830080.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《人生海海》读后感

麦家是写谍战的高手,《暗算》《风声》等等作品被搬上荧屏后,掀起了一阵一阵的收视狂潮。麦家声名远扬我自然是知道的,然而我对谍战似乎总是提不起兴趣,因此从来没有拜读过他的作品。这几天无聊时在网上找找看看,发现了…

从xxl-job源码中学习Netty的使用

1. 启动与Spring实例化 com.xxl.job.core.executor.impl.XxlJobSpringExecutor.java类 继承SmartInitializingSingleton 类,在afterSingletonsInstantiated 实例化后方法中 调用initJobHandlerMethodRepository 把所有的xxljob任务管理起来; private…

ARM Linux 设备树详细介绍(1)

1. ARM&Device&Tree 起源 Linus Torvalds 在 2011 年 3 月 17 日的 ARM Linux 邮件列表宣称“this whole ARM thing is a f*cking pain in the ass”,引发 ARM Linux 社区的地震,随后 ARM 社区进行了一系列 的重大修正。 在过去的 ARM Linux 中&…

电子电气架构 --- 智能座舱功能应用

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

springCloudAlibaba之分布式网关组件---gateway

gateway-网关 网关spring cloud gatewaygateway初体验gateway整合nacos简写方式 网关 在微服务架构中一个系统会被拆分成多个微服务。那么作为客户端(前端)要如何去调用这么多的微服务?如果没有网关的存在,我们只能在客户端记录每个微服务的地址&#xf…

工程设计问题---多盘离合器制动器设计问题

这个问题的主要目的是使多片式离合器制动器的质量最小化。在这个问题中,使用了五个整数决策变量,它们是内半径(x1)、外半径(x2)、盘厚度(x3)、致动器的力(x4)…

【Mybatis-Plus】根据自定义注解实现自动加解密

背景 我们把数据存到数据库的时候,有些敏感字段是需要加密的,从数据库查出来再进行解密。如果存在多张表或者多个地方需要对部分字段进行加解密操作,每个地方都手写一次加解密的动作,显然不是最好的选择。如果我们使用的是Mybati…

基于WPF技术的换热站智能监控系统13--控制设备开关

1、本节目的 本次工作量相对有点大,有点难度,需要熟悉MVVM模式,特别是属性绑定和命令驱动,目标是点击水泵开关,让风扇转动或停止,风扇连接的管道液体流动或静止。 ,具体对应关系是:…

单向散列函数解析

目录 1. 概述 2. 单向散列函数的性质 2.1 根据任意长度的消息计算出固定长度的散列值 2.2 能够快速计算出散列值 2.3 消息不同散列值也不同 2.4 具备单向性 3. 单向散列函数的算法 3.1 MD5 3.2 SHA序列 3.3 SM3 1. 概述 针对计算机所处理的消息,有时候我们…

【设计模式深度剖析】【9】【行为型】【访问者模式】| 以博物馆的导览员为例加深理解

👈️上一篇:备忘录模式 设计模式-专栏👈️ 文章目录 访问者模式定义英文原话直译如何理解呢? 访问者模式的角色类图代码示例 访问者模式的应用优点缺点使用场景 示例解析:博物馆的导览员代码示例 访问者模式 访问者模式(Visito…

计算机毕业设计hadoop+spark+hive知识图谱酒店推荐系统 酒店数据分析可视化大屏 酒店爬虫 高德地图API 酒店预测系统 大数据毕业设计

流程: 1.Python爬取去哪儿网全站旅游数据约10万,存入mysql; 2.使用pandasnumpy/hadoopmapreduce对mysql中旅游数据进行数据清洗,使用高德API计算地理信息,最终转为.csv文件上传hdfs; 3.hive建库建表导入.csv文件作为数据集&#x…

2024年汉字小达人活动还有4个多月开赛:来做18道历年选择题备考吧

结合最近几年的活动安排,预计2024年第11届汉字小达人比赛还有4个多月就启动,那么孩子们如何利用这段时间有条不紊地准备汉字小达人比赛呢? 我的建议是充分利用即将到来的暑假:①把小学1-5年级的语文课本上的知识点熟悉&#xff0…

Windows11和Ubuntu22双系统安装指南

一、需求描述 台式机电脑,已有Windows11操作系统,想要安装Ubuntu22系统(版本任意)。其中Windows安装在Nvme固态上,Ubuntu安装在Sata固态上,双盘双系统。开机时使用Grub控制进入哪个系统,效果图…

直接选择排序-C语言版本

前言 直接选择排序也是一个比较简单的排序,所以这里放在第二个进行讲解,这里和冒泡排序是有一点相似。直接选择排序和冒泡排序一样,也是具备一定的教学意义,但是没有什么实际操作的意义,因为直接选择排序的时间复杂度比…

云原生 Docker Swarm 使用详解

Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~ 💥💥个人主页:奋斗的小羊 💥💥所属专栏:C语言 🚀本系列文章为个人学习…

用Copilot画漫画,Luma AI生成视频:解锁创意新玩法

近年来,随着人工智能技术的不断发展,各种创意工具也层出不穷。今天,我们就来介绍一种全新的创作方式:使用Copilot画漫画,再将漫画放入Luma AI生成视频。 Copilot:你的AI绘画助手 Copilot是一款基于人工智…

Java | Leetcode Java题解之第147题对链表进行插入排序

题目: 题解: class Solution {public ListNode insertionSortList(ListNode head) {if (head null) {return head;}ListNode dummyHead new ListNode(0);dummyHead.next head;ListNode lastSorted head, curr head.next;while (curr ! null) {if (…

C++编程:vector容器的简单模拟实现

前言: 在C标准库(STL)中,vector容器是最常见使用的动态数组。它结合了链表与数组的优点,提供了灵活的大小调整与高效的随机访问。本文将简单的对vector容器进行介绍并且对vector容器简单的模拟实现。 一、vector的文…

Project ERROR: Unknown module(s) in QT: xlsx

Qt5下Qxlsx模块安装及使用_qt5xlsx-CSDN博客 主要参考上面这篇文章! Perl的安装与配置_perl安装-CSDN博客 1.1 windows环境安装Perl_windows perl-CSDN博客 首先,需要安装Perl,我安装的是Windows版本的。 Download & Install Perl - ActiveStat…

C#使用Scoket实现服务器和客户端互发信息

20240616 By wdhuag 目录 前言: 参考: 一、服务器端: 1、服务器端口绑定: 2、服务器关闭: 二、客户端: 1、客户端连接: 2、客户端断开: 三、通讯: 1、接收信…