一.介绍
1. 基础知识
DTS 即 Device Tree Source 设备树源码,Device Tree 是一种描述硬件的数据结构。
1. dts(device tree source)文件对应一个开发板,一般放置在内核的"arch/arm/boot/dts/"目录下:
2. dtsi:一些相同的 dts 配置可以抽象到 dtsi 文件中,这个 dtsi 文件其实就类似于 C 语言当中的.h 头文件,用法:
3. dtc: device-tree-compiler,就是设备树文件.dts 的编译器。
dtc 工具在 Linux 内核的 scripts/dtc 目录下。
4. dtb:.dts 文件编译成二进制数据之后得到的文件
2. 编译 make dtbs
2.1 编译流程:
执行”make all” 或者是”make dtbs” 命令的时候, arch/arm/boot/dts/Makefile文件中对应的那些 dts 文件就会被编译成 dtb(二进制文件) 文件。
2.2 编译指定的dts
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- system-top.dtb
二. dts语法
1 设备树基础结构体:
/{ //根节点
node1{ //node1节点
property1=value1; //node1节点属性
};
node2{ //node2节点
propertyx=valuex; //node2节点属性
...
node3{ //node2的子节点node3节点
property3=value3; //node3节点属性
};
};
};
2 节点和属性
节点:
label 标签:方便在 dts文件中被其他的节点引用;
node-name :节点名字;
unit-address:一般表示设备的地址或寄存基地址,如果某个节点没有地址或者寄存器的话“ unit-address”可以不要,比如“ cpu@0”、“ interrupt-controller@00a01000”。
示例:
特殊节点:
1. aliases 节点,示例:
2.chosen节点:
一般会有两个属性, “ bootargs”和“ stdout-path”
stdout-path = “ serial0:115200n8” ,表示标准输出设备使用串口 serial0
bootargs:启动参数3. momory节点:
memory 节点描述了系统内存的基地址以及系统内存大小。
属性:
1.字符串 " " 示例: compatible = "arm,cortex-a9";
2.整型数据< > 示例: clock-latency = <1000>; reg = <0x00000000 0x00500000>;3.二进制数据 [ ] 示例:local-mac-address = [00 0a 35 00 1e 53];
4.字符串数组 " "," " 示例:compatible = "n25q512a","micron,m25p80";
5.混合值 都用 示例:mixed-property = "a string", [0x01 0x23 0x45 0x67], <0x12345678>;
6.节点引用:& ,示例:clocks = <&clkc 3>;
7.注释:// 或 /* */
属性解释:
1.compatible 属性:一般使用” <制造商>,<型号>”命名。用于将设备和驱动绑定起来。
2.model属性:字符串描述信息, 它指定制造商的设备型号, model 属性一般定义
在根节点下,一般就是对板子的描述信息,没啥实质性的作用。3.status属性:设备状态。
注意如果节点中没有添加 status 属性,那么它默认就是“ status = okay”。
4.#address-cells 和#size-cells 属性:用于描述子节点的地址信息。
➢ #address-cells,用来描述子节点"reg"属性的地址表中首地址 cell 的数量;
➢ #size-cells,用来描述子节点"reg"属性的地址表中地址长度 cell 的数量reg = <address1 length1 address2 length2 address3 length3……>
5.reg属性:reg 属性的值一般是(address, length)对。 reg 属性一般用于描述设备地址空间资源信息,一般都是描述某个外设的寄存器地址范围信息、 flash 设备的分区信息等,
示例:
6.ranges属性:地址转换表
ranges 属性值可以为空或者(child-bus-address,parent-bus-address,length)
7.device_type 属性:表示节点的类型
此属性在设备树当中用的比较少,一般用于 cpu 节点或者 memory 节点
2.向节点追加或修改内容
向i2c0总线添加24c64和rtc,举例:
&i2c0{
clock-frequency = <100000>;
status = "okey";
24c64@50{
compatible = "atmel,24c64";
reg = <0x50>;
pagesize = <32>;
};
rtc@51{
compatible = "nxp,pcf8563";
reg = <0x51>;
};
};
帮助文档路径:Linux 源码目录/Documentation/devicetree/bindings
三. 设备树常用of操作函数
设备都是以节点的形式“挂”到设备树上的,因此要想获取这个设备的属性信息,必须先
获取到这个设备的节点。
路径:(include/linux/of.h)
device_node 结构体来描述一个节点,如下:
1.节点查找(5个函数)
a.根据名字查找:of_find_node_by_name
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
b.根据device_type属性查找:of_find_node_by_type
struct device_node *of_find_node_by_type(struct device_node *from, const char *type)
c.根据 device_type 和 compatible 这两个属性查找:of_find_compatible_node
struct device_node *of_find_compatible_node(struct device_node *from,
const char *type,const char *compatible)
d.根据 of_device_id 匹配表来查找:of_find_matching_node_and_match
struct device_node *of_find_matching_node_and_match(struct device_node *from,
const struct of_device_id *matches,const struct of_device_id **match)
e.根据节点路径查找:of_find_node_by_path
inline struct device_node *of_find_node_by_path(const char *path)
2.父/子节点查找
a.获取指定节点的父节点
struct device_node *of_get_parent(const struct device_node *node)
b.迭代的查找子节点
struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev)
3.提取属性值
a.查找指定的属性
property *of_find_property(const struct device_node *np,
const char *name,int *lenp)
b.获取属性中元素的数量
int of_property_count_elems_of_size(const struct device_node *np,
const char *propname,int elem_size)
c.从属性中获取指定下标
int of_property_read_u32_index(const struct device_node *np,
const char *propname,u32 index,u32 *out_value)
d.读取属性中 u8、 u16、 u32 和 u64 类型的数组数据
int of_property_read_u8_array(const struct device_node *np,
const char *propname,u8 *out_values,size_t sz)
int of_property_read_u16_array(const struct device_node *np,
const char *propname,u16 *out_values,size_t sz)
int of_property_read_u32_array(const struct device_node *np,
const char *propname,u32 *out_values,size_t sz)
int of_property_read_u64_array(const struct device_node *np,
const char *propname,u64 *out_values,size_t sz)
e.读取只有一个整形值的属性
int of_property_read_u8(const struct device_node *np,
const char *propname,u8 *out_value)
int of_property_read_u16(const struct device_node *np,
const char *propname,u16 *out_value)
int of_property_read_u32(const struct device_node *np,
const char *propname,u32 *out_value)
int of_property_read_u64(const struct device_node *np,
const char *propname,u64 *out_value)
f.读取属性中字符串值
int of_property_read_string(struct device_node *np,
const char *propname,const char **out_string)
g.获取#address-cells 和#size-cells属性值
int of_n_addr_cells(struct device_node *np)
int of_n_size_cells(struct device_node *np)
4.其他常用函数
a.检查设备节点的兼容性
int of_device_is_compatible(const struct device_node *device,const char *compat)
b.获取地址相关属性,主要是“ reg”或者“ assigned-addresses”属性值
const __be32 *of_get_address(struct device_node *dev,
int index,u64 *size,unsigned int *flags)
c.从设备树读取到的地址转换为物理地址
u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
d.从设备树里面提取资源值,本质:将 reg 属性值转换为 resource 结构体类型:
int of_address_to_resource(struct device_node *dev, int index,struct resource *r)
e.内存映射
void __iomem *of_iomap(struct device_node *np,int index)