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

news2024/10/6 14:37:31

        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 中,arch/arm/plat-xxx 和 arch/arm/mach-xxx 中充斥着大 量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不 过是垃圾,如板上的 platform 设备、resource、i2c_board_info、spi_board_info 以及各种硬 件的 platform_data。读者有兴趣可以统计下常见的 s3c2410、s3c6410 等板级目录,代码量 在数万行。

        社区必须改变这种局面,于是 PowerPC 等其他体系架构下已经使用的 Flattened Device Tree(FDT)进入 ARM 社区的视野。

        Device Tree 是一种描述硬件的数据结构,它起源于 OpenFirmware (OF)。在 Linux 2.6 中,ARM 架构的板极硬件细节过多地被硬编码在 arch/arm/plat-xxx 和 arch/arm/mach-xxx,采用 Device Tree 后,许多硬件的细节可以直接透 过它传递给 Linux,而不再需要在 kernel 中进行大量的冗余编码。

        Device Tree 由一系列被命名的结点(node)和属性(property)组成,而结点本身可包 含子结点。所谓属性,其实就是成对出现的 name 和 value。在 Device Tree 中,可描述的信 息包括(原先这些信息大多被 hard code 到 kernel 中):

        1、 CPU 的数量和类别

        2、 内存基地址和大小

        3、 总线和桥

        4、 外设连接

        5、 中断控制器和中断使用情况

        6、 GPIO 控制器和 GPIO 使用情况

        7、 Clock 控制器和 Clock 使用情况

        它基本上就是画一棵电路板上 CPU、总线、设备组成的树,Bootloader 会将这棵树传 递给内核,然后内核可以识别这棵树,并根据它展开出 Linux 内核中的 platform_device、 i2c_client、spi_device 等设备,而这些设备用到的内存、IRQ 等资源,也被传递给了内核, 内核会将这些资源绑定给展开的相应的设备。

        2. Device&Tree 组成和结构

        整个 Device Tree 牵涉面比较广,即增加了新的用于描述设备硬件信息的文本格式,又 增加了编译这一文本的工具,同时 Bootloader 也需要支持将编译后的 Device Tree 传递给 Linux 内核。

        DTS (device tree source) 

        dts 文件是一种 ASCII 文本格式的 Device Tree 描述,此文本格式非常人性化,适合人 类的阅读习惯。基本上,在 ARM Linux 在,一个.dts 文件对应一个 ARM 的 machine,一般 放置在内核的 arch/arm/boot/dts/目录。由于一个 SoC 可能对应多个 machine(一个 SoC 可 以对应多个产品和电路板),势必这些.dts 文件需包含许多共同的部分,Linux 内核为了简 化,把 SoC 公用的部分或者多个 machine 共同的部分一般提炼为.dtsi,类似于 C 语言的头 文件。其他的 machine 对应的.dts 就 include 这个.dtsi。譬如,对于 VEXPRESS 而言, vexpress-v2m.dtsi 就被 vexpress-v2p-ca9.dts 所引用, vexpress-v2p-ca9.dts 有如下一行:

        /include/ "vexpress-v2m.dtsi"

        当然,和 C 语言的头文件类似,.dtsi 也可以 include 其他的.dtsi,譬如几乎所有的 ARM SoC 的.dtsi 都引用了 skeleton.dtsi。

        dts(或者其 include 的.dtsi)基本元素即为前文所述的结点和属性:

                

                上述.dts 文件并没有什么真实的用途,但它基本表征了一个 Device Tree 源文件的结构:

                1 个 root 结点"/"; root 结点下面含一系列子结点,本例中为"node1" 和 "node2";

                结点"node1"下又含有一系列子结点,本例中为"child-node1" 和 "child-node2";

                各结点都有一系列属性。这些属性可能为空,如" an-empty-property";可能为字符串, 如"a-string-property";可能为字符串数组,如"a-string-list-property";可能为 Cells(由 u32 整数组成),如"second-child-property",可能为二进制数,如"a-byte-data-property"。

                下面以一个最简单的 machine 为例来看如何写一个.dts 文件。假设此 machine 的配置如 下:

                1 个双核 ARM Cortex-A9 32 位处理器;

                ARM 的 local bus 上的内存映射区域分布了 2 个串口(分别位于 0x101F1000 和 0x101F2000)、GPIO 控制器(位于 0x101F3000)、SPI 控制器(位于 0x10170000)、中 断控制器(位于 0x10140000)和一个 external bus 桥;

                External bus 桥上又连接了 SMC SMC91111 Ethernet(位于 0x10100000)、I 2 C 控制器 (位于 0x10160000)、64MB NOR Flash(位于 0x30000000); External bus 桥上连接的 I 2 C 控制器所对应的 I 2 C 总线上又连接了 Maxim DS1338 实时 钟(I 2 C 地址为 0x58)。

                其对应的.dts 文件为:

                

                   

                        

                  上述.dts 文件中,root 结点"/"的 compatible 属性 compatible = "acme,coyotes-revenge";定义 了系统的名称,它的组织形式为:,。

                   Linux 内核透过 root 结点"/"的 compatible 属性即可判断它启动的是什么 machine。 在.dts 文件的每个设备,都有一个 compatible 属性,compatible 属性用户驱动和设备的 绑定。compatible 属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确 切设备,形式为",",其后的字符串表征可兼容的其他设备。

                  可以说 前面的是特指,后面的则涵盖更广的范围。如在 arch/arm/boot/dts/vexpress-v2m.dtsi 中的 Flash 结点:

                

                compatible 属性的第 2 个字符串"cfi-flash"明显比第 1 个字符串"arm,vexpress-flash"涵盖 的范围更广。

                再比如,Freescale MPC8349 SoC 含一个串口设备,它实现了国家半导体(National Semiconductor)的 ns16550 寄存器接口。则 MPC8349 串口设备的 compatible 属性为 compatible = "fsl,mpc8349-uart", "ns16550"。其中,fsl,mpc8349-uart 指代了确切的设备, ns16550 代表该设备与 National Semiconductor 的 16550 UART 保持了寄存器兼容。

                接下来 root 结点"/"的 cpus 子结点下面又包含 2 个 cpu 子结点,描述了此 machine 上的 2 个 CPU,并且二者的 compatible 属性为"arm,cortex-a9"。

                注意 cpus 和 cpus 的 2 个 cpu 子结点的命名,它们遵循的组织形式为:[@],<>中的内容是必选项,[]中的则为可选项。name 是一个 ASCII 字符串,用于描 述结点对应的设备类型,如 3com Ethernet 适配器对应的结点 name 宜为 ethernet,而不是 3com509。如果一个结点描述的设备有地址,则应该给出@unit-address。多个相同类型设 备结点的 name 可以一样,只要 unit-address 不同即可,如本例中含有 cpu@0、cpu@1 以及 serial@101f0000 与 serial@101f2000 这样的同名结点。

                设备的 unit-address 地址也经常在其 对应结点的 reg 属性中给出。 ePAPR 标准给出了结点命名的规范。 可寻址的设备使用如下信息来在 Device Tree 中编码地址信息:

                        

                其中 reg 的组织形式为 reg = , 其中的每一组 address length 表明了设备使用的一个地址范围。address 为 1 个或多个 32 位 的整型(即 cell),而 length 则为 cell 的列表或者为空(若#size-cells = 0)。address 和 length 字段是可变长的,父结点的#address-cells 和#size-cells 分别决定了子结点的 reg 属性 的 address 和 length 字段的长度。

                在本例中,root 结点的#address-cells = ;和#size-cells = ;决定了 serial、gpio、spi 等结点的 address 和 length 字段的长度分别为 1。cpus 结点的 #address-cells = ;和#size-cells = ;决定了 2 个 cpu 子结点的 address 为 1,而 length 为 空,于是形成了 2 个 cpu 的 reg = ;和 reg = ;。external-bus 结点的#address-cells = 和#size-cells = ;决定了其下的 ethernet、i2c、flash 的 reg 字段形如 reg = ;、 reg = ;和 reg = ;。其中,address 字段长度为 0,开始的第一个 cell(0、1、2)是对应的片选,第 2 个 cell(0,0,0)是相对该片选的基地址,第 3 个 cell(0x1000、0x1000、0x4000000)为 length。特别要留意的是 i2c 结点中定义的 #addresscells = ;和#size-cells = ;又作用到了 I 2 C 总线上连接的 RTC,它的 address 字段为 0x58,是设备的 I 2 C 地址。

                root 结点的子结点描述的是 CPU 的视图,因此 root 子结点的 address 区域就直接位于 CPU 的 memory 区域。但是,经过总线桥后的 address 往往需要经过转换才能对应的 CPU 的 memory 映射。external-bus 的 ranges 属性定义了经过 external-bus 桥后的地址范围如何 映射到 CPU 的 memory 区域。

        

                ranges 是地址转换表,其中的每个项目是一个子地址、父地址以及在子地址空间的大 小的映射。

                映射表中的子地址、父地址分别采用子地址空间的#address-cells 和父地址空间 的#address-cells 大小。对于本例而言,子地址空间的#address-cells 为 2,父地址空间的 #address-cells 值为 1,因此 0 0 0x10100000 0x10000 的前 2 个 cell 为 external-bus 后片选 0 上偏移 0,第 3 个 cell 表示 external-bus 后片选 0 上偏移 0 的地址空间被映射到 CPU 的 0x10100000 位置,第 4 个 cell 表示映射的大小为 0x10000。ranges 的后面 2 个项目的含义 可以类推。

                Device Tree 中还可以中断连接信息,对于中断控制器而言,它提供如下属性:                 interrupt-controller – 这个属性为空,中断控制器应该加上此属性表明自己的身份; #interrupt-cells – 与#address-cells 和 #size-cells 相似,它表明连接此中断控制器的设备的 interrupts 属性的 cell 大小。

                在整个 Device Tree 中,与中断相关的属性还包括: interrupt-parent – 设备结点透过它来指定它所依附的中断控制器的 phandle,当结点没有 指定 interrupt-parent 时,则从父级结点继承。

                对于本例而言,root 结点指定了 interruptparent = ;其对应于 intc: interrupt-controller@10140000,而 root 结点的子结点并未指 定 interrupt-parent,因此它们都继承了 intc,即位于 0x10140000 的中断控制器。

                interrupts – 用到了中断的设备结点透过它指定中断号、触发方法等,具体这个属性含 有多少个 cell,由它依附的中断控制器结点的#interrupt-cells 属性决定。而具体每个 cell 又 是什么含义,一般由驱动的实现决定,而且也会在 Device Tree 的 binding 文档中说明。

                譬 如,对于 ARM GIC 中断控制器而言,#interrupt-cells 为 3,它 3 个 cell 的具体含义 Documentation/devicetree/bindings/arm/gic.txt 就有如下文字说明:

                        ​​​​​​​        

                另外,值得注意的是,一个设备还可能用到多个中断号。对于 ARM GIC 而言,若某设 备使用了 SPI 的 168、169 号 2 个中断,而言都是高电平触发,则该设备结点的 interrupts 属性可 定义为:interrupts = <0  168  4>,<0  169   4> ;

                除了中断以外,在 ARM Linux 中 clock、GPIO、pinmux 都可以透过.dts 中的结点和属 性进行描述。

                

                DTC (device tree compiler)

                将.dts 编译为.dtb 的工具。

                DTC 的源代码位于内核的 scripts/dtc 目录,在 Linux 内核使 能了 Device Tree 的情况下,编译内核的时候主机工具 dtc 会被编译出来,对应 scripts/dtc/Makefile 中的“hostprogs-y := dtc”这一 hostprogs 编译 target。

                在 Linux 内核的 arch/arm/boot/dts/Makefile 中,描述了当某种 SoC 被选中后,哪些.dtb 文件会被编译出来,如与 VEXPRESS 对应的.dtb 包括:

                

                

                Linux 下,我们可以单独编译 Device Tree 文件。

                当我们在 Linux 内核下运行 make dtbs 时,若我们之前选择了 ARCH_VEXPRESS,上述.dtb 都会由对应的.dts 编译出来。因 为 arch/arm/Makefile 中含有一个 dtbs 编译 target 项目。                

                 Device Tree Blob (.dtb)

                dtb 是.dts 被 DTC 编译后的二进制格式的 Device Tree 描述,可由 Linux 内核解析。通 常在我们为电路板制作 NAND、SD 启动 image 时,会为.dtb 文件单独留下一个很小的区域 以存放之,之后 bootloader 在引导 kernel 的过程中,会先读取该.dtb 到内存。

                Binding

                对于 Device Tree 中的结点和属性具体是如何来描述设备的硬件细节的,一般需要文档 来进行讲解,文档的后缀名一般为.txt。这些文档位于内核的 Documentation/devicetree/bindings 目录,其下又分为很多子目录。

                

                Bootloader

                Uboot mainline 从 v1.1.3 开始支持 Device Tree,其对 ARM 的支持则是和 ARM 内核支 持 Device Tree 同期完成。

                为了使能 Device Tree,需要编译 Uboot 的时候在 config 文件中加入

                #define CONFIG_OF_LIBFDT

                在 Uboot 中,可以从 NAND、SD 或者 TFTP 等任意介质将.dtb 读入内存,假设.dtb 放 入的内存地址为 0x71000000,之后可在 Uboot 运行命令 fdt addr 命令设置.dtb 的地址,如:

                U-Boot> fdt addr 0x71000000

                fdt 的其他命令就变地可以使用,如 fdt resize、fdt print 等。 对于 ARM 来讲,可以透过 bootz kernel_addr initrd_address dtb_address 的命令来启动内 核,即 dtb_address 作为 bootz 或者 bootm 的最后一次参数,第一个参数为内核映像的地址, 第二个参数为 initrd 的地址,若不存在 initrd,可以用 -代替。

《剩下内容请继续阅读第二篇》

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

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

相关文章

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

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

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

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

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

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

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

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

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

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

单向散列函数解析

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

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

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

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

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

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

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

Windows11和Ubuntu22双系统安装指南

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

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

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

云原生 Docker Swarm 使用详解

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

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

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

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

题目&#xff1a; 题解&#xff1a; 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容器的简单模拟实现

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

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

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

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

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

【后端】websocket学习笔记

文章目录 1. 消息推送常见方式1.1 轮询 VS 长轮询1.2 SSE&#xff08;server-sent event)服务器发送事件 2. websocket介绍2.1 介绍2.2 原理2.3 websoket API2.3.1 客户端【浏览器】API2.3.2 服务端API 3. 代码实现3.1 流程分析3.2 pom依赖3.3 配置类3.4 消息格式3.5 消息类 4.…

Qwen2大语言模型微调、导出、部署实践

上篇文章&#xff1a; Qwen1.5大语言模型微调实践_qwen1.5 7b微调-CSDN博客 我们介绍了Qwen1.5 大语言模型使用LLaMA-Factory 来微调&#xff0c;这篇文章我们介绍一下微调后模型的导出、部署。 一、模型导出 在webui 界面训练好模型之后点击“Export”选项卡&#xff0c;然…

Golang | Leetcode Golang题解之第155题最小栈

题目&#xff1a; 题解&#xff1a; type MinStack struct {stack []intminStack []int }func Constructor() MinStack {return MinStack{stack: []int{},minStack: []int{math.MaxInt64},} }func (this *MinStack) Push(x int) {this.stack append(this.stack, x)top : thi…