[原创] 设备树

dingguanliang   2015-12-2 13:12 楼主
1、起源:由于各家厂商重复添加代码到linux kernel中,导致内核充斥着大量重复代码。在linus爆发后,arm linux社区在linux kernel 3.1.y左右版本后,引进了其他体系(PowerPC:Flattened Device Tree)的设备树结构。
2、变化:
    a、添加描述设备的配置文本(.dts)。
    b、添加对配置文本解析的工具(dtc),将.dts编译成.dtb,.dtb可以单独编译,编译完成后可以追加到bootload或kernel镜像的后面 。
    c、bootload需要传递设备树参数给内核。即从某个地址搬运.dtb到内存中,然后将地址传递给内核。

3、.dts与machine:.dts与machine的关系一般是一一对应。如果多个machine有共享的数据,则可以合成.dsti,相当于c语言的头文件。其他.dts要用的时候直接include就行。

4、.dts格式:.dts文件包含了节点和属性。节点可以包含子节点(形成树的结构)。节点表示machine上面的一个device,如:cpu, ram或rom。属性表示device的各种资源,由name和value组成。
    例:ARM的local bus上内存映射区域分布了2个串口(分别位于0x101F1000 和0x101F2000)、GPIO控制器(位于0x101F3000)、SPI控制器(位于0x10170000)、中断控制器(位于0x10140000)和一个external bus桥;
    External bus桥上又连接了SMC SMC91111 Ethernet(位于0x10100000)、I2C控制器(位于0x10160000)、64MB NOR Flash(位于0x30000000);
    External bus桥上连接的I2C控制器所对应的I2C总线上又连接了Maxim DS1338实时钟(I2C地址为0x58)。
    / {  
        compatible = "acme,coyotes-revenge";  
        #address-cells = <1>;  
        #size-cells = <1>;  
        interrupt-parent = <&intc>;  

        cpus {  
            #address-cells = <1>;  
            #size-cells = <0>;  
            cpu@0 {  
                compatible = "arm,cortex-a9";  
                reg = <0>;  
            };  
            cpu@1 {  
                compatible = "arm,cortex-a9";  
                reg = <1>;  
            };  
        };  

        serial@101f0000 {  
            compatible = "arm,pl011";  
            reg = <0x101f0000 0x1000>;  
            interrupts = <1 0>;  
        };  

        serial@101f2000 {  
            compatible = "arm,pl011";  
            reg = <0x101f2000 0x1000>;  
            interrupts = <2 0>;  
        };  

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

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

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

        external-bus {  
        #address-cells = <2>   
        #size-cells = <1>;  
        ranges = <0 0  0x10100000   0x10000            // Chipselect 1, Ethernet。  
                          1 0  0x10160000   0x10000            // Chipselect 2, i2c controller。  
                          2 0  0x30000000   0x1000000>;     // Chipselect 3, NOR Flash。  

            ethernet@0,0 {  
                compatible = "smc,smc91c111";  
                reg = <0 0 0x1000>;  
                interrupts = <5 2>;  
            };  

            i2c@1,0 {  
                compatible = "acme,a1234-i2c-bus";  
                #address-cells = <1>;  
                #size-cells = <0>;  
                reg = <1 0 0x1000>;  
                interrupts = <6 2>;  
                rtc@58 {  
                    compatible = "maxim,ds1338";  
                    reg = <58>;  
                    interrupts = <7 3>;  
                };  
            };  

            flash@2,0 {  
                compatible = "samsung,k8f1315ebm", "cfi-flash";  
                reg = <2 0 0x4000000>;  
            };  
        };  
    };  
5、编译成dtb后组织结构为:
file:///C:/Users/guanliang%20ding/AppData/Local/YNote/data/smart_john_ding@163.com/b26333ec6fcd424185d081430628657c/clipboard.png
   

注:

1、节点与具体设备一一对应。如总线控制器下挂载多个从设备。就会有控制器节点和从设备节点。2、具体配置参考内核doc。路径:Documentation/devicetree/bindings。

3、由于设备树和内核分开编译。所以极大的增加了内核的灵活性。某些情况下不需要重新编译内核就能将内核移植到另一个平台上。即平台管脚和内存布局定义相同,差别的只是资源在系统中的位置。这类设备的显著特点是同一个厂商。
4、设备树是从各类驱动中抽象并且分离出来的特性。如平台驱动的struct platform_device、i2c设备的struct i2c_board_info与spi设备的struct spi_board_info。
5、bootload将设备树从flash搬到ram中。然后内核读取设备树后,将其转化成对应的信息存储在/sys文件系统中。接着,驱动加载时,可由驱动或者驱动框架去读取。待驱动注册成功时,设备驱动会在/dev/目录下出现设备名。
6、设备树可以单独编译(# dtc xxx.dtb),也可以在内核中编译(# make xxx.dtb)。运行# make xxx.dtb可以将arch/arm/boot/dtc/中的xxx.dts编译成xxx.dtb。
7、fdt是dt的一种。是一种符合open firmware标准的启动部件。在linux内核中,所有跟fdt有关的函数都会以of_xxx开头。
8、设备树属于一种静态配置资源的方式,不同于x86的动态配置。x86动态配置主要体现在即插即用技术,例如pci总线。另外,还有地址重映射机制。任何地址空间都能动态的映射到cpu总线空间,而在嵌入式中一般是固定的。9、设备树中的内容。一部分由系统读取,并交给驱动。例如:reg、clk、gpio和interrupt。另外一部分可能由驱动自己去读取。所以,针对不同的设备树,需要根据驱动代码具体分析。
10、一个设备的设备树一般需要创建三个文件。*.h文件定义一些常量,*.dts文件用来放核心部件的配置,*.dtsi用来放外设配置。

回复评论 (2)

这个树我收藏了

点赞  2015-12-3 11:32
新东西,收藏了
点赞  2016-1-19 17:04
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复