设备树.dts文件
一,概念
设备树(Device Tree)是描述计算机的特定硬件设备信息的数据结构,以便于操作系统的内核可以管理和使用这些硬件,包括CPU或CPU,内存,总线和其他一些外设。它起源于OpenFirmware。采用设备树后,许多硬件的细节可以直接传递给linux,不需要在内核中充斥着大量的冗余代码。
Linux内核从3.x版本之后开始支持使用设备树,这样做的意义重大,可以实现驱动代码与设备的硬件信息相互的隔离,减少了代码中的耦合性,在此之前,一些与硬件设备相关的具体信息都要写在驱动代码中,如果外设发生相应的变化,那么驱动代码就需要改动。但是在引入了设备树之后,这种尴尬的情况找到了解决的办法,通过设备树对硬件信息的抽象,驱动代码只要负责处理逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,开发者只需要修改设备树文件信息,不需要改写驱动代码。
二,框架理解
设备树由一系列的节点和属性组成,节点可包含子节点。在设备树中,可描述的信息包括:
- CPU数量和类型
- 内存基地址和大小
- 总线和桥
- 外设连接
- 中断控制器和中断使用情况
- GPIO控制器和GPIO使用情况
- 时钟控制器和时钟使用情况
bootload会将这些信息传递给内核,内核开始识别这些树,并解析成linux内核中platform_device,i2c_client,spi_device等设备,而这些设备使用的内存资源,中断等信息也传递给内核。内核会将这些资源绑定给相应的设备。
dtb(Device Tree Blob)
,dts
经过dtc
编译之后会得到dtb
文件,dtb
通过Bootloader
引导程序加载到内核。所以Bootloader
需要支持设备树才行;Kernel也需要加入设备树的支持;
三,语法
一个dts文件主要包含以下几个部分:
- 根节点:
\
- 设备节点:
nodex
- 节点名称:图中
node
; - 节点地址:
node@0
就是节点的地址; - 子节点:
childnode
- 节点名称:图中
- 属性:属性名称(
Property name
)和属性值(Property value
) - 标签
比如下面这个:
对该dts文件做一些解释:
/dts-v1/;
:这是DTS文件的版本指令,表示该文件使用版本1的DTS语法。/
:该节点是根节点,表示整个系统。#address-cells
和#size-cells
:这些属性用于指定节点的地址和大小长度,这里设置为1,即32。compatible
:该属性用于描述系统和其组件的兼容性,compatible 属性的值是一个字符串列表, compatible 属性用于将设备和驱动绑定起来,用于选择设备所要
使用的驱动程序。model
:该属性用于描述该系统的型号信息,描述设备模块信息。- L xx :在Device Tree文件中,L是一个label(标签)的前缀,用于标识不同的节点。Label是一个唯一的字符串标识符,可以用于在设备树中引用节点。在这个文件中,L被用于标识不同的节点,如serial0、cpus、soc等等。
aliases
:该节点是别名节点,允许为设备定义别名,以便在系统中引用。这里定义了一个串口设备别名“serial0”。
CPU部分:
cpus
:该节点是CPU节点,用于描述系统中的CPU资源。这里定义了一个名为“cpu@0”的CPU,使用了“sifive,rocket0”和“riscv”兼容属性。- hardware-exec-breakpoint-count = <1>; 表示硬件执行断点计数器的数量为1。
- i-cache-block-size = <64>; 表示I缓存块的大小为64字节。
- i-cache-sets = <64>; 表示I缓存的组数为64。
- i-cache-size = <4096>; 表示I缓存总大小为4096字节。
- reg = <0x0>; 表示该处理器的寄存器起始地址为0。
- riscv,isa = "rv32imac"; 表示该处理器的指令集为RV32IMAC。
- riscv,pmpgranularity = <4>; 表示处理器的物理内存保护(PMP)粒度为4字节。
- riscv,pmpregions = <8>; 表示该处理器支持8个PMP区域。
- sifive,dtim = <&L4>; 表示该处理器的数据总线RAM接口使用标签为L4的节点。
- status = "okay"; 表示该处理器节点已启用。
- timebase-frequency = <1000000>; 表示该处理器的时间基准频率。
- L2: 标签“interrupt-controller”表示该节点是一个中断控制器。
- #interrupt-cells = <1>; 表示中断编号单元数为1。
- compatible = "riscv,cpu-intc"; 表示该中断控制器与RISC-V CPU中断控制器兼容。
- interrupt-controller; 表示该节点是一个中断控制器。
- htif:这个DTS片段定义了一个名为"htif"的节点,它具有属性"compatible",其值为"ucb,htif0"。这意味着此节点是兼容于"ucb,htif0"的硬件。 "htif"是"Host-Target Interface"的缩写,用于在主机和目标之间建立通信通道。在此情况下,这个节点可能表示与主机之间的通信接口。
在
soc
节点中,#address-cells
和#size-cells
属性指定了地址和大小的编码方式。compatible
属性指定了 SoC 的类型和所使用的总线类型。ranges
属性可以指定子节点寻址的偏移量和大小的转换。boot-address-reg
子节点描述了启动地址寄存器,用于指定系统启动时的执行位置。clint
子节点是 RISC-V 处理器的计时器和中断控制器,可处理外部中断并在内部生成软件中断,"interrupts-extended"属性列出了与此节点相关联的中断线,指定了中断控制器的编号和每个控制器中断的编号。"reg"属性指定了此节点的物理地址和大小,"reg-names"属性指定了此地址范围的名称。。clock-gater
子节点是 SoC 的时钟门控制器,用于控制时钟的开关和频率。debug-controller
子节点是处理器的调试控制器,用于支持外部调试工具的连接。dtim
子节点是 SoC 的数据存储器,用于存储指令和数据。error-device
子节点是错误信息设备,用于报告硬件错误和异常。
interrupt-controller
子节点是 SoC 的中断控制器,用于处理外部中断并将其分发到适当的处理器或设备。它的地址范围是从 0x0 到 0x1000。该控制器是支持 jtag 连接的,因此debug-attach
属性设置为"jtag"
。此外,它的中断号设置为 65535,即不使用中断。其compatible
属性表示它符合sifive,debug-013
和riscv,debug-013
规范。lbwif-ram
和lbwif-rom
子节点是 SoC 上的 RAM 和 ROM 存储器。lbwif-rom
是一个只读存储器(ROM),用于存储启动代码和固件等固定数据- rom@10000: 这是 SoC 中的另一个 ROM 存储器,其物理地址范围为 0x10000 到 0x20000。
serial
子节点是 SoC 的串行通信设备,用于与外部设备进行通信。subsystem_pbus_clock
子节点是 SoC 的时钟设备,用于控制总线时钟频率。这里定义了一个名为subsystem_pbus_clock的时钟节点,其频率为100MHz。它使用了fixed-clock的驱动程序,并且没有#clock-cells属性,表明它是一个固定频率的时钟。此时钟节点没有父时钟,它是根时钟。tile-reset-setter
子节点是重置控制器,用于重置 SoC 中的各个模块。