ARM设备树解析

linux-4.8.5\arch\arm\boot\dts ARM设备树文件所在位置
include/linux目录下的of_xxx.h为设备树函数头文件所在位置

概念

设备树是一种描述硬件的数据结构,采用设备树后,许多硬件的细节可以直接通过它传给Linux。

组成

 它是由命令的节点(Node)和属性(Property)组成,而节点本身可以包含子节点。

DTS文件
(Device Tree Source,dts)是以ASCII文本形式描述设备树内容。
DTB文件
dtb文件是二进制格式,编译工具为:Device Tree Compiler(DTC)。
DTSI文件
dtsi文件则类似C语言的头文件,其他设备包含了这个文件。

包含信息

  • CPU的数量和类别
  • 内存基地址和大小
  • 总线和桥
  • 外设连接
  • 中断控制器和中断使用情况
  • GPIO控制器和GPIO使用情况
  • 时钟控制器和时钟使用情况

设备树语法解析

基本结构

/{                            /*根节点*/
    node{                     /*子节点*/
        key=value;  
        child_node{         /*node的子节点*/
            key=value;
            ...
        }
        ....
    }
.....
}

节点名

语法:<name>[@]
eg:serial@1111000

一般名字我们以设备类型命名,unit-address一般是设备地址

节点地址

/{
    ethernet@800000000{
        ...
    }
}

节点路径:/ethernet@800000000

节点描述

头文件:include/of.h
struct device_node {
    const char *name;                 //节点名
    const char *type;                 //设备类型
    const char *full_name;            //全路径节点名
    struct  device_node *parent;      //父节点指针
    struct  device_node *child;       //子节点指针
    ...
}

节点引用

为了解决节点路径过长的问题,引入了节点别名的概念。

demo:demo@80000000{
....
}
在这里demo就是节点demo@80000000的别名
也可以这样: demo = &demo0 

那么如何引用呢?

&demo{
    ...
}
或者
{
    property=<&demo>;
}

在第二个例子中,property应用了demo节点的内容,一般情况,引用其他节点的目的是使用其节点的部分属性内容。

节点合并、替换

先编写好节点,仅仅描述部分属性值;使用者后加一部分属性值。在同级路径下,节点名相同的“两个”节点实际是一个节点。
前提:节点名相同
合并:取一个和原属性不同的名字;
替换:取一个和原属性一样的名字;

chosen节点

chosen{
    bootargs = "root=/dev/nfs........."
}

chosen节点描述的不是一个真实的设备,而是通过firmware传递一些参数给内核,例如传递bootargs给内核启动参数。

属性

/{
    #address-cells = <1>;
    #size-cells = <0>;
    son-node {
        compatible = "arm,cortex-a9";
        reg = <addr1 len1[addr2 len2]>;
    };
};

#address-cells:描述子节点reg属性值的地址表中的首地址cell数量
#size-cells:描述子节点reg属性值的地址表中地址长度cell数量

在上面的示例中,子节点cpu0中有属性,地址表这些成员,下面一个个详细分析。

属性-compatible

驱动自定义属性
ARM设备树解析_第1张图片
有些属性很难通用,需要驱动自己定义好,可以通过内核的属性提取解析函数得到属性。

compatible属性

/{
    node{
        compatible="厂商名,名称";
        };
        .....
};

属性-address

在描述一个设备内存地址的时候,经常一个cell(32bits)描述地址,紧接着一个cell(32bits)描述地址长度。

reg = <0x101f3000 0x1000
       0x101f4000 0x2000>

#address-cells:描述子节点reg属性值的地址表中首地址cell数量
#size-cells:描述子节点reg属性值的地址表中地址长度cell数量
有时reg中会把size省略掉。
另外,譬如i2c设备,有一个寻址地址,没有内存地址那样的地址长度和范围,一般使用1个cell(32bits)描述该地址,而没有描述地址长度的cell。
地址转换范围Ranges
有些设备是有片选的,就需要描述片选及片选的偏移量,在说明地址时,还需要说明地址映射范围。

ranges = <0 0 0x10100000 0x10000 //片选 片选偏移量 地址  地址长度
          1 0 0x10160000 0x10000
          2 0 0x30000000 0x100000
        >
reg = <0 0 0x1000>;片选0 偏移0 被映射到CPU地址空间的0x1010000~0x10110000中,地址长度为0x10000      

属性-interrupt

属性-gpio


设备树驱动常用函数

查找节点方法

  1. 通过节点的compatible属性值查找指定节点
  2. 通过节点名查找指定节点
  3. 通过节点路径查找指定节点

工程实例

你可能感兴趣的:(Linux_kernel)