1.简介
DTS, Device Tree Source设备源码树,是一种描述硬件的数据结构体,dts的加入,先将
dts解析成树型结构,然后放在内存中,等待内核后面注册device 和 driver的时候再来铺开调用。
DTS由一系列被命名为节点node和属性property组成,而节点本身可以包含子节点,所谓属性
就是成对出现的name和value。
2.DTS使用
DTS在内核中,dts使用各种device node形式存在,而这些device node对于大部分的内核驱动\
模型platform driver来说,最终需要由对应的platform device来匹配,才可以完成一次device 和 driver\
的probe过程。
device node转为platform device,这个过程是交给of_platform_populate来
完成的,(dts相关的device node tree是在start_kernel的setup_arch->unflatten_device_tree
来加载dtb并解析)。
of_platform_populate的入口一般是处于init_machine中,对于arm架构而言位于board.c中的
DT_MACHINE_START()的init_machine中定义,而init_machine的调用是以一个module的形式存在的,
该module被加载后的目的,就是做device的create,在以前旧的board中,会将board.c中定义的
device_info转换为对应的device,以便后面的driver加载时可以match到相应的device。
需要说明的是dts中定义的各种device node,往往只是用来辅助核心的device node而存在的,
也就是说这些node存在不需要加载为platform device,那么哪些device node是不会在
of_platform_populate中被解析为device的呢?
static int of_platform_bus_of_platform_populatereate(struce device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent,bool strict)
源码省略,of_get_property("compatible"),如果这个节点的root device属性不存在,则表明其
不需要生成为platform device,随后,root device node由函数of_platform_device_create_pdate
创建为platform device后,需要检查当前节点的compatible是否和match table中定义的table list
相互匹配。对于dts中定义的device node,只有其所属的parent node所属的compatible属性和调用
of_platform_populate时传入的of_device_id相互匹配,则说明如果当前的device node只要包含有
compatible属性就会被创建为platform device。
2.1 节点语法
节点构成:node_name@unit_address,node_name:由数字,大小字符等组成。unit_address:表示
是节点所表示的硬件配置的起始地址即reg属性的起始值,若节点没有reg属性则不需要设置。
属性property,属性有两种,一种是没有值的空属性,一种是有值的属性。
例如:
compatible="gpio-keys";
上面是常见的有值的属性,属性值有三种
a).用引号括起来,字符串,如上述实例
b).使用尖括号
这些是根节点必须有的属性,它们代表的含义都是默认的.
参考一个瑞芯微上驱动一个mipi屏幕的驱动代码:
&dsi {
status = "okay";
rockchip,lane-rate = <650>; //680
panel: panel@0 {
compatible = "simple-panel-dsi";
reg = <0>;
backlight = <&backlight>;
reset-gpios = <&gpio2 RK_PB3 GPIO_ACTIVE_HIGH>;
enable-gpios = <&gpio2 RK_PC7 GPIO_ACTIVE_HIGH>;
power-supply = <&vcc33_lcd>;
......
prepare-delay-ms = <20>; //enable gpio delay
reset-delay-ms = <20>; //reset gpio delay
init-delay-ms = <20>; //after gpio befor send cmds delay
enable-delay-ms = <20>; //enable backlight
status = "okay";
panel-init-sequence = [
29 00 02 B0 00
05 78 01 29
05 46 01 11
];
panel-init-sequence2 = [
29 14 16 CB 00 18 00 80 01 00 00 83 03 E8 00 00
....
29 14 1B D3 1B 33 BB 77 77 77 33 33 33 12 8A 07 3D BC
];
panel-exit-sequence = [
05 64 01 28
05 96 01 10
];
disp_timings: display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <27000000>; //29700000
hactive = <640>;
hback-porch = <49>;
hfront-porch = <67>;
hsync-len = <8>;
....
de-active = <0>;
pixelclk-active = <0>;
};
};
};
};
3.代码测试
实际测试使用全志linux开发板测试。
设备树DTS:
//假设使用如下dts文件
/{
//在根节点下面添加按键信息
gpio-keys{
compatible="gpio-keys";
power{
label = "Power Button";
gpios = <&gpio3 291 1>;
linux,code = <116>;//key power
};
};
};
上述设备树中compatible属性
//开始解析该dts文件
#include <linux/module.h>
#include <linux/init>
#include <linux/fs.h>
#include <linux/gpio_keys.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/spinlock.h>
static int __init device_tree_ce(void)
{
struct device_node *node,*pp;
int nbuttons;
int code;
const char* desc;
int gpio;
/*
根据下面函数解析内容看:只有compatible属性值有作用感,
第一节点什么用也没有发现。
*/
node = of_find_compatible_node(NULL,NULLL,"gpio-keys");
//上面函数找到DTS中compatible为“gpio-keys”的节点
printk(KERN_EMERG"%d",of_device_id_compatible(node,"gpio-leys"));
//判断节点的compatible属性是否包含compat指定的字符串,当一个驱动支持2个
//或者多个设备时,这些不同的dts文件中设备的compatible属性都会进入驱动
//OF匹配表,因此驱动可以透过bootloader传递给内核的Device Tree中真正
//节点的compatible属性以确定究竟是哪一种设备,从而根据不同设备类型
//进行不同的处理。
nbuttons = of_get_child_count(node);//算出节点下面共有多少个节点
//printk;
for_each_child_of_node(node,pp)//遍历子节点
{
enum of_gpio_flags flags;
if(!of_find_property(pp,"gpios",NULL))//子节点里面是否包含“gpio”属性
{
printk(KERN_EMERG"Found button without gpios\n");
continue;
}
gpio=of_get_gpio_flags(pp,0,&flags);
of_property_read_u32(pp,"linux,code",&code);//读取属性名为“linux,code”属性的节点整型值。
desc = of_get_property(pp,"label",NULL);//读取属性名为“label"
}
}
您还没有登录,请您登录后发表评论。