栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

设备树学习报告

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设备树学习报告

文章目录
  • 1. 设备树的基本概念
    • 1.1 什么是设备树
    • 1.2 设备树的组成
  • 2. 设备树的基本结构
    • 2.1 设备树的基本构造
    • 2.2 节点之间的联系
    • 2.3内核与节点匹配
    • 2.4 自定义属性的设置与获取

1. 设备树的基本概念 1.1 什么是设备树

在linux3.x版本之前的内核源码,存在大量对板级细节信息的描述造成内核源码的冗余。为了解决这个问题引入了设备树

官方对设备树的描述是: 一个描述硬件的数据结构 设备树通过bootloader将硬件资源传给内核。使内核和硬件资源描述相对独立

1.2 设备树的组成

设备树的主要由三部分组成 DTC (device tree compiler) DTS (device tree source) 和 DTB (device tree blob)

DTS:dts 文件时对device Tree 的描述,放置在内核的/arch/arm/boot/dts目录中。一个***.dtb 文件对应一个ARM的machine。dts文件描述了一个板子的硬件资源

DTC:DTC为编译工具,它可以将.dts文件编译成.dtb文件

DTB:DTC编译***.dts 生成的二进制文件(.dtb) bootload 在引导内核时,先预读取.dtb到内存,进而由内核解析。

设备树中还有一个文件: dtsi文件 由于一个SOC可能有多个不同的电路板。而每个电路板都拥有一个.dts。 这些dts会存在很多共同的部分,为了提高代码的复用率。设备树使用dist文件保存了这些共同部分的代码。这样就可以提供给不同的dts使用。

所以1个dts文件+n个dtsi文件,它们编译而成的dtb文件就是真正的设备树,此外,dts/dtsi兼容c语言的一些语法,能使用宏定义,也能包含.h文件

2. 设备树的基本结构

下面是六轴主控制器的设备树文件的一部分 下面以它为例对设备树的基本结构进行分析

/include/ "am572x_clock.dtsi"

/   {
    model = "TI_AM572X_IDK - Cortex-A15 (ARMV7A)";
    compatible = "ti,sitara-ctxa15";
    #address-cells = <1>;
    #size-cells = <1>;
    interrupt-parent = <&intc>;
    
    ...

     i2c1@48070000
            {
            compatible  = "ti,am38xx-i2c";
            interrupts  = <88 0 4>;
            reg         = <0x48070000 0xd6>;
            clocks      = <&l4per_i2c1_mod>;
            clock-names = "l4per_i2c1_mod";
            clock-frequency = <400000>;
            #address-cells = <1>;
            #size-cells = <0>;
            pinmux-0    = <&i2c1_pads>;
            
            pcf8564@0x51
                {
                compatible  = "nxp,pcf8564";
                reg         = <0x51>;
                data-scl-frequency = <400000>;
                };
            
            tps659037@0x58
                {
                compatible  = "ti,tps659037-compatible";
                reg         = <0x58>;
                data-scl-frequency = <400000>;
                };

            pinmux-0    = <&i2c1_pads>; 标号引用&i2c1_pads
    ...

    }
2.1 设备树的基本构造

{}包围起来的结构称之为设备树节点,dts中最开头的/ {},称为根节点。节点的标准结构是xxx@yyy{…},xxx是节点的名字,yyy则不是必须的,其值为节点的地址(寄存器地址或其他地址).比如i2c1: i2c@48070000中的48070000就是一个i2c控制器的寄存器基地址,pcf8564@0x51中的0x51就是这个rtc设备的i2c地址

1.属性:地址

有关节点的地址,比如i2c1@48070000,虽然它在名字后面跟了地址。但正式的设置是在reg属性中设置的比如 reg = <0x48070000 0xd6>; reg的格式通常为;0x48070000是寄存器基地址,0xd6是长度。address和length的个数是可变的,由父节点的属性#address-cells 和#size-cells 决定,比如节点i2c1@48070000的父节点 #address-cells 和#size-cells均为1,所以下面的i2c节点的reg属性就有address 和length,而i2c节点本身#address-cells 和#size-cells 分别为1和0,所以其下的rtc: pcf8564@0x51 的reg属性就只有一个0x51(i2c地址)了

2.属性:兼容性

如果一个节点是设备节点,这个设备节点就会有一个compatible(属性),这是设备用于和驱动匹配的依据,compatible(兼容性)的值可以有不止一个字符串以满足不同的需求。而根节点的compatible也是非常的重要,也是就是"ti,sitara-ctxa15"这个字符串,因为内核系统启动后,将根据根节点的compatible来判断cpu信息,并由此进行初始化。

3.属性设置的技巧

属性设置主要有二种技巧

(1).可以参考类似的dts

(2).查询内核中的文档

2.2 节点之间的联系

节点和节点之间的关联,由“标号引用” 和“包含”来实现

标号引用就是在节点名称前加上标号,这样设备树的其他位置就能够通过&符号来调用/访问该节点,比如上面代码所示i2c节点中的 pinmux-0属性,就引用了i2c1_pads标号处的节点

pinmux-0    = <&i2c1_pads>; 标号引用&i2c1_pads
i2c1_pads: i2c1pads
                    {
                    pin-set = <
                               0x1800 0x00060000   
                               0x1804 0x00060000   
                               >;
                    };

包含是最基本的方式,比如如上面的代码我们要在在i2c1接口添加一个i2c外设,那么就必须要在i2c1下面添加一个节点,比如上面代码中的pcf8564@0x51{}

2.3内核与节点匹配

内核需要知道dtb文件的地址,这样内核就可以通过一些API任意获取设备树的内部信息

驱动程序直接通过设备节点中的compatible(兼容性)来与设备节点直接进行配对的,

这里以GPMC驱动为例 只要驱动中的compatible值与设备节点中的compatible相匹配,

LOCAL const VXB_FDT_DEV_MATCH_ENTRY vxbGpmc_match[] =  //match table 
    {
        {
        "zjc,gpmc", 
        (void *)NULL
        },
        {}
    };

Probe 函数匹配如下图所示 vxbFdtDevMatch函数进行兼容性匹配 如果匹配成功就进入attach函数进行挂载设备

STATUS vxbGpmcProbe
    (
    struct vxbDev * pDev
    )
    {
    VXB_FDT_DEV_MATCH_ENTRY   * match;
    STATUS                      ret;
    
    
    VXB_ASSERT (pDev != NULL, ERROR);
         
    ret = vxbFdtDevMatch (pDev, vxbGpmc_match, &match);
    if (ret == ERROR)
        return ERROR;
   
    printf(" GPMC Probe success n");
         
    return OK;
    }
2.4 自定义属性的设置与获取

所谓的自定义属性,有点类似于老内核中的platform_data,我们在设备节点中可以随意添加自定义属性,比如下面GPMC节点里面的nand-addr属性

 gpmc:gpmc@0x50000000
           {
           compatible = "zjc,gpmc";
           reg = <0x50000000 0x37c>,
                 <0x08000000 0x01000000>;
           nand-addr = <0x08000000>;
           pinmux-0 = <&gpmc_pads>;
           };

使用以下vxFdtPropGet函数进行获取nand-addr属性的

const void * vxFdtPropGet
    (
    int    offset,      
    char * pPropName,   
    int *  pLen         
                        
    )       
vxFdtPropGet( pFdtDev->offset, "nand-addr", &len)

针对32位整形的属性可以利用下面这个API来获取属性值,第一个参数是节点,第二个参数是属性名字,第三个参数是返回属性值内容的字节大小

vxFdtPropGet( pFdtDev->offset, "nand-addr", &len)

针对32位整形的属性可以利用下面这个API来获取属性值,第一个参数是节点,第二个参数是属性名字,第三个参数是返回属性值内容的字节大小

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/830882.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号