设备树 简介

设备树(device tree)机制是Linux内核从linux-3.x版本开始引进的一种机制,目的是解决内核源码的arch/arm目录下代码混乱的问题:随着ARM生态的快速发展,在内核源码的arch/arm目录下,存放着几十种arm芯片和几百个开发板相关的源文件,很多开发板和处理器的中断、寄存器等相关硬件资源都在这个目录下以.c或.h的文件格式定义。而对于内核来说,与这些硬件耦合,会导致内核代码混乱不堪,每个开发板上运行的内核镜像都必须单独编译配置,无法通用。什么时候Linux内核能像Windows镜像那样,无论你的电脑什么配置,一个Windows安装包,都可以直接下载安装运行呢?

设备树机制,实现了Linux内核和硬件平台的解耦:每个硬件平台的硬件资源使用一个设备树文件(xxx.dts)来描述,而不是在arch/arm下以.c 或 .h 文件来定义。Linux内核是一个通用的内核,在启动过程中,在通过解析设备树中的硬件资源来初始化某个具体的平台。

引入设备树后,很多和内核驱动开发的工作也发生了变化:以往驱动工程师关注的头文件宏定义、寄存器定义,现在这些基本上不用关注,关注的重点则转向了如何根据硬件平台去配置和修改设备树文件。很多驱动的编程接口也发生了变化,开始慢慢使用device tree提供的编程接口去开发驱动。

一个设备树文件:xxx.dts,使用设备树语法,通过节点(node)和属性(property),来描述一个开发板的硬件资源。

cpu {
    device_type = "cpu";
    interrupt-parent = <&gic>;
};

在设备树文件中,CPU是一个node,用来表示一个设备,使用一个大括号和一个分号隔开。大括号内是和CPU节点相关的属性,用来描述CPU相关的信息。

一个设备树文件中,有一个根节点,在根节点下通常会有各种各样的节点,来表示当前开发板上的所有资源:

/ {
    cpu {
        device_type = "cpu";
        compatible = "arm,cortex-a9";
        interrupt-parent = <&gic>;

    };
    memory {
        device_type = "memory";
        reg = <0x60000000 0x40000000>;
    };
    gic: interrupt-controller@1e001000 {
        compatible = "arm,cortex-a9-gic";
        #interrupt-cells = <3>;
        #address-cells = <0>;
        interrupt-controller;
        reg = <0x1e001000 0x1000>,
              <0x1e000100 0x100>;
    };
};

设备树编译器DTC(device tree compiler)会把xxx.dts格式的文本文件编译成二进制格式的设备树文件:xxx.dtb,然后由u-boot加载到内存的指定地址,内核在启动过程中,会解析加载到指定内存的dtb文件,获取当前开发板的各种硬件信息(各个控制器的寄存器地址、中断资源等),来初始化硬件平台。

对于驱动开发者来说,如何根据自己的硬件平台来修改和维护设备树文件,是一个必备技能,尤其是内核引入设备树之后,驱动开发的一部分工作量就是修改和配置设备树文件。

接下来,将会分享如何能看懂设备树文件,如何修改设备树文件,如何使用设备树语法去描述硬件平台上的各种资源,包括:CPU、缓存、控制器、中断控制器、内存、存储器等等。

驱动开发核心理论,Linux内核开发入门实战视频教程:《Linux内核编程》,具有一线芯片原厂开发经验的驱动工程师录制,内含Linux设备树课程,教你如何修改设备树文件和基于设备树接口开发驱动。详情点击:王利涛老师个人淘宝店:Linux内核编程