linux设备树(DTS)的前世今生

什么是DTS?为什么要引入DTS?

DTS即Device Tree Source 设备树源码, Device Tree是一种描述硬件的数据结构,它起源于 OpenFirmware (OF)。
在Linux 2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,

比如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data,这些板级细节代码对内核来讲只不过是垃圾代码。

而采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。
每次正式的linux kernel release之后都会有两周的merge window,在这个窗口期间,kernel各个部分的维护者都会提交各自的patch,将自己测试稳定的代码请求并入kernel main line。

每到这个时候,Linus就会比较繁忙,他需要从各个内核维护者的分支上取得最新代码并merge到自己的kernel source tree中。Tony Lindgren,内核OMAP development tree的维护者,发送了一个邮件给Linus,请求提交OMAP平台代码修改,并给出了一些细节描述:
1)简单介绍本次改动
2)关于如何解决merge conficts。有些git mergetool就可以处理,不能处理的,给出了详细介绍和解决方案
一切都很平常,也给出了足够的信息,然而,正是这个pull request引发了一场针对ARM linux的内核代码的争论。

我相信Linus一定是对ARM相关的代码早就不爽了,ARM的merge工作量较大倒在其次,主要是他认为ARM很多的代码都是垃圾,代码里面有若干愚蠢的table,而多个人在维护这个table,从而导致了冲突。因此,在处理完OMAP的pull request之后(Linus并非针对OMAP平台,只是Tony Lindgren撞在枪口上了),他发出了怒吼:
Gaah.Guys, this whole ARM thing is a f*cking pain in the ass.
之后经过一些讨论,对ARM平台的相关code做出如下相关规范调整,这个也正是引入DTS的原因。
1.ARM的核心代码仍然保存在arch/arm目录下
2.ARM SoC core architecture code保存在arch/arm目录下
3.ARM SOC的周边外设模块的驱动保存在drivers目录下
4.ARM SOC的特定代码在arch/arm/mach-xxx目录下
5.ARM SOC board specific的代码被移除,由DeviceTree机制来负责传递硬件拓扑和硬件资源信息。
本质上,Device Tree改变了原来用hardcode方式将HW 配置信息嵌入到内核代码的方法,改用bootloader传递一个DB的形式。
如果我们认为kernel是一个black box,那么其输入参数应该包括:
a.识别platform的信息

b.runtime的配置参数

c.设备的拓扑结构以及特性
对于嵌入式系统,在系统启动阶段,bootloader会加载内核并将控制权转交给内核,此外,还需要把上述的三个参数信息传递给kernel,以便kernel可以有较大的灵活性。

在linux kernel中,Device Tree的设计目标就是如此。

设备树文件介绍

在设备树出现之前,关于硬件的描述信息一般放在一个个类似 arch/xxx/mach-xxx/board-xxx.c 的文件中,如:

static struct resource gitchat_resource[] = {
    {
        .start = 0x20100000 ,
        .end = 0x20100000 +1,
        .flags = IORESOURCE_MEM 
        …
        .start = IRQ_PF IRQ_PF 15 ,
        .end = IRQ_PF IRQ_PF 15 ,
        .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE
    }
};

static struct platform_device gitchat_device = {
    .name name ="gitchat",
    .id = 0,
    .num_resources num_resources = ARRAY_SIZE(gitchat_resource),
    .resource = gitchat_resource,
};

static struct platform_device *ip0x_devices[] __initdata ={
    &gitchat_device,
};

static int __init ip0x_init(void)
{
    platform_add_devices(ip0x_devices, ARRAY_SIZE(ip0x_devices)); 
}

至于设备树的出现到底带来了哪些好处,先看一下设备树的文件:

eth:eth@ 4,c00000 {
    compatible ="csdn, gitchat";
    reg =<
        4 0x00c00000 0x2
        4 0x00c00002 0x2
    >;
    interrupt-parent =<&gpio 2>;
    interrupts=<14 IRQ_TYPE_LEVEL_LOW>;
    …
};

从代码中可看到对于 GITCHAT 这个网卡驱动、一些寄存器、中断号和上一层 gpio 节点都很清晰的被描述。比上一图的代码优化了很多,也容易维护了很多。这样就形成了设备在脚本,驱动在 c 文件里的关系图:


linux设备树(DTS)的前世今生

从图中可以看出 A、B、C 三个板子里都含有 GITCHAT 设备树文件,这样对于 GITCHAT 驱动写一份就可在 A、B、C 三个板子里共用。从上幅图里不难看出,其实设备树的出现在软件模型上相对于之前并没有太大的改变,设备树的出现主要在设备维护上有了更上一层楼的提高,此外在内核编译上使内核更精简,镜像更小。

设备树的文件结构和剖析

设备树和设备树之间到底是什么关系,有着哪些依赖和联系,先看下设备树之间的关系图:


linux设备树(DTS)的前世今生

除了设备树(DTS)外,还存有 dtsi 文件,就像代码里的头文件一样,是不同设备树共有的设备文件,这不难理解,但是值得注意的是如果 dts 和 dtsi 里都对某个属性进行定义的话,底层覆盖上层的属性定义。这样的好处是什么呢?假如你要做一块电路板,电路板里有很多模块是已经存在的,这样就可以直接像包含头文件一样把共性的 dtsi 文件包含进来,大大减少工作量,后期也可以对类似模块再次利用。

设备树文件的格式是 dts,包含的头文件格式是 dtsi,dts 文件是一种程序员可以看懂的格式,但是 Uboot 和 Linux 只能识别二进制文件,不能直接识别。所以就需要把 dts 文件编译成 dtb 文件。把 dts 编译成 dtb 文件的工具是 dtc,位于内核目录下 scripts/dtc,也可以手动安装:sudo apt-get install device-tree-compiler 工具。具体 dts 是如何转换成机器码并在内存里供 kernel 识别的,请看下图:


linux设备树(DTS)的前世今生

设备树的应用

有了理论,在具体的工程里如何做设备树呢?这里介绍三大法宝:文档、脚本、代码。文档是对各种 node 的描述,位于内核 documentation/devicetree/bingdings/arm/ 下,脚本就是设备树 dts,代码就是你要写的设备代码,一般位于 arch/arm/ 下,以后在写设备的时候可以用这种方法,绝对的事半功倍。很多上层应用开发者没有做过内核开发的经验,对内核一直觉得很神秘,其实可以换一种思路来看内核,相信上层应用开发者最熟悉的就是各种 API,工作中可以说就是和 API 打交道,对于内核也可以想象是各种 API,只不过是内核态的 API。这里设备文件就是根据各种内核态的 API 来调用设备树里的板级信息。

struct device_node *of_find_node_by_phandle(phandle handle);

struct device_node *of_get_parent(const struct device_node_ *node);

of_get_child_count()

of_property_read_u32_array()

of_property_read_u64()

of_property_read_string()

of_property_read_string_array()

of_property_read_bool()

具体的用法这里不做进一步的解释,大家可以查询资料或者看官网解释。

这里对设备树做个总结,设备树可以总结为三大作用:

一是平台标识,所谓平台标识就是板级识别,让内核知道当前使用的是哪个开发板,这里识别的方式是根据 root 节点下的 compatible 字段来匹配。

二是运行时配置,就是在内核启动的时候 ramdisk 的配置,比如 bootargs 的配置,ramdisk 的起始和结束地址。

三是设备信息集合,这也是最重要的信息,集合了各种设备控制器,接下来的实践课会对这一作用重点应用。这里有张图对大家理解设备树作用有一定的帮助:

linux设备树(DTS)的前世今生

(注:本文为转载)

展开阅读全文

页面更新:2024-03-21

标签:维护者   设备   拓扑   板子   内核   脚本   前世   模块   今生   细节   作用   参数   代码   硬件   文件   平台   科技   信息

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top