泰山派学习09--设备树DTS
一、设备树定义
设备树就是用于描述硬件信息的一个配件文件,其是一种树状的结构,有节点(node)和属性(property)组成。每个节点描述一个硬件设备或资源,属性描述了设备的特性。
二、设备树术语及关系
1、设备树文件(Device Tree Source):格式为dts,类似C语言的.c文件;
2、设备树包含文件(Device Tree Source Include):格式为dtsi,可以通过 #include
指令在其他设备树源文件中引用。用于共享公共的设备树定义和配置,类似c语言的.h文件;
3、设备树编译器(Device Tree Compiler):用于将设备树源文件(DTS)编译成设备树二进制文件(DTB)的工具,类似c语言的gcc编译器;
4、设备树二进制文件(Device Tree Blob):设备树源文件编译生成的二进制文件,类似c语言的.hex或者bin文件;
5、节点(Node):在设备树中用来描述硬件设备或资源的一个独立部分。每个节点都有一个唯一的路径和一组属性;
6、属性(Property):用于描述节点的特征和配置信息,包括设备的名称、地址、中断号、寄存器配置等;
7、属性值(Property Value):属性中的具体数据,可以是整数、字符串、布尔值等各种类型;
8、父节点与子节点(Parent Node and Child Node):在设备树中,每个节点都可以有一个父节点和多个子节点,用于描述设备之间的连接关系。
三、泰山派的设备树
泰山派使用rk3566的主控芯片,在泰山派SDK/kernel/arch/arm64/boot/dts/rockchip 路径下有瑞芯微64位架构处理器的所有设备树及其相关文件。
rk3568.dtsi :主控相关配置
rk3566.dtsi :包含了rk3568.dtsi头文件配置
tspi-rk3566-core-v10.dtsi :tspi核心配置层,这里是几乎后期不需要怎么改动
tspi-rk3566-gmac1-v10.dtsi :网口相关配置
tspi-rk3566-csi-v10.dtsi :mipi摄像头相关配置
tspi-rk3566-edp-v10.dtsi :edp显示屏幕相关的配置
tspi-rk3566-hdmi-v10.dtsi :hdmi显示屏相关的配置
tspi-rk3566-user-v10-linux.dts:用户自定义相关配置他会去包含前面的所有
四、单独DTC编译器的安装、编译、反编译
1、安装
sudo apt update #更新源
sudo apt install device -tree -complier #安装dtc
dtc --version #查看dtc 是否安装成功
2、编译(编译.dts 和.dtsi ,生成.dtb)==>如果使用sdk的编译器,必须使用绝对路径(泰山派sdk/kernel/scripts/dtc/dtc)替代单独安装的dtc编译器。
dtc -I dts -O dtb -o output_file.dtb input_file.dts
①:-I dts 指定输入文件格式为dts
②:-O dtb 指定输出文件格式为dtb
③:-o output_file.dtb 设置输出dtb文件名称
④:input_file.dts 需要编译的dts文件。
3、反编译(反编译.dtb ,生成.dts)
dtc -I dtb -O dts -o output_file.dts input_file.dtb
①:-I dtb 指定输入文件格式为dtb
②:-O dts 指定输出文件格式为dts
③:-o output_file.dts 设置输出dts文件名称
④:input_file.dtb 需要反编译的dtb文件。
五、设备树语法
1、注释(与c语言一样)
// 单行注释
/* */ 多行注释
2、包含.dtsi文件
/include/ "xxx.dtsi" //包含需要调用.dtsi文件名称
3、包含.dtsi文件或者.h文件(#include
是非设备树语法他是c语言语法,需要先用cpp编译生成一个预编译文件,然后在用dtc编译这个预编译文件生成dtb)
#include "xxx.dtsi" // 包含需要调用的.dtsi文件名称
#include "xxx.h" //包含需要调用的.h 文件名称
3.1、预编译命令(使用cpp 工具将xxx.dts文件中的头文件展开,生成一个临时文件xxxx.dtb.dts.tmp
)
cpp -nostdinc -I[dir_with_dts_includes] -x assembler-with-cpp [src_dts_file] > [tmp_dts_file]
①:-nostdinc :不使用标准的系统头文件目录,避免不必要的报错
②、 -I[dir_with_dts_includes] :这里是头文件的目录,如果就是在当前目录就用I.
③、 [src_dts_file] :编译的源设备树文件(.dts
)
④、tmp_dts_file:是预处理后的输出文件,为了和瑞芯微保持统一我们到时候命名后最写成xxxxxxxxxxxx.dtb.dts.tmp
3.2 编译(把预编译文件xxx.dts.tmp 编译为xxx.dtb)
dtc -I dts -O dtb -o output_file.dtb input_file.dts.tmp
3.3 反编译(把xxx.dtb反编译为xxx.dts)
dtc -I dtb -O dts -o output_file.dts input_file.dtb
六、设备树节点
/dts-v1/; //dts 版本
/{
标签:节点名@单元地址{
属性=“xxx”;
子节点1{
};
子节点2{
};
};
};
1、根节点:/ 根节点,类似根文件目录
2、子节点
①:标签、节点名和单元地址,其中标签可引用、单元地址可选填
②:一对花括号和分号结束{};
③:属性定义(可以是字符串、整数、列表、空值、引用 )
字符串:compatible = "rockchip, rk3566";
整数:reg = <0x0100, 0x01>;
列表: interrupts = <0 93 4>, <0 41 4>, <0 40 4>;
空值:regulator-always-on; //表示永远开启
引用:gpio = <&gpio1 RK_PB0 GPIO_ACTION_LOW>
④:子节点定义
七、设备树属性
设备树属性是键对值,用于定义节点的硬件相关参数。属性类型有如下
1、字符串
属性名称:compatible
属性示例:compatible = “lckfb, tpsi-v1","rockchip, rk3566”;
2、整数
属性名称:reg
属性示例:reg = <0x1000>;
3、数组
属性名称:reg
属性示例:reg = <0x1000, 0x01>;
4、列表
属性名称: interrupts
属性示例:interrupts = <0 39 4>,<0 40 4>,<0 41 4>;
5、空值
属性名称:regulator-always-on
属性示例:regulator-always-on;
6、引用
属性名称:gpios
属性示例:gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_LOW>
model 属性 ==> 字符串属性,用于描述开发板型号
示例:modle = "lckfb tspi v10 borad";
compatible 属性 ==> 最关键属性,字符串或字符串列表属性,用于标识设备的兼容性。操作系统使用该属性来匹配设备与对应驱动程序
示例: compatible = "rockship,rockchip_headset", "rockchip,rockchip_headset2";
①、第一个参数manufacture:表示厂商
②、第二参数model:表示模块对应的驱动名字
驱动程序:static const struct of_device_id rockchip_headset_of_match[]={
{.compatible = "rockchip_headset", }, //与设备树定义属性匹配
{}, //必须留空的结束符
};
MODULE_DEVICE_TABLE(of, rockchip_headset_of_match);
reg属性 ==> 包含基址与大小,配合父节点的address-cells 和size-cells使用。描述设备的物理地址访问
示例: gmac1 : ethernet@fe010000 {
reg = <0x0 0xfe010000 0x0 0x10000>;
};
#address-cells 与 #size-cells属性 ==> 必须为整数,用于说明父节点如何解释它子节点的reg属性
reg = <[address1] [length1] [address2] [length2]....>;
①、addressN: 表示区域的起始物理地址,用多少个无符号整数来表示这个地址取决于父节点定义的#address-cells
的值。
例如,如果#address-cells
为1,则使用一个32位整数表示地址;如果#address-cells
为2,则使用两个32位整数表示一个64位地址。
②、lengthN: 表示区域的长度(或大小)。用多少个无符号整数来表示这个长度同样取决于父节点定义的#size-cells
的值.
示例:
/ {
#address-cells = <2>;
#size-cells = <2>;
cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu0: cpu@0 {
受cpus节点的影响
#address-cells = <2>;
#size-cells = <0>;
所以地址就是0x0,大小就是 0x0
*/
reg = <0x0 0x0>;
};
};
gmac1: ethernet@fe010000 {
/*
受根节点的影响
#address-cells = <2>;
#size-cells = <2>;
所以地址就是0xfe010000 ,大小就是 0x10000
*/
reg = <0x0 0xfe010000 0x0 0x10000>;
};
};
status属性 ==> 非常重要的字符串属性,打开某个节点或者关闭某个节点,最常用的是okay、disabled、fail 、fail-sss。
示例:&leds {
status = "okay"; //开启leds
};
&rk_headset{
status = "disabled"; //关闭耳机检测
};
decice_type属性 ==>字符串属性,仅用于cpu和memory节点描述
示例: cpus {
device_type = "cpu";
};
八、获取设备树节点信息
1、查找节点函数
struct device_node *of_find_node_by_path(const char *path);
其中struct device_node{
const char *name;
const char *type;
phandle phandle;
const char *full_name;
struct fwonde_handle fwnode;
......
}
2、根据节点类型寻找节点函数
struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
3、根据节点类型和compatible属性寻找节点函数
struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible);
4、根据匹配表寻找节点函数
static inline struct device_node *of_find_matching_node_and_match(struct device_node *from, const struct of_device_id *matches, const struct device_id **match)
struct of_device_id {
char name[32];
char type[32];
char compatible[128];
const void *data;
}
5、寻找父节点函数
struct device_node*of_get_parent(const struct );
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)