泰山派学习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-dsi-v10.dtsi:mipi显示屏幕相关的配置  

  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 );

 

posted @   zbl1118  阅读(567)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示