IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux下设备树内容(详细)总结及示例解析 -> 正文阅读

[系统运维]Linux下设备树内容(详细)总结及示例解析

一、简介

设备树是在PowerPC平台最先使用,后来2011年3月份Linux创始人Linus Torvalds在邮件建议ARM社区也使用设备树的方式去描述板级结构。所以设备树其实就是描述开发板上的硬件信息,由于其结构就像现实世界的大树一样,所以就将这种结构叫设备树,如下图所示。

在这里插入图片描述

二、设备树基础内容

2.1 设备树文件存放路径

dts源码都在对应的架构目录下,如arm平台arch/arm/boot/dts,对应的文件主要有1个dts文件+n个dtsi文件,它们编译而成的dtb文件就是真正的设备树。
soc厂商会把soc公共的特性和多块开发板公用的特性提炼为dtsi,而dts则负责描述某个具体的产品(开发板)的特性。dts直接或间接的包含多个dtsi(类似于c语言的头文件),就体现了一个完整的产品(开发板)所有的特性。以solidrun公司的hummingboard为例,其组成为

imx6dl-hummingboard.dts
        |_imx6dl.dtsi
        |   |_imx6qdl.dtsi
        |_imx6qdl-microsom.dtsi
        |_imx6qdl-microsom-ar8035.dtsi 

2.2 DTS、DTB和DTC关系

DTS(devcie tree source):设备树源码文件
DTB(device tree binary):将 .dts 编译后得到二进制文件,下载到 DDR 中的是 .dtb 文件
DTC(device tree compiler):将 .dts 编译为 .dtb 的编译工具,它有个文件夹,经过编译后得到 DTC

2.3 传统驱动代码和使用设备树的对比

传统方式:
(1)代码冗余
在没有使用设备树的时候,有关板级的硬件信息都被硬编码在内核中,这就导致了内核中描述板级硬件的代码过于庞大,不利于阅读。以arm架构为例,通常这些硬件信息会放在/arch/arm/mach-xxx和/arch/arm/plat-xxx里面。

(2)修改麻烦
在内核中有一种叫总线的模型,这种模型的作用是将设备信息与驱动进行分离,在没有使用设备树的情况下,这里的设备信息就被硬编码到/arch/arm/mach-xxx和/arch/arm/plat-xxx中。这就会导致一种不好的结果,当你修改了某个设备的信息时,你就需要重新编译内核并把内核烧到系统中。

设备树的优点:
在使用设备树后,内核中就不再需要那些硬件信息了,描述硬件的信息都会被统一放到/arch/arm/boot/dts的设备树文件中,这样就可以减少代码的冗余。
当你需要修改设备的硬件信息时,只需要在修改设备树之后,对设备树进行编译并放到系统中,uboot就会将设备树的地址告诉Linux内核,让Linux内核到相应的内存地址去解析设备树信息,不再需要重新编译内核。

三、设备树内容属性介绍

3.1 节点名称

node-name@unit-address  //node-name:节点名字 unit-address:表示寄存器基地址或设备地址,如下serial@101f0000
label:node-name@unit-address        // 引入label目的就是为了方便便访问节点,可以直接通过&label来访问这个
serial@101f0000 {  
	compatible = "arm,pl011";  
	reg = <0x101f0000 0x1000 >;  
	interrupts = < 1 0 >;  

3.2 compatible

compatible 属性值为字符串列表,?于将设备和驱动绑定起来,字符串列表?于选择设备所要使用的驱动程序

"manufacturer,model"     //anufacturer :厂商  model:模块对应的驱动名

一般驱动程序文件中都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。

3.3 model 属性

model 属性:描述设备模块信息,比如名字什么的,如:model = “wm8960-audio”。

3.4 status 属性

status 属性:描述设备状态,如:okay - 设备可操作,disabled - 设备不可操作

3.5 #address-cells 和 #size-cells 属性

#address-cells 和 #size-cells 描述?节点应如何编写 reg 属性值,一般 reg 属性是某个外设的寄存器地址范围信息。

3.6 ranges 属性

ranges它是一个地址映射/转换表,如果 ranges 属性值为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换。

3.7 aliases 节点

用 aliases 节点给多个同类型的控制器分配唯一编号,便于Linux内核区分。在Linux启动时会解析aliases节点。

3.8 chosen 节点

chosen 并不是一个真实的设备,主要用于将 uboot 中的 bootargs 环境变量值传递给 Linux 内核作为命令行参数

四、设备树文件内容示例解析

    / {  
        compatible = "acme,coyotes-revenge";  
        #address-cells = <1>;  
        #size-cells = <1>;  
        interrupt-parent = <&intc>;  
      
        cpus {  
            #address-cells = <1>;  
            #size-cells = <0>;  
            cpu@0 {  
                compatible = "arm,cortex-a9";  
                reg = <0>;  
            };  
            cpu@1 {  
                compatible = "arm,cortex-a9";  
                reg = <1>;  
            };  
        };  
      
        serial@101f0000 {  
            compatible = "arm,pl011";  
            reg = <0x101f0000 0x1000 >;  
            interrupts = < 1 0 >;  
        };  
      
        serial@101f2000 {  
            compatible = "arm,pl011";  
            reg = <0x101f2000 0x1000 >;  
            interrupts = < 2 0 >;  
        };  
      
        gpio@101f3000 {  
            compatible = "arm,pl061";  
            reg = <0x101f3000 0x1000  
                   0x101f4000 0x0010>;  
            interrupts = < 3 0 >;  
        };  
      
        intc: interrupt-controller@10140000 {  
            compatible = "arm,pl190";  
            reg = <0x10140000 0x1000 >;  
            interrupt-controller;  
            #interrupt-cells = <2>;  
        };  
      
        spi@10115000 {  
            compatible = "arm,pl022";  
            reg = <0x10115000 0x1000 >;  
            interrupts = < 4 0 >;  
        };  
      
        external-bus {  
            #address-cells = <2>  
            #size-cells = <1>;  
            ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet  
                      1 0  0x10160000   0x10000     // Chipselect 2, i2c controller  
                      2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash  
      
            ethernet@0,0 {  
                compatible = "smc,smc91c111";  
                reg = <0 0 0x1000>;  
                interrupts = < 5 2 >;  
            };  
      
            i2c@1,0 {  
                compatible = "acme,a1234-i2c-bus";  
                #address-cells = <1>;  
                #size-cells = <0>;  
                reg = <1 0 0x1000>;  
                interrupts = < 6 2 >;  
                rtc@58 {  
                    compatible = "maxim,ds1338";  
                    reg = <58>;  
                    interrupts = < 7 3 >;  
                };  
            };  
      
            flash@2,0 {  
                compatible = "samsung,k8f1315ebm", "cfi-flash";  
                reg = <2 0 0x4000000>;  
            };  
        };  
    };  

4.1 设备树关键内容解析

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

(2)中断号和电平触发方式

interrupts = < 6 2 >;   //中断号为6,下降沿触发
#电平触发方式定义
1 = low-to-high edge triggered 
2 = high-to-low edge triggered 
4 = active high level-sensitive 
8 = active low level-sensitive 

(3)驱动获取设备树内容的常用函数
设备树描述了设备的详细信息,我们在编写驱动时需要获取到这些信息,Linux内核给我们提供了一系列的函数来获取设备树中的节点或者属性信息,内核启动时会解析.dtb文件,从而获取设备树中各个节点的信息,并且在根文件系统的/proc/device-tree目录下根据节点名字创建不同文件夹。

查找节点:of_find_node_by_path 函数,通过指定全路径来查找指定节点。
提取属性值:of_find_property 函数 ,获取到的值保存到了 property 结构体中。
读取属性中字符串值:of_property_read_string 函数。
读取属性中数组数据:of_property_read_u32_array 函数,常用于一次读取出 reg 属性中的所有数据。
直接内存映射:of_iomap 函数,获取内存地址所对应的虚拟地址

(4)绑定信息文档查询
我们往往不知道如何在设备树中添加一个硬件对应的节点,此时我们可以参考Linux内核源码中有详细的.txt文档描述了如何添加节点,这些.txt文档叫做绑定文档。
路径:/Documentation/devicetree/bindings
在这里插入图片描述

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章           查看所有文章
加:2022-05-16 11:30:21  更:2022-05-16 11:31:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 16:53:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码