设备树基础



!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  Warning  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Do not belive this chapter without any doubt, to avoid being hole

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  前方高能  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

请不要绝对相信本文,以免被坑

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  要说三遍  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

重要的事情说3次,请不要绝对相信本文,以免被坑

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 

看本文前,请自行打开内核工程的两个文件浏览一遍:

1、 arch/arm/boot/dts 中的随意一个dts文件;

2、 include/linux/of.h

 

=================================  设备树  ================================

设备树这块,我想说,网上资料基本都是辣鸡,基本都在分析设备树的结构、设备树的内容,但是设备树与内核的关联并没有任何说明,因此总体而言,都是一些没有什么卵用的辣鸡。

所以对于这一块,我也不知道该怎么说才比较好,主要靠的是感觉,你们就信一半试一半吧!

有一篇文章写得非常好,我结合自己的经验,重新编排了一部分,就是下面的文字了。这篇文章网址是:

 

一、 设备树的文件格式

1、 Dts:板级设备树,编译zImage之后,会自动编译dts文件,生成dtb文件;

2、 Dtsi:设备树模块,可以在其他的dts、dtsi文件中,通过 #include 指令加载;效果类似C++ 的继承,父树有而子树没有的属性合并到子树中,子树中与父树重合的属性会覆盖父树的相应属性;

3、 Dtb:板级设备树输出包,是zImage启动的必要条件之一;

 

二、 设备树的结构(网上基本都是在这一小节上面大做文章,还不完整)

1、 根节点

/ { … };

根节点是一个节点!必须具有根节点!因为所有结构都是从这里开始的!

根节点没有父节点!

2、 Node(节点)和property(属性)

a) 格式

  1. 节点:
  2. 属性:

b) 节点可以独立存在,属性必须依赖节点存在;

c) 嵌套:

嵌套是节点间关系,通过嵌套形成树形结构,故称为设备树;

例:

/ {
node1 {
property = “a”;
node3 {
property1 = <1>;
property2;
};
};
node2 {
proprety = <0>;
};
};

3、 标签

标签用于修饰节点,使这个节点能够被“嵌套”到属性中;可以形成跨越树形结构的链接,使完全不同的设备关联起来,如,把设备的管脚配置关联到设备中;

例,将node1赋值给node2的property:

tag: node1 { … };
node2 {
property = <&tag>;
};

4、 命名规则

a) 节点: 设备名@十六进制地址;

b) 属性: 随便;

c) 标签: 设备名+id

5、 赋值

赋值是针对属性的操作,不可以对节点进行赋值。赋值的形式非常多样化,例:

a) 布尔量: property; //有这个属性?or no?

b) 十进制整形值: property = <1234>;

c) 十六进制整型值:property = <0x1234>;

d) 字符串: property = “abcd”;

e) 节点: property = <&tag >;

f) 整形数组: property = <0x1234 1234>;

g) 节点数组: property = <&tag1 &tag2 &tag3>;

h) 结构体: property = <&tag 0x0 123>;

i) 多个字符串: property = ”123”, “456”, “789”;

6、 继承

  1. 源文件:
a) tree1.dtsi:
/ {
node1 {
property1 = 1;
};
};
b) tree2.dtsi:
/ {
node1 {
property2 = 2;
};
 
node2 {
property1 = 1;
};
};
c) tree.dts:
#include “tree1.dtsi”
#include “tree2.dtsi”
/ {
node1 {
property1 = a;
};
};

内核工程make:DTC tree.dts

  1. 等效结果:
/ {
node1 {
property1 = a;
property2 = 2;
};
node2 {
property1 = 1;
};
};

注意node1,tree.dts继承了tree2.dtsi,两者均对node1的proprety1进行了赋值,那么子树tree.dts中的配置将生效,父树中相应的配置失效。

 

==================================  使用设备树  ===============================

 

一、 关联简单的驱动程序

1、 compatible和status属性

每个带有compatible属性的节点,都会在linux系统中对应一个设备,不管物理上是否存在这个设备,compatible属性是该节点代表的设备的类型的唯一标识。status控制linux系统是否会创建这个设备,如果为字符串okay,则会创建该设备的匹配关系,若否,则该设备即使存在驱动程序,也不会被匹配。

例:

/ {
test {
compatible = “test”;
status = “okay”;
/* status = “disable”; */
};
};

2、 Driver的compatible属性

static const struct of_device_id test_of_match[] = {
    {
            .compatible = "test",
    },
    { }
};
static struct platform_driver test_driver = {
    .driver = {
        .name = "btn_test",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(test_of_match),
    },
    .probe =    Test_Probe,
    .remove =   Test_Remove,
};

driver的compatible与node的compatible匹配,那么linux就调用driver的probe函数,初始化设备。

 

二、 在驱动程序中访问设备树

1、 技能需求

我们不需要对设备树的API非常熟悉,因为linux系统已经为我们匹配好了设备树节点,即使需要写全新的驱动程序,也可以参考其他的驱动程序进行仿写。

2、 内核API的of系函数

由于不是太熟练,仅提供函数名,自己体会作用!

a) 与node有关的API:

of_find_node_by_name
of_find_compatible_node
of_get_parent
of_get_next_child
of_get_child_by_name
b) 与property有关的API:
of_find_property
of_get_property
of_property_read_u8
of_property_read_u32
of_property_read_u64
of_property_read_u8_array
of_property_read_u32_array
of_property_read_string

 

三、 设备树中与启动相关的信息

平台信息都放在根节点中,这些信息参与与linux启动,以A5为例:

/{
model = "Atmel SAMA5D36-EK";
compatible = "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d3", "atmel,sama5";
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a5";
reg = <0x0>;
};
};
memory {
reg = <0x20000000 0x8000000>;
};
clocks {
…
};
};

其中compatible、cpu、memory中的错误,尤其是经常改动的memory,都会导致内核启动死掉。

 

四、 设备树的影响范围

这是值得注意的一点,设备树只是一个数据结构,保存了设备的地址、配置信息,但事实上并不影响设备本身,操作设备依旧是交给驱动程序去完成,所有驱动程序都需要通过匹配compatible属性方式启动,这一点与过去的board.c文件中直接调取初始化列表的方式是非常不一样的。