目录
4.5 #address-cells和 #size-cells属性
8、根据节点(device_node)找到属性(property)的API
8.3 of_property_read_string_index、of_property_read_string
8.4 of_property_read_u32_index
8.5 of_property_read_u8_array、of_property_read_u16_array...
8.6 of_n_addr_cells:获取#address-cells的值
8.7 of_n_size_cells:获取#size-cells的值
1、设备节点(node)
label : node-name @unit-address {
properties definitions
child nodes
};
label(标号):可以没有,label是为了更方便的引用这个node
unit-address:设备地址
properties:属性,属性由一个键值对组成,具体用法看第二小节
child nodes:子节点
2、属性(property)
属性实际上就是一个键值对,当然,也可以没有值,这代表的是一个标识。
1、字符串类型(" ")
string-property = "string";
2、无符号32位整数(< >)
cell-property = <0xFFFFFFFF>
cells-property = <1 2 3 4> //其中每个数都是一个uint32的数
3、字节序列([ ])一个字节的16进制表示的数
byte-property = [01 23 45 67]
3、节点的一些特性
3.1 在设备树如果有同名的节点会被合并,如果是属性名相同的话,后面的节点会覆盖前面的节点
node {
property1 = "111";
property2 = "222";
};
node {
property2 = "333";
property3 = "444";
};
合并后的节点:
node {
property1 = "111";
property2 = "333";
property3 = "444";
};
3.2 取别名,取别的意义是方便给其他节点引用,取别名有两种办法
取别名方法一:
node : node_node@0xFFFFFFFF {
}
取别名方法二:
aliases {
node_node = &node;
}
引用
&node {
//要增加或者修改的内容
}
3.2 上述引用中其实可以用来删除节点
&node {
/delete-property/property1
}
4、节点的一些标准属性
4.1 compatible属性
compatible属性也叫做“兼容性”属性, compatible属性的值是一个字符串列表, compatible属性用于将设备和驱动绑定起来。字符串列表用于选择设备所要使用的驱动程序, compatible属性的值格式如下所示:
"manufacturer,model"
其中 manufacturer表示厂商, model一般是模块对应的驱动名字。
4.2 model属性
model属性与compatible属性有些类似,但是有差别。compatible属性是一个字符串列表,表示可以你的硬件兼容A、B、C等驱动;model用来准确地定义这个硬件是什么。例如:
{
compatible = "samsung,smdk2440", "samsung,mini2440";
model = "jz2440_v3";
};
它表示这个单板,可以兼容内核中的“smdk2440”,也兼容“mini2440”。
4.3 status属性
dtsi文件中定义了很多设备,但是在你的板子上某些设备是没有的。这时你可以给这个设备节点添加一个status属性,设置为“disabled”,或者默认是disabled,要去开启他,就设置为"okay",例如:
&node {
status = "disabled";
};
4.4 reg属性
reg的本意是register,用来表示寄存器地址。但是在设备树里,它可以用来描述一段空间。反正对于ARM系统,寄存器和内存是统一编址的,即访问寄存器时用某块地址,访问内存时用某块地址,在访问方法上没有区别。reg属性的值,是一系列的“address size”,用多少个32位的数来表示address和size,由其父节点的#address-cells、#size-cells决定。例如:
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
memory {
reg = <0x80000000 0x20000000>;
};
};
4.5 #address-cells和 #size-cells属性
cell指一个32位的数值,address-cells:address要用多少个32位数来表示;size-cells:size要用多少个32位数来表示。比如一段内存,怎么描述它的起始地址和大小?下例中,address-cells为1,所以reg中用1个数来表示地址,即用0x80000000来表示地址;size-cells为1,所以reg中用1个数来表示大小,即用0x20000000表示大小:
/ {
#address-cells = <1>;
#size-cells = <1>;
memory {
reg = <0x80000000 0x20000000>;
};
};
5、device_node结构体
struct device_node {
const char *name; //节点的名字 node
const char *type; //节点的全名 node@0x12345678
struct property *properties; //节点内的属性,是一条链表
struct device_node *parent; //父节点
struct device_node *child; //子节点
struct device_node *sibling; //兄弟节点
};
6、property结构体
struct property {
char *name; //键
int length; //值的长度
void *value; //值
struct property *next; //下一个键值对
};
7、 找到节点(device_node)的API
7.1 定义节点
mynode@0x12345678 {
compatiable = "zgjl,mynode";
string = "AAAAA";
cell = <0x11223344>;
byte = [01 23 24 56 78 9A];
mixed = "BBBB",<0x12345678>,[01 02 03 04];
};
7.2 of_find_node_by_path
static inline struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)
node = of_find_node_by_path("/mynode@0x12345678");
7.3 of_find_node_by_name
static inline struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)
//参数from表示从哪一个节点开始寻找,传入NULL表示从根节点开始寻找。
node = of_find_node_by_name(NULL,"mynode");
7.4 of_find_compatible_node
static inline struct device_node *of_find_compatible_node(
struct device_node *from,
const char *type,
const char *compat)
//参数from表示从哪一个节点开始寻找,传入NULL表示从根节点开始寻找
//参数compat是一个字符串,用来指定compatible属性的值
//参数type是一个字符串,用来指定device_type属性的值,可以传入NULL
node = of_find_compatible_node(NULL,NULL,"zgjl,mynode");
8、根据节点(device_node)找到属性(property)的API
8.1 通过node中的properties属性找到值
//第一个是字符串,name是键,value是值
node->properties->name,(char *)node->properties->value
//第二个是32位无符号整数,__be32_to_cpup是大小端转化函数
node->properties->naxt->name,__be32_to_cpup(node->properties->next->value
8.2 of_find_property
static inline struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)
//参数np表示节点,我们要在这个节点中找到名为name的属性。
//lenp用来保存这个属性的长度,即它的值的长度。
prop = of_find_property(node,"byte",&len);
for (int i = 0; i < len; i++) {
printk("name=%s,value=%#x\n","binint",*(char *)(prop->value+i));
}
8.3 of_property_read_string_index、of_property_read_string
static inline int of_property_read_string_index(const struct device_node *np,
const char *propname,
int index, const char **output)
static inline int of_property_read_string(const struct device_node *np,
const char *propname,
const char **out_string)
//np:设备节点。
//proname 要读取的属性名字。
//out_string:读取到的字符串值。
of_property_read_string_index(node,"string",0,&value);
printk("string = %s\n", value);
8.4 of_property_read_u32_index
static inline int of_property_read_u32_index(const struct device_node *np,
const char *propname, u32 index, u32 *out_value)
//np:设备节点。
//proname 要读取的属性名字。
//index:要读取的值标号。
//out_value:读取到的值
of_property_read_u32_index(node,"cell",0,&u32_val);
printk("cell = %#x\n", u32_val);
8.5 of_property_read_u8_array、of_property_read_u16_array...
static inline int of_property_read_u8_array(const struct device_node *np,
const char *propname, u8 *out_values, size_t sz)
//np:设备节点。
//proname 要读取的属性名字。
//out_value:读取到的数组值,分别为 u8、 u16、 u32和 u64。
//sz 要读取的数组元素数量。
static inline int of_property_read_u16_array(const struct device_node *np,
const char *propname, u16 *out_values, size_t sz)
static inline int of_property_read_u32_array(const struct device_node *np,
const char *propname, u32 *out_values, size_t sz)
static inline int of_property_read_u64_array(const struct device_node *np,
const char *propname, u64 *out_values, size_t sz)
of_property_read_u8_array(node,"binint",u8_arr,6);
for (int i = 0; i < 6; i++) {
printk("u8_arr[%d] = %#x\n", i, u8_arr[i]);
}
8.6 of_n_addr_cells:获取#address-cells的值
int of_n_addr_cells(struct device_node *np)
{
const __be32 *ip;
ip = of_get_property(np, "#address-cells", NULL);
if (ip)
return be32_to_cpup(ip);
}
8.7 of_n_size_cells:获取#size-cells的值
int of_n_size_cells(struct device_node *np)
{
const __be32 *ip;
ip = of_get_property(np, "#size-cells", NULL);
if (ip)
return be32_to_cpup(ip);
}
9、小知识
1、查看设备树
cd /sys/firmware/devicetree/base/
2、编译设备树文件
找到内核文件 make dtbs
3、设备树文件在 arch/arm/boot/dts 中