5. 设备树的规范 - DTS格式

一、概述

     ARM Device Tree起源于OpenFirmware (OF),在Linux 2.6中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件platform_data。常见的s3c2410、s3c6410等板级目录,代码量在数万行。
     Linus Torvalds对于此种情况大发雷霆,在2011年的ARM Linux邮件列表宣称this whole ARM thing is a f*cking pain in the ass”。
     所以Linux开发社区就开始整改,设备树最早用于PowerPC等其他体系架构,ARM架构开发社区就开始采用设备树来描述设备的信息。

二、设备树结构

      Device Tree是一种描述硬件的数据结构,由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的namevalue。在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文件,即可满足。
      设备树信息被保存在一个ASCII 文本文件中,适合人类的阅读习惯,类似于xml文件, 在ARM Linux中,一个.dts文件对应一个ARMmachine放置在内核的arch/arm/boot/dts/目录。

三、设备树语法

3.1 节点node

3.2 属性property

属性拥有两种格式:
Property格式1(没有值) : [label:] property-name;
Property格式2(键值对) : [label:] property-name = value;;

四、设备树实例

下述例子译自: http://elinux.org/Device_Tree_Usage

下面给出一个例子,从0开始描述如何写一个完整的设备树。现在有个arm平台的板子,假设制造商为“acme”我们给他命名为“Coyote's Revenge”首先,假设我们有如下的硬件平台:

  • 一颗 32bit ARM CPU

  • 处理器本地总线上映射了串口SPI控制器、I2C控制器、中断控制器以及外部总线桥。

  • 基地址为0,大小为256MB的SDRAM

  • 基地址分别为0x101F1000 和0x101F2000的2个串口

  • 基地址为0x101F3000 GPIO控制器

  • 基地址为0x10170000的SPI 控制器上有如下的设备:

  • MMC 卡槽的SS引脚连接到了GPIO #1

  • 外部总线桥上有如下的设备:

  • SMC公司生产的SMC91111 Ethernet,其基地址为0x10100000。

  • 在基地址为0x10160000的 i2c 控制器有如下设备:

  • 美信公司的DS1338 实时时钟芯片. 从站相应地址为0x58

  • 大小为64MB 的 NOR flash 其基地址为0x30000000

下面将按照上面的描述信息,写一个DTS文件。

初始化结构体
首先先给整个设备树写一个框架如下所示:

/dts-v1/;

/ {
    compatible ="acme,coyotes-revenge";
};

上面首先在根节点下写了一个属性compatible,该属性是系统用来识别不同板级设备的重要依据,其一般由厂商名和样板名两部分组成,比如在上面我们的制造商为acme板子的名字叫做coyotes-revenge。
加入CPU
假如我们的CPU是一颗双核A9的CPU,我们添加一个叫”cpus”的子节点,具体如下:

/dts-v1/;

/ {

    compatible ="acme,coyotes-revenge";

    cpus {
       cpu@0 {
           compatible = "arm,cortex-a9";
       };

       cpu@1 {
           compatible = "arm,cortex-a9";
       };
    };
};

cpu的compatible设置与顶层的类似,有两部分组成。Arm描述了制造商,cortex-a9指明了型号。

系统中每个设备都是依靠设备树节点来描述的,接下来就要添加一些设备节点来描述每一个设备:

/dts-v1/;

/ {

    compatible = "acme,coyotes-revenge";

    cpus {

        cpu@0 {

           compatible = "arm,cortex-a9";

        };

        cpu@1 {

           compatible = "arm,cortex-a9";

        };

    };

    serial@101F0000{

       compatible = "arm,pl011";

    };

   serial@101F2000 {

       compatible = "arm,pl011";

    };

   gpio@101F3000 {

       compatible = "arm,pl061";

    };

   interrupt-controller@10140000 {

       compatible = "arm,pl190";

    };

   spi@10115000 {

       compatible = "arm,pl022";

    };

    external-bus {

       ethernet@0,0 {

           compatible = "smc,smc91c111";

       };

       i2c@1,0 {

           compatible = "acme,a1234-i2c-bus";

           rtc@58 {

                compatible ="maxim,ds1338";

           };

      };

        flash@2,0 {

           compatible = "samsung,k8f1315ebm","cfi-flash";

       };

    };

};

通过上面的列表可以看出来,通过dts的层次关系,可以看到具体的板级的设备连接关系,比如外部总线上有ethercat、i2c和flash三个设备。

但是上面描述的这课树还不是一个完整有效的设备树,因此他缺少必要的连接方式、地址信息等。稍后会加上这些信息。
理解Compatible
每个设备节点都会有compatible属性, 设备与驱动之间的结合就依赖这个属性的匹配。

Compatible属性是由字符串列表组成,就像上面列出的flash节点,compatible有两个属性值,以一个字符串确切的表示该设备的信息,第二个字符串描述的与该节点描述符相兼容的设备。
设备如何寻址
设备寻址地址在设备树中通过如下的属性信息来表示:
reg

address-cells

size-cells

每一个可寻址设都会有一个reg属性,该属性有一个或多个元素组成,其基本格式为:
reg =<address1 length1 [address2 length2] [address3 length3] ... >
上面的每一个元素都代表设备的寻址地址及其寻址大小,每一个元素中的address值可以是一个或者多个无符号32位整形数据类型cell来表示,元素中的length可以为空也可以使一个或者多个无符号32位整形数据类型cell。
由于每个可寻址设备都会有reg属性可设置,而且reg属性元素也是灵活可选择的,那么谁来制定reg属性元素中每个元素也就是address和length的个数呢?
在这里,要关注到期父节点的两个属性,其中#address-cells表示reg中address元素的个数,#size-cells用来表示length元素的个数。
为了展示刚刚接手实行的作用,那么现在做一个演示,首先从cpu节点开始演示:
CPU 寻址地址
对于寻址地址的编写,cpu节点是最简单的一个例子,之前介绍,而每个cpu节点都包含一个标记ID,但是没有其他的描述信息,这里填充一些其他的属性:

 cpus {

        #address-cells= <1>;

       #size-cells = <0>;

        cpu@0 {

           compatible = "arm,cortex-a9";

            reg= <0>;

        };

        cpu@1 {

           compatible = "arm,cortex-a9";

            reg= <1>;

        };

    };

在cpus节点 #address-cells 赋予 1, #size-cells 赋予 0.。这意味着在其子节点的reg只有一个地址元素值,没有长度元素值。在这个案例当中,两颗cpu核的地址分别呗分配成0和1。因为每个cpu只分配了地址,所以节点 #size-cells元素被设置为 0。

内存映射设备
需要内存映射的设备不同于上面的cpu节点,这类的设备需要一段内存而不是单一的内存地址,因此不近需要包含内存的基地址还而且还需要映射地址的长度,因此需要使用 #size-cells属性来表示reg属性元素中表示地址长度元素的个数。在下面的例子中,每一个节点的address值有一个32位无符号整形数据而且length值也是用一个32位无符号整形数据来表示。因此在32的系统中 #address-cells 和#size-cells都要设置为1,但是在64位系统中 #address-cells就要设置成2了。具体设置如下:

/dts-v1/;
/ {

    #address-cells= <1>;
    #size-cells = <1>;

    ...
    serial@101f0000{
        compatible= "arm,pl011";
        reg =<0x101f0000 0x1000 >;
    };
 
    serial@101f2000{
        compatible= "arm,pl011";
        reg =<0x101f2000 0x1000 >;
    };

    gpio@101f3000 {
        compatible= "arm,pl061";
        reg =<0x101f3000 0x1000
              0x101f4000 0x0010>;
    };

   interrupt-controller@10140000 {
        compatible= "arm,pl190";
        reg =<0x10140000 0x1000 >;
    };

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

上面的例子中reg属性都有address元素和length属性,值的注意的是,例子中的GPIO被分配了两个地址范围,分别是 0x101f3000...0x101f3fff 以及0x101f4000..0x101f400f。

有一些设备可能有不同的寻址方案,比如一个设备挂载到总线上连接一个片选信号线,可以通过片选信号选择不同的设备。由于父节点可以定义了其子节点的地址映射域,所以可以选择最适合的一项来描述硬件设备。下面的代码就是把片选号码编入地址码挂载到外部总线上的一个设备。

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";
            reg = <1 0 0x1000>;
            rtc@58{
               compatible = "maxim,ds1338";
            };

        };

        flash@2,0 {
            compatible= "samsung,k8f1315ebm", "cfi-flash";
            compatible= <2 0 0x4000000>;

        };

    };

上面的代码中, #address-cells 属性为2,则表示reg属性的address有两个地址域,其中一个表示片选号,另一个表示设备到片选基地址的偏移量,#size-cells为1,其地址范围量的个数还是一个32位的无符号整数。所以最后reg有三个属性值,分别表示片选号、偏移量、地址范围。

无内存映射设备
其他的一些设备,他们在处理器总线瓶没有内存映射。他们拥有地址范围但是他们不被cpu直接的访问,而是被父设备驱动替代cpu进行访问。

举个例子,对于i2c设备,每个设备都会有一个指定的访问地址,但是这些设备不会有相关联的范围或者地址长度,这有点类似cpu节点地址分配。如下是具体代码的例子:

 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>;
            };
        };



参考:
https://blog.csdn.net/sgmenghuo/article/details/45071615
https://blog.csdn.net/woshidahuaidan2011/article/details/52948732
设备树使用文档

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容