!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 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
================================= 设备树 ================================
设备树这块,我想说,网上资料基本都是辣鸡,基本都在分析设备树的结构、设备树的内容,但是设备树与内核的关联并没有任何说明,因此总体而言,都是一些没有什么卵用的辣鸡。
所以对于这一块,我也不知道该怎么说才比较好,主要靠的是感觉,你们就信一半试一半吧!
有一篇文章写得非常好,我结合自己的经验,重新编排了一部分,就是下面的文字了。这篇文章网址是:http://blog.csdn.net/21cnbao/article/details/8457546
一、 设备树的文件格式
1、 Dts:板级设备树,编译zImage之后,会自动编译dts文件,生成dtb文件;
2、 Dtsi:设备树模块,可以在其他的dts、dtsi文件中,通过 #include 指令加载;效果类似C++ 的继承,父树有而子树没有的属性合并到子树中,子树中与父树重合的属性会覆盖父树的相应属性;
3、 Dtb:板级设备树输出包,是zImage启动的必要条件之一;
二、 设备树的结构(网上基本都是在这一小节上面大做文章,还不完整)
1、 根节点
/ { … };
根节点是一个节点!必须具有根节点!因为所有结构都是从这里开始的!
根节点没有父节点!
2、 Node(节点)和property(属性)
a) 格式
- 节点: node { … };
- 属性: property = … ;
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、 继承
- 源文件:
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
- 等效结果:
/ {
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文件中直接调取初始化列表的方式是非常不一样的。