linux设备树笔记__dts基本概念及语法

更新时间:2023-07-18 05:56:25 阅读: 评论:0

linux设备树笔记__dts基本概念及语法
设备树⼿册(Device Tree Usage)原⽂地址:
有关device tree数据格式的更完整技术说明,读者可以参考ePAPR规范()
概述:
ARM Device Tree起源于OpenFirmware (OF),在过去的Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着⼤量的垃圾代码,相当多数的代码只是在描述板级细节,⽽这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data。为了改变这种局⾯,Linux社区的⼤⽜们参考了PowerPC等体系架构中使⽤的Flattened Device Tree(FDT),也采⽤了Device Tree结构,许多硬件的细节可以直接透过它传递给Linux,⽽不再需要在kernel中进⾏⼤量的冗余编码。
Device Tree是⼀种描述硬件的数据结构,由⼀系列被命名的结点(node)和属性(property)组成,⽽结点本⾝可包含⼦结点。所谓属性,其实就是成对出现的name和value。在Device Tree中,可描述的信息包括(原先这些信息⼤多被hard code到kernel中):CPU的数量和类别,内存基地址和⼤⼩,总线和桥,外设连接,中断控制器和中断使⽤情况,GPIO控制器和GPIO使⽤情况,Clock控制器和Clock使⽤情况。
通常由.dts⽂件以⽂本⽅式对系统设备树进⾏描述,经过Device Tree Compiler(dtc)将dts⽂件转换成⼆进制⽂件binary device tree blob(dtb),.dtb⽂件可由Linux内核解析,有了device tree就可以在不改动Linux内核的情况下,对不同的平台实现⽆差异的⽀持,只需更换相应的dts⽂件,即可满⾜,当然这样会增加内核的体积。
设备树的存储格式:
如何预防校园暴力
简单的说,设备树是⼀种描述硬件配置的树形数据结构,有且仅有⼀个根节点[4]。它包含了有关CPU、物理内存、总线、串⼝、PHY以及其他外围设备信息等。该树继承了Open Firmware IEEE 1275设备树的定义。操作系统能够在启动时对此结构进⾏语法分析,以此配置内核,加载相应的驱动。
  U-Boot需要将扁平设备树在内存地址传给内核。该树主要由三⼤部分组成:头(Header)、结构块(Structure block)、字符串块(Strings block)。在内存中分配图如下:
------------------------------
ba ->| struct boot_param_header |
------------------------------
|(alignment gap)(*)|
------------------------------
| memory rerve map |
------------------------------
|(alignment gap)|
------------------------------
||
| device-tree structure |
||
------------------------------
|(alignment gap)|
-
-----------------------------
||
| device-tree strings |
||
----->------------------------------
|
|
---(ba + totalsize)
<1> 头(header)
头主要描述设备树的⼀些基本信息,例如设备树⼤⼩,结构块偏移地址,字符串块偏移地址等。偏移地址是相对于设备树头的起始地址计算的。
struct boot_param_header {
__be32 magic;//设备树魔数,固定为0xd00dfeed
__be32 totalsize;//整个设备树的⼤⼩
__be32 off_dt_struct;//保存结构块在整个设备树中的偏移
__be32 off_dt_strings;//保存的字符串块在设备树中的偏移
__be32 off_mem_rsvmap;//保留内存区,该区保留了不能被内核动态分配的内存空间
__be32 version;//设备树版本
__be32 last_comp_version;//向下兼容版本号
__be32 boot_cpuid_phys;//为在多核处理器中⽤于启动的主cpu的物理id
吧的笔顺
__be32 dt_strings_size;//字符串块⼤⼩
__be32 dt_struct_size;//结构块⼤⼩
};
<2> 结构块(struct block)
设备树结构块是⼀个线性化的结构体,是设备树的主体,以节点node的形式保存了⽬标单板上的设备信息。
在结构块中以宏OF_DT_BEGIN_NODE标志⼀个节点的开始,以宏OF_DT_END_NODE标识⼀个节点的结束,整个结构块以宏OF_DT_END结束。⼀个节点主要由以下⼏部分组成。定语的顺序
什么狗粮品牌好(1)节点开始标志:⼀般为OF_DT_BEGIN_NODE。
(2)节点路径或者节点的单元名(v ersion<3以节点路径表⽰,version>=0x10以节点单元名表⽰)
(3)填充字段(对齐到四字节)
(4)节点属性。每个属性以宏OF_DT_PROP开始,后⾯依次为属性值的字节长度(4字节)、属性名称在字符串块中的偏移量(4字节)、属性值和填充(对齐到四字节)。
(5)如果存在⼦节点,则定义⼦节点。
(6)节点结束标志OF_DT_END_NODE。
<3>字符串块
污染的近义词
通过节点的定义知道节点都有若⼲属性,⽽不同的节点的属性⼜有⼤量相同的属性名称,因此将这些属性名称提取出⼀张表,当节点需要应⽤某个属性名称时直接在属性名字段保存该属性名称在字符串块中的偏移量。
<4> 设备树源码 DTS 表⽰
设备树源码⽂件(.dts)以可读可编辑的⽂本形式描述系统硬件配置设备树,⽀持 C/C++⽅式的注释,该结构有⼀个唯⼀的根节点“/”,每个节点都有⾃⼰的名字并可以包含多个⼦节点。设备树的数据格式遵循了 Open Firmware IEEE standard 1275。这个设备树中有很多节点,每个节点都指定了节点单元名称。每⼀个属性后⾯都给出相应的值。以双引号引出的内容为ASCII 字符串,以尖括号给出的是 32 位的16进制值。这个树结构是启动 Linux 内核所需节点和属性简化后的集合,包括了根节点的基本模式信息、CPU 和物理内存布局,它还包括通过/chon 节点传递给内核的命令⾏参数信息。
<5> machine_desc结构
内核提供了⼀个重要的结构体struct machine_desc ,这个结构体在内核移植中起到相当重要的作⽤,内核通过machine_desc结构体来控制系统体系架构相关部分的初始化。machine_desc结构体通过MA
CHINE_START宏来初始化,在代码中,通过在start_kernel->tup_arch中调⽤tup_machine_fdt来获取。
struct machine_desc {
unsigned int nr;/* architecture number */
const char *name;/* architecture name */
unsigned long atag_offt;/* tagged list (relative)*/
const char *const*dt_compat;/*array of device tree*'compatible' strings */
unsigned int nr_irqs;/* number of IRQs */
#ifdef CONFIG_ZONE_DMA
phys_addr_t dma_zone_size;/* size of DMA-able area */
#endif
unsigned int video_start;/* start of video RAM */
unsigned int video_end;/*end of video RAM */
unsigned char rerve_lp0 :1;/* never has lp0 */
unsigned char rerve_lp1 :1;/* never has lp1 */
unsigned char rerve_lp2 :1;/* never has lp2 */
enum reboot_mode reboot_mode;/* default restart mode */
struct smp_operations *smp;/* SMP operations */
bool (*smp_init)(void);
void (*fixup)(struct tag *, char **,struct meminfo *);
void (*init_meminfo)(void);
void (*rerve)(void);/* rerve mem blocks */
void (*map_io)(void);/* IO mapping function*/
void (*init_early)(void);
void (*init_irq)(void);
void (*init_time)(void);
void (*init_machine)(void);
void (*init_late)(void);
#ifdef CONFIG_MULTI_IRQ_HANDLER
void (*handle_irq)(struct pt_regs *);
#endif
void (*restart)(enum reboot_mode,const char *);
};
<6>设备节点结构体
struct device_node {
const char *name;//设备name
圆柱的底面积
const char *type;//设备类型
phandle phandle;
const char *full_name;//设备全称,包括⽗设备名
struct property*properties;//设备属性链表
struct property*deadprops;//removed properties
struct device_node *parent;//指向⽗节点
struct device_node *child;//指向⼦节点
struct device_node *sibling;//指向兄弟节点
struct device_node *next;//相同设备类型的下⼀个节点
秋景struct device_node *allnext;//next in list of all nodes
struct proc_dir_entry *pde;//该节点对应的proc
struct kref kref;
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
const char *path_component_name;
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
<7>属性结构体
struct property{
char *name;//属性名
int length;//属性值长度
void *value;//属性值
struct property*next;//指向下⼀个属性
unsigned long _flags;//标志
unsigned int unique_id;
};
基本数据格式
————————————————————————————————
device tree是⼀个简单的节点和属性树,属性是键值对,节点可以包含属性和⼦节点。下⾯是⼀个.dts格式的简单设备树。
该树并未描述任何东西,也不具备任何实际意义,但它却揭⽰了节点和属性的结构。即:
⼀个的根节点:'/',两个⼦节点:node1和node2;node1的⼦节点:child-node1和child-node2,⼀些属性分散在树之间。
属性是⼀些简单的键值对(key-value pairs):value可以为空也可以包含任意的字节流。⽽数据类型并没有编码成数据结构,有⼀些基本数据表⽰可以在device tree源⽂件中表⽰。
⽂本字符串(null 终⽌)⽤双引号来表⽰:string-property = "a string"
“Cells”是由尖括号分隔的32位⽆符号整数:cell-property = <0xbeef 123 0xabcd1234>
⼆进制数据是⽤⽅括号分隔:binary-property = [0x01 0x23 0x45 0x67];
不同格式的数据可以⽤逗号连接在⼀起:mixed-property = "a string", [0x01 0x23 0x45 0x67], <0x12345678>;
逗号也可以⽤来创建字符串列表:string-list = "red fish", "blue fish";
基本概念
————————————————————————————————
为了帮助理解device tree的⽤法,我们从⼀个简单的计算机开始,⼿把⼿创建⼀个device tree来描述它。
例⼦
假设有这样⼀台计算机(基于ARM Versatile),由“Acme”制造并命名为"Coyote's Revenge":
⼀个32位的ARM CPU
所以的笔顺
连接到内存映射串⾏端⼝的处理器本地总线(processor local bus),spi bus controller, i2c controller, interrupt controller, 和external bus bridge 256MB SDRAM,起始地址为0
两个串⼝起始地址为0x101F1000,0x101F2000
GPIO controller,起始地址为0x101F3000
SPI controller起始地址为0x10170000,并挂载以下设备:
MMC插槽(SS管脚连接到GPIO #1)
External bus bridge,挂载以下设备:
SMC SMC91111以太⽹设备连接到external bus,基地址0x10100000
i2c controller起始地址为0x10160000,并挂载以下设备:
Maxim DS1338 real time clock.响应从机地址1101000 (0x58)
64MB NOR flash,基地址0x30000000
初始结构
第⼀步,先构建⼀个计算机的基本架构,即⼀个有效设备树的最⼩架构。在这⼀步,要唯⼀地标志这台计算机。
compatible属性以"<manufacturer>,<model>"的格式指定了系统名称。指定了具体设备和制造商名称来避免命名空间的冲突是很重要的,因为⼀个操作系统可以使⽤compatible值来决定如何运⾏这台计算机,在该属性中填⼊正确的数据很重要。理论上,compatible是⼀个OS唯⼀地识别⼀台计算机所需要的所有数据。如果计算机的所有细节都被硬编码,那么OS可以在顶层compatible属性中专门查找"acme,coyotes-revenge"。
CPU
接下来就要描述各个CPU了。先添加⼀个“cpus”容器节点,再将每个CPU作为⼦节点添加。在本例中,系统是基于ARM的双核Cortex A9系统。
各个CPU节点的compatible属性是⼀个字符串,与顶层compatible属性类似,该字符串以“<manufacturer>,<model>”的格式指定了CPU的确切型号。
随后更多的属性被添加到cpu节点,但⾸先我们需要先了解⼀些基本概念。
节点命名
花些时间谈谈命名习惯是值得的。每个节点都必须有⼀个<name>[@<unit-address>]格式的名称。<n
ame>是⼀个简单的ascii字符串,最长为31个字符,总的来说,节点命名是根据它代表什么设备。⽐如说,⼀个代表3com以太⽹适配器的节点应该命名为ethernet,⽽不是3com509。
如果节点描述的设备有地址的话,就应该加上unit-address,unit-address通常是⽤来访问设备的主地址,并在节点的reg属性中被列出。后⾯我们将谈到reg属性。
同级节点的命名必须是唯⼀,但多个节点的通⽤名称可以相同,只要地址不同就⾏。(即rial@101f1000 & rial@101f2000)。
关于节点命名的全部细节请参考ePAPR规范2.2.1节。
设备
系统中的每个设备由device tree的⼀个节点来表⽰,接下来将为设备树添加设备节点。在我们讲到如何寻址和如何处理中断之前,暂时将新节点置空。

本文发布于:2023-07-18 05:56:25,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1102572.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:节点   设备   属性   内核   地址
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图