Device Tree(二):基本概念

发布者:石头上种庄稼最新更新时间:2023-09-30 来源: elecfans关键字:Device  Tree  基本概念 手机看文章 扫描二维码
随时随地手机看文章

一、前言

一些背景知识(例如:为何要引入Device Tree,这个机制是用来解决什么问题的)请参考引入Device Tree的原因,本文主要是介绍Device Tree的基础概念。

简单的说,如果要使用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。

本文主要描述下面两个主题:

1、Device Tree source file语法介绍

2、Device Tree binaryfile格式介绍

 

二、Device Tree的结构

在描述Device Tree的结构之前,我们先问一个基础问题:是否Device Tree要描述系统中的所有硬件信息?答案是否定的。基本上,那些可以动态探测到的设备是不需要描述的,例如USB device。不过对于SOC上的usb host controller,它是无法动态识别的,需要在device tree中描述。同样的道理,在computer system中,PCI device可以被动态探测到,不需要在device tree中描述,但是PCI bridge如果不能被探测,那么就需要描述之。

为了了解Device Tree的结构,我们首先给出一个Device Tree的示例:

/ o device-tree 
      |- name = "device-tree" 
      |- model = "MyBoardName" 
      |- compatible = "MyBoardFamilyName" 
      |- #address-cells = <2> 
      |- #size-cells = <2> 
      |- linux,phandle = <0> 
      | 
      o cpus 
      | | - name = "cpus" 
      | | - linux,phandle = <1> 
      | | - #address-cells = <1> 
      | | - #size-cells = <0> 
      | | 
      | o PowerPC,970@0 
      |   |- name = "PowerPC,970" 
      |   |- device_type = "cpu" 
      |   |- reg = <0> 
      |   |- clock-frequency = <0x5f5e1000> 
      |   |- 64-bit 
      |   |- linux,phandle = <2> 
      | 
      o memory@0 
      | |- name = "memory" 
      | |- device_type = "memory" 
      | |- reg = <0x00000000 0x00000000 0x00000000 0x20000000>
      | |- linux,phandle = <3> 
      | 
      o chosen 
        |- name = "chosen" 
        |- bootargs = "root=/dev/sda2" 
        |- linux,phandle = <4>

从上图中可以看出,device tree的基本单元是node。这些node被组织成树状结构,除了root node,每个node都只有一个parent。一个device tree文件中只能有一个root node。每个node中包含了若干的property/value来描述该node的一些特性。每个node用节点名字(node name)标识,节点名字的格式是node-name@unit-address。如果该node没有reg属性(后面会描述这个property),那么该节点名字中必须不能包括@和unit-address。unit-address的具体格式是和设备挂在那个bus上相关。例如对于cpu,其unit-address就是从0开始编址,以此加一。而具体的设备,例如以太网控制器,其unit-address就是寄存器地址。root node的node name是确定的,必须是“/”。

在一个树状结构的device tree中,如何引用一个node呢?要想唯一指定一个node必须使用full path,例如/node-name-1/node-name-2/node-name-N。在上面的例子中,cpu node我们可以通过/cpus/PowerPC,970@0访问。

属性(property)值标识了设备的特性,它的值(value)是多种多样的:

1、可能是空,也就是没有值的定义。例如上图中的64-bit ,这个属性没有赋值。

2、可能是一个u32、u64的数值(值得一提的是cell这个术语,在Device Tree表示32bit的信息单位)。例如#address-cells = <1> 。当然,可能是一个数组。例如<0x00000000 0x00000000 0x00000000 0x20000000>

4、可能是一个字符串。例如device_type = "memory" ,当然也可能是一个string list。例如"PowerPC,970"

 

三、Device Tree source file语法介绍

了解了基本的device tree的结构后,我们总要把这些结构体现在device tree source code上来。在linux kernel中,扩展名是dts的文件就是描述硬件信息的device tree source file,在dts文件中,一个node被定义成:

[label:] node-name[@unit-address] { 
   [properties definitions] 
   [child nodes] 
}

“[]”表示option,因此可以定义一个只有node name的空节点。label方便在dts文件中引用,具体后面会描述。child node的格式和node是完全一样的,因此,一个dts文件中就是若干嵌套组成的node,property以及child note、child note property描述。

考虑到空泛的谈比较枯燥,我们用实例来讲解Device Tree Source file 的数据格式。假设蜗窝科技制作了一个S3C2416的开发板,我们把该development board命名为snail,那么需要撰写一个s3c2416-snail.dts的文件。如果把所有的开发板的硬件信息(SOC以及外设)都描述在一个文件中是不合理的,因此有可能其他公司也使用S3C2416搭建自己的开发板并命令pig、cow什么的,如果大家都用自己的dts文件描述硬件,那么其中大部分是重复的,因此我们把和S3C2416相关的硬件描述保存成一个单独的dts文件可以供使用S3C2416的target board来引用并将文件的扩展名变成dtsi(i表示include)。同理,三星公司的S3C24xx系列是一个SOC family,这些SOCs(2410、2416、2450等)也有相同的内容,因此同样的道理,我们可以将公共部分抽取出来,变成s3c24xx.dtsi,方便大家include。同样的道理,各家ARM vendor也会共用一些硬件定义信息,这个文件就是skeleton.dtsi。我们自下而上(类似C++中的从基类到顶层的派生类)逐个进行分析。

1、skeleton.dtsi。位于linux-3.14archarmbootdts目录下,具体该文件的内容如下:

/ { 
    #address-cells = <1>; 
    #size-cells = <1>; 
    chosen { }; 
    aliases { }; 
    memory { device_type = "memory"; reg = <0 0>; }; 
};

device tree顾名思义是一个树状的结构,既然是树,必然有根。“/”是根节点的node name。“{”和“}”之间的内容是该节点的具体的定义,其内容包括各种属性的定义以及child node的定义。chosen、aliases和memory都是sub node,sub node的结构和root node是完全一样的,因此,sub node也有自己的属性和它自己的sub node,最终形成了一个树状的device tree。属性的定义采用property = value的形式。例如#address-cells和#size-cells就是property,而<1>就是value。value有三种情况:

1)属性值是text string或者string list,用双引号表示。例如device_type = "memory"

2)属性值是32bit unsigned integers,用尖括号表示。例如#size-cells = <1>

3)属性值是binary data,用方括号表示。例如binary-property = [0x01 0x23 0x45 0x67]

如果一个device node中包含了有寻址需求(要定义reg property)的sub node(后文也许会用child node,和sub node是一样的意思),那么就必须要定义这两个属性。“#”是number的意思,#address-cells这个属性是用来描述sub node中的reg属性的地址域特性的,也就是说需要用多少个u32的cell来描述该地址域。同理可以推断#size-cells的含义,下面对reg的描述中会给出更详细的信息。

chosen node主要用来描述由系统firmware指定的runtime parameter。如果存在chosen这个node,其parent node必须是名字是“/”的根节点。原来通过tag list传递的一些linux kernel的运行时参数可以通过Device Tree传递。例如command line可以通过bootargs这个property这个属性传递;initrd的开始地址也可以通过linux,initrd-start这个property这个属性传递。在本例中,chosen节点是空的,在实际中,建议增加一个bootargs的属性,例如:

"root=/dev/nfs nfsroot=1.1.1.1:/nfsboot ip=1.1.1.2:1.1.1.1:1.1.1.1:255.255.255.0::usbd0:off console=ttyS0,115200 mem=64M@0x30000000"

通过该command line可以控制内核从usbnet启动,当然,具体项目要相应修改command line以便适应不同的需求。我们知道,device tree用于HW platform识别,runtime parameter传递以及硬件设备描述。chosen节点并没有描述任何硬件设备节点的信息,它只是传递了runtime parameter。

aliases 节点定义了一些别名。为何要定义这个node呢?因为Device tree是树状结构,当要引用一个node的时候要指明相对于root node的full path,例如/node-name-1/node-name-2/node-name-N。如果多次引用,每次都要写这么复杂的字符串多少是有些麻烦,因此可以在aliases 节点定义一些设备节点full path的缩写。skeleton.dtsi中没有定义aliases,下面的section中会进一步用具体的例子描述之。

memory device node是所有设备树文件的必备节点,它定义了系统物理内存的layout。device_type属性定义了该node的设备类型,例如cpu、serial等。对于memory node,其device_type必须等于memory。reg属性定义了访问该device node的地址信息,该属性的值被解析成任意长度的(address,size)数组,具体用多长的数据来表示address和size是在其parent node中定义(#address-cells和#size-cells)。对于device node,reg描述了memory-mapped IO register的offset和length。对于memory node,定义了该memory的起始地址和长度。

本例中的物理内存的布局并没有通过memory node传递,其实我们可以使用command line传递,我们command line中的参数“mem=64M@0x30000000”已经给出了具体的信息。我们用另外一个例子来加深对本节描述的各个属性以及memory node的理解。假设我们的系统是64bit的,physical memory分成两段,定义如下:

RAM: starting address 0x0, length 0x80000000 (2GB) 
RAM: starting address 0x100000000, length 0x100000000 (4GB)

对于这样的系统,我们可以将root node中的#address-cells和#size-cells这两个属性值设定为2,可以用下面两种方法来描述物理内存:

方法1:

memory@0 { 
    device_type = "memory"; 
    reg = <0x000000000 0x00000000 0x00000000 0x80000000 
              0x000000001 0x00000000 0x00000001 0x00000000>; 
};

方法2:

memory@0 { 
    device_type = "memory"; 
    reg = <0x000000000 0x00000000 0x00000000 0x80000000>; 
};

memory@100000000 { 
    device_type = "memory"; 
    reg = <0x000000001 0x00000000 0x00000001 0x00000000>; 
};

2、s3c24xx.dtsi。位于linux-3.14archarmbootdts目录下,具体该文件的内容如下(有些内容省略了,领会精神即可,不需要描述每一个硬件定义的细节):

#include "skeleton.dtsi"

/ { 
    compatible = "samsung,s3c24xx"; -------------------(A) 
    interrupt-parent = <&intc>; ----------------------(B)

    aliases { 
        pinctrl0 = &pinctrl_0; ------------------------(C) 
    };

    intc:interrupt-controller@4a000000 { ------------------(D) 
        compatible = "samsung,s3c2410-irq"; 
        reg = <0x4a000000 0x100>; 
        interrupt-controller; 
        #interrupt-cells = <4>; 
    };

    serial@50000000 { ----------------------(E)  
        compatible = "samsung,s3c2410-uart"; 
        reg = <0x50000000 0x4000>; 
        interrupts = <1 0 4 28>, <1 1 4 28>; 
        status = "disabled"; 
    };

    pinctrl_0: pinctrl@56000000 {------------------(F) 
        reg = <0x56000000 0x1000>;

        wakeup-interrupt-controller { 
            compatible = "samsung,s3c2410-wakeup-eint"; 
            interrupts = <0 0 0 3>,
                     <0 0 1 3>,
                     <0 0 2 3>,
                     <0 0 3 3>,
                     <0 0 4 4>,
                     <0 0 5 4>;
        }; 
    };

[1] [2]
关键字:Device  Tree  基本概念 引用地址:Device Tree(二):基本概念

上一篇:串口0作为调试端口,怎么改变为接收数据接口
下一篇:linux-3.0移植到FL2440(只做基本的移植)

推荐阅读最新更新时间:2024-11-17 05:21

2440/2410上将usb device改成usb host
之前的开发,要在2440上使用两个usb host口,一个接摄像头,一个接无线网卡。但友善之臂mini2440板子只有一个usb host口,曾想通过外接一个usb hub来解决,无线网卡接hub没有问题,但是摄像头插到hub上总是有错误: usb 1-1: reset full speed USB device using s3c2410-ohci and address 3 usb 1-1.2: new full speed USB device using s3c2410-ohci and address 4 usb 1-1.2: device descriptor read/64, error
[单片机]
嵌入式-ARM寄存器基本概念
无论是学习哪一种处理器,首先需要明确的就是这种处理器的寄存器以及工作模式。 ARM有37个寄存器,其中31个通用寄存器,6个状态寄存器。 这里尤其要注意区别的是ARM自身寄存器和它的一些外设的寄存器的区别。 ARM自身是统一架构的,也就意味着37个寄存器无论在哪个公司的芯片里面都会出现。但是各家公司会对ARM进行外设的扩展,所以就出现了好多外设寄存器,一定要与这37个寄存器区别开来!!! 1、备份寄存器(R8-R14) 对于R8-R12来说,除在快速中断模式下,每个模式对应相同物理寄存器,所以在FIQ模式下可不必保护和恢复中断现场。 对于R13-R14来说,每个寄存器对应6个不同的物理寄存器,其中一个是用户模式和系
[嵌入式]
基于tiny4412的Linux内核移植(支持device tree)(二)
平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本:Linux-4.4.0 (支持device tree) u-boot版本:友善之臂自带的 U-Boot 2010.12 (为支持uImage启动,做了少许改动) busybox版本:busybox 1.25 交叉编译工具链: arm-none-linux-gnueabi-gcc (gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29)) 步骤 继续上文。 由于Linux-4.4.0对tiny4412已经有了很好的支持,所以留给我
[单片机]

推荐帖子

新手共同进步——对CubeSuite+软件的一些见解
打开该软件,就有一种似曾相识的感觉,很像大家广泛使用的uVsion,,本以为很容易上手的。可是随着对该软件的使用,慢慢发现该软件很难使用,装驱动就算了,换了芯片,还需要更新固体,真心麻烦,程序不能在软件里选了型号以后下载进去吗。。。在这里,我觉得PIC要做得更好些,集成开发环境,驱动管理,仿真。。。细分以后,让使用者更好使用该公司的服务,现在,我都不清楚我现在还需要安装什么库或者软件来支持CubeSuite+来让我能够正常使用该软件带来的服务。而且,看了网友的帖子,据说该软件CFP(程
不足论 瑞萨电子MCU
数字电源 第2版 PCB到手了。
本帖最后由dontium于2013-12-2811:34编辑 昨天晚上收到了PCB,申通真慢,路上用了4X24小时。1、概况2、正面3、简单说明4、背面数字电源第2版PCB到手了。本帖最后由dontium于2013-12-2811:53编辑 PCB使用三片,剩余七片。有愿意一起DIY者,以成本(5元)价出。板上的其它元器件,可以出两套,均以购入价漂亮!!等待调试参数不错~~~看来DT版主春节前可完工xuyiyi
dontium DIY/开源硬件专区
关于ARM的中断服务程序
 这个2440test里面的中断写的向量有些隐蔽,兜了很多个圈,也难怪这么难理解,下面就对这个东西抽丝剥茧,看清楚这究竟是一个怎么样的过程。  中断向量  bHandlerIRQ;handlerforIRQinterrupt很自然,因为所有的单片机都是那样,中断向量一般放在开头,用过单片机的人都会很熟悉那就不多说了。  异常服务程序  这里不用中断(interrupt)而用异常(exception),毕竟中断只是异常的一种情况,呵呵下面主要分析的是
Aguilera 微控制器 MCU
MJE13009-TO220供应
本帖最后由jameswangsynnex于2015-3-320:01编辑MJE13009-TO220产品类型节能灯用晶体管/硅NPN半导体三极管型号MJE13009-TO220品牌蓝箭封装形式插件型Vceb700VVceo400VVebo9.0VIc12A主要用途:适用于节能灯、电子镇流器、充电器及各类功率开关电路。主要特点:击穿电压高
TGWN123456 移动便携
【芯币兑换】AVR ATmega16学习板标准原理图
下面是最终版原理图,请大家参考【芯币兑换】AVRATmega16学习板标准原理图先把资料下载了,然后继续等待板子ING,就快收到板子了,激动ING。。。原帖由fengxin于2010-8-714:22发表先把资料下载了,然后继续等待板子ING,就快收到板子了,激动ING。。。呵呵,最新消息:元器件已经齐套了,下周可以发了回复板凳tiankai001的帖子呵呵,等待板子了。。。回复板凳tiankai001的帖子不知道有没有一整套学
tiankai001 Microchip MCU
【得捷电子Follow me第1期】+ 提交贴
##项目描述使用RaspberryPicoW控制板板载的无线模块连接WIFI进行时间同步,通过串口连接Grove-GPS(Air530)模块获取定位信息,并转化为具体的城市位置,然后再通过和风天气提供的天气接口https://dev.qweather.com/docs/api/weather/weather-now/,获取城市当前的天气信息,并通过I2C接口连接的OLED进行显示。设备在运行过程中每一分钟进行一次位置更新,每一个小时进行一次时间同步和天气更新。
ID.LODA DigiKey得捷技术专区
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved