DTS
阅读原文时间:2023年07月11日阅读:1

一、DTS的加载过程

如果要使用Device Tree,首先用户要了解自己的硬件配置和系统运行参数,并把这些信息组织成Device Tree source file。通过DTC(Device Tree Compiler),可以将这些适合人类阅读的Device Tree source file变成适合机器处理的Device Tree binary file(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。

它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。

Device Tree是否要描述系统中的所有硬件信息?答案是否定的。基本上,不需要描述那些可以动态探测到的设备,例如USB device。不过对于SOC上的usb hostcontroller,它无法被动态识别,需要在device tree中描述。

同理,在computersystem中,PCI device可以被动态探测到,不需要在device tree中描述,但是PCI bridge如果不能被探测,那么就需要描述它。

.dts文件是一种ASCII 文本格式的Device Tree描述,此文本格式非常人性化,适合人类的阅读习惯。

基本上,在ARM Linux中,一个.dts文件对应一个ARM的machine,一般放置在内核的arch/arm/boot/dts/目录。

由于一个SoC可能对应多个machine(一个SoC可以对应多个产品和电路板),势必这些.dts文件需包含许多共同的部分,Linux内核为了简化,把SoC公用的部分或者多个machine共同的部分一般提炼为.dtsi,类似于C语言的头文件。其他的machine对应的.dts可以include这个.dtsi。

譬如,对于RK3288而言, rk3288.dtsi就被rk3288-chrome.dts所引用,rk3288-chrome.dts有如下一行:#include“rk3288.dtsi”。

再如rtd1195, 在 rtd-119x-nas.dts中就包含了/include/ "rtd-119x.dtsi"。

当然,和C语言的头文件类似,.dtsi也可以include其他的.dtsi,譬如几乎所有的ARM SoC的.dtsi都引用了skeleton.dtsi,即#include"skeleton.dtsi“

或者 /include/ "skeleton.dtsi"

{

    node1 {

        a-string-property = "A string";

        a-string-list-property = "first string", "second string";

        a-byte-data-property = \[0x01 0x23 0x34 0x56\];

        child-node1 {

            first-child-property;

            second-child-property = <>;

            a-string-property = "Hello, world";

        };

        child-node2 {

        };

    };

    node2 {

        an-empty-property;

        a-cell-property = <   >; /\* each number (cell) is a uint32 \*/  

        child-node1 {

        };

    };

};

下面以一个最简单的machine为例来看如何写一个.dts文件。假设此machine的配置如下:
1、1个双核ARM Cortex-A9 32位处理器;

2、ARM的local
bus上的内存映射区域分布了2个串口(分别位于0x101F1000 和
0x101F2000)、GPIO控制器(位于0x101F3000)、SPI控制器(位于0x10115000)、中断控制器(位于0x10140000)和一个external
bus桥;

3、External bus桥上又连接了SMC SMC91111 Ethernet(位于0x10100000)、I2C控制器(位于0x10160000)、64MB NOR Flash(位于0x30000000);

4、External bus桥上连接的I2C控制器所对应的I2C总线上又连接了Maxim DS1338实时钟(I2C地址为0x58)。

其对应的.dts文件为:

{

    compatible = "acme,coyotes-revenge";

#address-cells = <>;  

#size-cells = <>;  

    interrupt-parent = <&intc>;

    cpus {

#address-cells = <>;  

#size-cells = <>;  

        cpu@ {

            compatible = "arm,cortex-a9";

            reg = <>;

        };

        cpu@ {

            compatible = "arm,cortex-a9";

            reg = <>;

        };

    };

    serial@101f0000 {

        compatible = "arm,pl011";

        reg = <0x101f0000 0x1000 >;

        interrupts = <   >;

    };

    serial@101f2000 {

        compatible = "arm,pl011";

        reg = <0x101f2000 0x1000 >;

        interrupts = <   >;

    };

gpio@101f3000 {

        compatible = "arm,pl061";

        reg = <0x101f3000 0x1000  

0x101f4000 0x0010>;

        interrupts = <   >;

    };

    intc: interrupt-controller@ {

        compatible = "arm,pl190";

        reg = <0x10140000 0x1000 >;

        interrupt-controller;

#interrupt-cells = <>;  

    };

    spi@ {

        compatible = "arm,pl022";

        reg = <0x10115000 0x1000 >;

        interrupts = <   >;

    };

external-bus {

#address-cells = <>  

#size-cells = <>;  

        ranges = <   0x10100000   0x10000     // Chipselect 1, Ethernet  

   0x10160000   0x10000     // Chipselect 2, i2c controller  

   0x30000000   0x1000000>; // Chipselect 3, NOR Flash  

        ethernet@, {

            compatible = "smc,smc91c111";

            reg = <  0x1000>;

            interrupts = <   >;

        };

        i2c@, {

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

#address-cells = <>;  

#size-cells = <>;  

            reg = <  0x1000>;

            rtc@ {

                compatible = "maxim,ds1338";

                reg = <>;

                interrupts = <   >;

            };

        };

        flash@, {

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

            reg = <  0x4000000>;

        };

    };

};

上述.dts文件中, root结点"/"的compatible 属性compatible = "acme,coyotes-revenge";定义了系统的名称,它的组织形式为:,

Linux内核透过root结点"/"的compatible 属性即可判断它启动的是什么machine。

如在arch/arm/boot/dts/vexpress-v2m.dtsi中的Flash结点:

flash@, {

    compatible = "arm,vexpress-flash", "cfi-flash";

    reg = < 0x00000000 0x04000000>,

    < 0x00000000 0x04000000>;

    bank-width = <>;

};

compatible属性的第2个字符串"cfi-flash"明显比第1个字符串"arm,vexpress-flash"涵盖的范围更广。

在本例中,root结点的#address-cells = <1>;和#size-cells =<1>;决定了serial、gpio、spi等结点的address和length字段的长度分别为1。

ranges是地址转换表,其中的每个项目是一个子地址、父地址以及在子地址空间的大小的映射。映射表中的子地址、父地址分别采用子地址空间的#address-cells和父地址空间的#address-cells大小。

对于本例而言,子地址空间的#address-cells为2,父地址空间的#address-cells值为1,因此0
0  0x10100000  
0x10000的前2个cell为external-bus后片选0上偏移0,第3个cell表示external-bus后片选0上偏移0的地址空间被映射到CPU的0x10100000位置,第4个cell表示映射的大小为0x10000。ranges的后面2个项目的含义可以类推。

static struct i2c\_board\_info \_\_initdata afeb9260\_i2c\_devices\[\] = {

{

I2C\_BOARD\_INFO("tlv320aic23", 0x1a),

}, {

I2C\_BOARD\_INFO("fm3130", 0x68),

}, {

I2C\_BOARD\_INFO("24c64", 0x50),

}

};

之类的i2c_board_info代码,目前不再需要出现,现在只需要把tlv320aic23、fm3130、24c64这些设备结点填充作为相应的I2C controller结点的子结点即可,类似于前面的

i2c@, {

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

    …

    rtc@ {

        compatible = "maxim,ds1338";

        reg = <>;

        interrupts = <   >;

    };

};

Device Tree中的I2C client会透过I2C host驱动的probe()函数中调用of_i2c_register_devices(&i2c_dev->adapter); 然后被自动展开。

从设备树中读取相关GPIO的配置编号和标志,返回值为 gpio number。

  1. dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \

  2. vexpress-v2p-ca9.dtb \

  3. vexpress-v2p-ca15-tc1.dtb \

  4. vexpress-v2p-ca15_a7.dtb \

  5. xenvm-4.2.dtb

当我们在Linux内核下运行make

dtbs时,若之前选择了ARCH_VEXPRESS,上述.dtb都会由对应的.dts编译出来。因为arch/arm/Makefile中含有一个dtbs编译target项目。当然也可以单独编译Device
Tree文件。命令由读者自行去找。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章