首页 > 系统相关 >[linux] Linux dts、dtsi、dtc、dtb整理

[linux] Linux dts、dtsi、dtc、dtb整理

时间:2024-11-11 19:44:12浏览次数:3  
标签:dtc dtb cells 节点 compatible linux dts reg 属性

参考链接

设备树属性解读_设备树reg属性解析-CSDN博客

高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)_高通提取dtb-CSDN博客

高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)-腾讯云开发者社区-腾讯云

高通平台msm8953 Linux DTS(Device Tree Source)设备树详解之二(DTS设备树匹配过程) - fire909090 - 博客园

dts(device tree source 设备树源文件)

        dts文件是一种ASCII文本格式的设备树描述文件,此文件适合人类阅读主要是给用户看的。一个dts文件对应一个ARM的设备,一般放置在arch/arm/boot/dts/中。

DTS的加载过程

如果要使用Device Tree,首先用户要了解自己的硬件配置和系统运行参数,并把这些信息组织成Device Tree source file。通过DTC(Device Tree Compiler),可以将这些适合人类阅读的Device Tree source file变成适合机器处理的Device Tree binary file(有一个更好听的名字,DTB,device tree blob)。在系统启动的时候,boot program(例如:firmware、bootloader)可以将保存在flash中的DTB copy到内存(当然也可以通过其他方式,例如可以通过bootloader的交互式命令加载DTB,或者firmware可以探测到device的信息,组织成DTB保存在内存中),并把DTB的起始地址传递给client program(例如OS kernel,bootloader或者其他特殊功能的程序)。对于计算机系统(computer system),一般是firmware->bootloader->OS,对于嵌入式系统,一般是bootloader->OS。

dts的格式

sdx35为例

/dts-v1/;   /*dts版本号*/

#include "sdxbaagha.dtsi"  /*引用的dtsi文件*/
#include "sdxbaagha-mtp.dtsi"    /*引用的dtsi文件*/

/*root根节点*/
/ {
	model = "Qualcomm Technologies, Inc. SDXBAAGHA MTP 256M"; /*root节点属性*/
	compatible = "qcom,sdxbaagha-mtp",
		"qcom,sdxbaagha", "qcom,mtp";/*定义系统属性*/
	qcom,board-id = <0x10008 0x103>, <0x10008 0x203>;/*定义board-id*/
};

上述.dts文件中,root结点"/"的compatible 属性"qcom,sdxbaagha-mtp",
        "qcom,sdxbaagha", "qcom,mtp";定义了系统的名称,它的组织形式为:<manufacturer>,<model>。Linux内核透过root结点"/"的compatible 属性即可判断它启动的是什么machine。
在.dts文件的每个设备,都有一个compatible 属性,compatible属性用户驱动和设备的绑定。compatible 属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确切设备,形式为"<manufacturer>,<model>",其后的字符串表征可兼容的其他设备 。compatible属性的第2个字符串明显比第1个字符串涵盖的范围更广 

        当然devicetree的根节点也是需要和板子进行匹配的,这个匹配信息存放在sbl(second boot loader)中,对应dts文件中描述的board-id(上面代码中的qcom,board-id属性),通过共享内存传递给bootloader,由bootloader将此board-id匹配dts文件(devicetree的根节点文件),将由dtc编译后的dts文件(dtb文件)加载到内存,然后在kernel中展开dts树,并且挂载dts树上的所有设备。(cat /proc/cmdline 查看cmdline)

Dts中相关符号的含义

/        根节点

@     如果设备有地址,则由此符号指定

&     引用节点

:        冒号前的label是为了方便引用给节点起的别名,此label一般使用为&label

,        属性名称中可以包含逗号。如compatible属性的名字 组成方式为"[manufacturer], [model]",加入厂商名是为了避免重名。自定义属性名中通常也要有厂商名,并以逗号分隔。

# #并不表示注释。如 #address-cells ,#size-cells 用来决定reg属性的格式。

        空属性并不一定表示没有赋值。如 interrupt-controller 一个空属性用来声明这个node接收中断信号

数据类型

“”     引号中的为字符串,字符串数组:”strint1”,”string2”,”string3”

< >    尖括号中的为32位整形数字,整形数组<12 3 4>

[ ]      方括号中的为32位十六进制数,十六机制数据[0x11 0x12 0x13]  其中0x可省略

构成节点名的有效字符:

0-9a-zA-Z,._+-

构成属性名的有效字符:

0-9a-zA-Z,._+?#

DTS中几个难理解的属性的解释

a. 地址

设备的地址特性根据一下几个属性来控制:

reg  
#address-cells  
#size-cells  

reg意为region,区域。格式为:

  1. reg = <address1length1 [address2 length2] [address3 length3]>;  

父类的address-cells和size-cells决定了子类的相关属性要包含多少个cell,如果子节点有特殊需求的话,可以自己再定义,这样就可以摆脱父节点的控制。

address-cells决定了address1/2/3包含几个cell,size-cells决定了length1/2/3包含了几个cell。本地模块例如:

spi@10115000{  
        compatible = "arm,pl022";  
        reg = <0x10115000 0x1000 >;  
};  

位于0x10115000的SPI设备申请地址空间,起始地址为0x10115000,长度为0x1000,即属于这个SPI设备的地址范围是0x10115000~0x10116000。

实际应用中,有另外一种情况,就是通过外部芯片片选激活模块。例如,挂载在外部总线上,需要通过片选线工作的一些模块:

external-bus{  
    #address-cells = <2>  
    #size-cells = <1>;  
   
    ethernet@0,0 {  
        compatible = "smc,smc91c111";  
        reg = <0 0 0x1000>;  
    };  
   
    i2c@1,0 {  
        compatible ="acme,a1234-i2c-bus";  
        #address-cells = <1>;  
        #size-cells = <0>;  
        reg = <1 0 0x1000>;  
        rtc@58 {  
            compatible ="maxim,ds1338";  
            reg = <58>;  
        };  
    };  
   
    flash@2,0 {  
        compatible ="samsung,k8f1315ebm", "cfi-flash";  
        reg = <2 0 0x4000000>;  
    };  
};  

external-bus使用两个cell来描述地址,一个是片选序号,另一个是片选序号上的偏移量。而地址空间长度依然用一个cell来描述。所以以上的子设备们都需要3个cell来描述地址空间属性——片选、偏移量、地址长度。在上个例子中,有一个例外,就是i2c控制器模块下的rtc模块。因为I2C设备只是被分配在一个地址上,不需要其他任何空间,所以只需要一个address的cell就可以描述完整,不需要size-cells。

当需要描述的设备不是本地设备时,就需要描述一个从设备地址空间到CPU地址空间的映射关系,这里就需要用到ranges属性。还是以上边的external-bus举例:

#address-cells= <1>;  
#size-cells= <1>;  
...  
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  
};  

ranges属性为一个地址转换表。表中的每一行都包含了子地址、父地址、在自地址空间内的区域大小。他们的大小(包含的cell)分别由子节点的address-cells的值、父节点的address-cells的值和子节点的size-cells来决定。以第一行为例:

·        0 0 两个cell,由子节点external-bus的address-cells=<2>决定;

·        0x10100000 一个cell,由父节点的address-cells=<1>决定;

·        0x10000 一个cell,由子节点external-bus的size-cells=<1>决定。
最终第一行说明的意思就是:片选0,偏移0(选中了网卡),被映射到CPU地址空间的0x10100000~0x10110000中,地址长度为0x10000。

b. 中断

描述中断连接需要四个属性:
1. interrupt-controller 一个空属性用来声明这个node接收中断信号;
2. #interrupt-cells 这是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符;
3. interrupt-parent 标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的;
4. interrupts 一个中断标识符列表,表示每一个中断输出信号。

如果有两个,第一个是中断号,第二个是中断类型,如高电平、低电平、边缘触发等触发特性。对于给定的中断控制器,应该仔细阅读相关文档来确定其中断标识该如何解析。一般如下:

二个cell的情况

第一个值: 该中断位于他的中断控制器的索引;

第二个值:触发的type

固定的取值如下:

        1 = low-to-high edge triggered
        2 = high-to-low edge triggered
        4 = active high level-sensitive
        8 = active low level-sensitive

三个cell的情况

第一个值:中断号

第二个值:触发的类型

第三个值:优先级,0级是最高的,7级是最低的;其中0级的中断系统当做 FIQ处理。

c. 其他

除了以上规则外,也可以自己加一些自定义的属性和子节点,但是一定要符合以下的几个规则:

1.    新的设备属性一定要以厂家名字做前缀,这样就可以避免他们会和当前的标准属性存在命名冲突问题;

2.    新加的属性具体含义以及子节点必须加以文档描述,这样设备驱动开发者就知道怎么解释这些数据了。描述文档中必须特别说明compatible的value的意义,应该有什么属性,可以有哪个(些)子节点,以及这代表了什么设备。每个独立的compatible都应该由单独的解释。

新添加的这些要发送到[email protected]邮件列表中进行review,并且检查是否会在将来引发其他的问题。

dtsi

       由于dts中包含了很多公共部分,linux内核为了简化,将Soc公共部分提炼为.dtsi文件。 由于一个SOC可能有多个不同的电路板,而每个电路板拥有一个 *.dts。这些dts势必会存在许多共同部分,为了减少代码的冗余,设备树将这些共同部分提炼保存在*.dtsi文件中,供不同的dts共同使用。*.dtsi的使用方法,类似于C语言的头文件,在dts文件中需要进行include *.dtsi文件。同时dtsi本身也支持include 另一个dtsi文件。

dtsi格式

#include "sdxbaagha.dtsi" /*引用文件*/
/ {
};

&chosen {
	bootargs = "pcie_ports=compat cpufreq.default_governor=performance";
	linux,initrd-start = <0x87700000>; /*启动地址*/
};

&soc {
	pcie0: qcom,pcie@1bf0000 {
		status = "disabled";
	};
};

/delete-node/ &mem_dump;  /*删除节点*/
&reserved_memory {
	mpss_audio_mem: mpss_audio_region@82e00000 {
		no-map;
		reg = <0x82e00000 0x3300000>;
	};

	trusted_apps_mem: trusted_apps_region@82680000 {
		no-map;
		reg = <0x82680000 0x29a000>;
	};

	system_cma: linux,cma {
		compatible = "shared-dma-pool";
		alloc-ranges = <0x00000000 0xffffffff>;
		reusable;
		alignment = <0x400000>;
		size = <0x400000>;
		linux,cma-default;
	};
};

&ethqos_hw {
	status = "disabled";
};

&soc {
	mem_dump {
		compatible = "qcom,mem-dump";
		memory-region = <&system_cma>;

		etr_reg {
			qcom,dump-size = <0x1000>;
			qcom,dump-id = <0x100>;
		};
	};
};

dtsi中编码地址信息

  •     reg
  •     #address-cells
  •     #size-cells

reg的组织形式为

reg = <address1 length1 [address2 length2] [address3 length3] ... >

其中的每一组address length表明了设备使用的一个地址范围。

每个可编址设备都有 reg,它是一个元组表,形式:reg=<地址1 长度1 [地址2 长度2] [地址3 长度3]>. 每个元组都表示该设备使用的一个地址范围。 每个地址值是一个或多个32位整数列表,成为cell,长度值也可以是一个cell列表或者空。 父节点的#address-cells 和 #size-cells 属性用来声明各个字段的cell的数量==也就是说解释一个reg属性需要用到父节点的#address-cells 和 #size-cells的值;
例如:

i2c主机控制器是一个父节点,地址长度为一个32位整数,地址长度为0. s5m8767_pmic是i2c主机控制器下的一个子节点,地址为0x66;
如果一个节点有reg属性,那么该节点名字就必须包含设备地址=reg属性里边第一个值

mtk ethernet

&eth {
	...
	mdio: mdio-bus {
		#address-cells = <1>;
		#size-cells = <0>;

	gmac1: mac@1 {
		compatible = "mediatek,eth-mac";
		reg = <1>;
		phy-mode = "sgmii";
		phy-handle = <&phy5>;
	};

    phy5: phy@5 {
		compatible = "ethernet-phy-idc0ff.0421";
		reg = <1>;
		phy-mode = "sgmii";
		full-duplex;
		pause;
	};

 

dtc

      DTC为编译工具,它可以将.dts文件编译成.dtb文件。DTC的源码位于内核的scripts/dtc目录,内核选中CONFIG_OF,编译内核的时候,主机可执行程序DTC就会被编译出来。 即scripts/dtc/Makefile中

dtb(dtb - device tree blob设备树二进制文件)

        DTC编译*.dts生成的二进制文件(*.dtb),bootloader在引导内核时,会预先读取*.dtb到内存,进而由内核解析

标签:dtc,dtb,cells,节点,compatible,linux,dts,reg,属性
From: https://blog.csdn.net/wgl307293845/article/details/143628473

相关文章

  • Linux硬盘挂载与磁盘分区基础(一)(主分区、拓展分区、逻辑分区)
      我们常用windows时,会区分C盘、D盘之类的(A、B盘是软盘)就是所谓的分区,这么做为了方便数据管理,比如扩容之类的。  本文采用Linux(Ubuntu20.04)来介绍分区,其它Linux系统基本一样的。  首先,我们需要熟悉几个概念:  硬盘:存储数据用的硬件,比如移动硬盘、固态硬盘、U盘等,有了硬......
  • Linux 关机的shell脚本
    今天突发奇想想写一个关机的脚本然后去找了很多帖子发现写的都不是很详细就打算自己写一个比较详细的:首先用vim编辑器先创建一个脚本文件(我是在桌面创建的)(也可以用其他文本编辑器不一定是vim):vimshutdown.sh然后就是在将以下内容输入至“shutdown.sh”中:#!/bin/bash......
  • 深入理解Linux内核中的虚拟文件系统(VFS)
    深入理解Linux内核中的虚拟文件系统(VFS)1.引言今天我们要探讨的是Linux内核中的虚拟文件系统(VFS)。VFS作为一层抽象,为各种不同的文件系统提供了一个统一的接口。无论是你常用的ext4,还是远程的NFS,都能通过VFS提供的相同接口进行交互。这期教程我会带你深入了解VFS的核心原理......
  • 《Linux操作系统》课程标准
      《Linux操作系统》是计算机类专业的一门专业课程,是培养和检验学生在Linux平台上熟练使用Linux操作系统,掌握基本服务器配置与管理等综合应用能力的一门重要的实践性课程。目的是掌握LINUX的安装与启动、LINUX远程登录、LINUX的磁盘文件管理,学会正则表达式、shell编程、用......
  • Linux基础(2)以及资源耗尽病毒的编写(详见B站泷羽sec)
    免责声明:本教程作者及相关参与人员对于任何直接或间接使用本教程内容而导致的任何形式的损失或损害,包括但不限于数据丢失、系统损坏、个人隐私泄露或经济损失等,不承担任何责任。所有使用本教程内容的个人或组织应自行承担全部风险。Linux目录介绍:/bin 二进制可执行文......
  • linux 计算程序运行时间, 及时间差
    linux计算程序运行时间,及时间差统计Shell脚本执行时间,帮助分析改进脚本执行linuxshell计算时间差值#!/bin/bash#计算时间差date1=$(date+"%Y-%m-%d%H:%M:%S")echo"时间1:$date1"echo"延时10s"sleep10date2=$(date+"%Y-%m-%d%H:%M:%S")echo"时间2......
  • Linux kernel 堆溢出利用方法(二)
    前言本文我们通过我们的老朋友heap_bof来讲解Linuxkernel中off-by-null的利用手法。在通过讲解另一道相对来说比较困难的kerneloff-by-null+dockerescape来深入了解这种漏洞的利用手法。(没了解过docker逃逸的朋友也可以看懂,毕竟有了root权限后,docker逃逸就变的相对简单了)。......
  • Linux常用命令之touch命令详解
    touch命令详解touch是一个在Unix和类Unix操作系统(如Linux和macOS)中广泛使用的命令行工具,主要功能包括更新文件的时间戳(访问时间和修改时间)和创建新的空文件。touch命令非常灵活,可以通过多种选项来定制其行为,以满足不同的需求。基本语法touch命令的基本语法如......
  • linux中使用cd指令跳转路径时带不带“/”
    在Linux中使用`cd`命令跳转目录时,是否需要`/`取决于路径的类型。以下是规则:1.**绝对路径:以`/`开头**-如果路径以`/`开头,表示从根目录开始的**绝对路径**。-使用绝对路径可以精确定位到文件系统中的某个目录,不受当前目录影响。-例如:```bashcd/......
  • linux进程概念
    前言:进程是linux中非常重要的概念,执行的每一个程序都是进程。因此我们需要了解进程。1.冯洛伊曼体系结构我们常见的计算机以及不常见的计算机大多都遵循冯洛伊曼体系结构。冯洛伊曼体系结构由五部分组成,分别是输出设备,输入设备,存储器,运算器和控制器组成。输入设备包括键......