一:基本简介
设备作用:提供设备信息
设备树(Device Tree)是一种描述硬件的数据结构在操作系统引导阶段进行设备初始化的时候,数据结构中的硬件信息被检测并传递给操作系统
设备树: 设备树源文件(xxxx.dts) —DTC—>>> 设备树二进制文件(xxxx.dtb)
设备树基本语法:
设备树的基本单元是节点(node),这些node被组织成树状结构,除了root node,每个node都只有一个parent node,一个device tree文件中只能有一个root node。每个node中包含了若干的键值对(property/value)来描述该node的一些特性。每个node用节点名字标识。
节点名命名规范:节点名字的格式是[@]。如果该node没有reg属性,那么该节点名字中不能包括@unit-address。unit-address的具体格式是和设备挂在哪个bus上相关。例如对于CPU,其unit-address就是从0开始编址,以此加1,而具体的设备,例如以太网控制器,其unit-address就是寄存器地址。根节点的节点名是确定的,必须是“/”。
节点别名:一个设备可能会使用到别的节点的内容,可以通过节点的别名来引用到其内容。引用的目的可能是合并两个节点的内容、 替换部分内容、或是使用部分内容
节点名 : demo0@0x48000000
节点路径: /demo0@0x48000000
节点别名: demo
demo等价/demo0@80000000
合并节点内容:一个硬件设备的部分信息不会变化,但是另一部分信息是有可能会变化的,就出现了节点内容合并。即:先编写好节点,仅仅描述部分属性值;使用者后加一部分属性值。在同级路径下,节点名相同的“两个”节点实际会自动合并成一个节点 设备树键值对相关语法:[1]. 字符串信息 compatible = "qf-edu,iot-test";[2]. 32位无符号整形数组 word-array = <32 45 67 89>; 例子:reg = <0x10001000 0x24 0x20001000 0x24>;[3]. 二进制数组 bi-array = [0c 20 11 24]; 例子:mac = [FE 02 11 CB 40 58];[4]. 字符数组 string-list = "aaa" , "bbb" , "ccc"; 默认意义的属性: [1]. 设备树语法中已经定义好的,具有通用规范意义的属性如果是设备信息和驱动分离框架的设备节点,则能够在内核初始化找到节点时候,自动解析生成相应的设备信息。 常见属性的有: compatible、地址address、中断interrupt [2]. ARM Linux内核定义好的,一类设备通用的有默认意义的属性不能被内核自动解析生成相应的设备信息,但是内核已经编写了相应的解析提取函数。 常见属性的有: MAC地址、 GPIO、 clock ... Compatible属性:用于匹配设备节点和设备驱动的属性,规则是驱动设备ID表中的compatible域的值(字符串),和设备树中设备节点中的compatible属性值完全一致。 compatible=“厂商名,设备名” ;
platform_driver--->>>struct device_driver driver; struct of_device_id{ char compatible[128]; //用来和设备树中的 compatible属性进行匹配 kernel_ulong_t data;#endif};
地址属性:
reg 描述地址表
#address-cells:描述子节点reg属性值的地址表中首地址元素的数量
#size-cells :描述子节点reg属性值的地址表中地址长度元素的数量
GPIO属性:
gpio-controller:说明该节点描述的是一个gpio控制器
#gpio-cells:描述gpio使用节点的属性一个cell的内容属性名=<&引用GPIO节点别名 GPIO标号 工作模式>;
eg: gpios = <&gpx0 1 1> ;
中断属性:Documentation/devicetree/bindings/interrupt-controller/interrupts.txtDocumentation/devicetree/bindings/interrupt-controller/arm,gic.txt
interrupt-controller
一个空属性用来声明这个node接收中断信号#interrupt-cells 这是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符interrupt-parent 标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的interrupts 一个中断标识符列表,表示每一个中断输出信号
驱动代码中如何从设备树上获取设备信息:
struct device_node { const char *name; //名字 const char *type; //类型 char *full_name; //节点全名 }; //1.获取节点struct device_node *of_find_node_by_name(struct device_node *from,const char *name);功能:通过节点名字查询获取节点参数: @from 查找的时候,从from节点开始向下查找,如果传NULL,从根节点开始查找 @name 节点名返回值:成功返回节点结构体指针,失败返回NULL struct device_node *of_find_node_by_type(struct device_node *from,const char *type); 功能:通过节点类型查询获取节点 参数: @from 查找的时候,从from节点开始向下查找,如果传NULL,从根节点开始查找 @type 节点类型 device_type = “mydemo”;返回值:成功返回节点结构体指针,失败返回NULL
struct device_node *of_find_node_by_path(const char *path); 功能:通过路径来查找 参数: @path 节点路径 返回值:成功返回节点结构体指针,失败返回NULL
//2.获取属性值 int of_property_read_u32_array(const struct device_node *np,const char *propname,\ u32 *out_values, size_t sz) 功能:获取无符号32位整型数组值 参数: @np 设备节点结构体指针 @propname 属性名 @out_values 存放u32类型数据的地址(定义一个u32类型的数组,将数组首地址传递过 来) @sz 获取数组元素的个数
int of_property_read_string(struct device_node *np, const char *propname,const char **out_string) 功能:获取字符串属性值 参数: @np 设备节点结构体指针 @propname 属性名 @out_string 存放字符串地址的变量