• Linux设备驱动模型之devicetree


    Linux设备驱动模型之devicetree

    当前Linux驱动开发,离不开devicetree的配置,它是干什么的呢?简单理解设备数,它就是一个板子配置信息描述文件。一开始内核并没有没有设备树,关于板端的设备信息都是在代码中描述,从而导致内核的arch目录下非常多板级相关的源文件,都是以.c或.h的格式定义。相对内核的其他而言,这些配置很多重复的,为了解决这样的问题,内核引进了devicetree,专门用来描述板级的配置信息,而内核的驱动则解析设备树获取板级信息进行配置,驱动干驱动的事情,完成了驱动和板级配置的解耦。那么设备树具体是怎样的呢?下面继续跟进。

    devicetree

    设备树是描述板级硬件设备的数据结构文本,设备树文件一般以.dts或.dtsi为后缀的文件进行保存,通过节点和属性来描述板级资源。下面以一个dts文件进行介绍:

    #include 
    #include 	/* dts中可以通过include引用其他的头文件,使用它们的定义 */
    #include "sun8iw18p1-clk.dtsi"		/* 可以引用其它的dts文件 */
    #include "sun8iw18p1-pinctrl.dtsi"
    
    / {			/* device tree,树总会有根,而/则是设备树的根,其他的都是节点,节点可以包含子节点 */
            cpus {	/* cpus作为根节点下的一个子节点,它也包含了cpu0、1两个子节点以及enable-method等属性信息 */
                    enable-method = "allwinner,sun8iw18p1";
                    #address-cells = <1>;
                    #size-cells = <0>;
    
                    cpu@0 {
                            device_type = "cpu";
                            compatible = "arm,cortex-a7","arm,armv7";
                            reg = <0x0>;
                            enable-method = "psci";
                        	/* 描述设备的时钟依赖信息,后续驱动可获取该信息 */
                            clocks = <&clk_pll_cpu>,<&clk_cpu>,<&clk_pll_periph0>;
                            clock-names = "pll","cpu","periph0";
                            operating-points-v2 = <&cpu_opp_l_table0>;
                            cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0 &SYS_SLEEP_0>;
                    };
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    大家可以简单理解,设备树在开机的时候,系统会逐个解析dts并为之注册设备,而我们再编写驱动,当驱动与设备匹配时,则可以正常使用该设备。关于设备树,记住一点:只要符合语法规则即可,其他的都需要由驱动进行解析。所以,除了devicetree的信息外,驱动还需要对设备树进行解析,解析的接口下面介绍。

    常用devicetree api

    从设备树获取整形变量

    int of_property_read_u32(const struct device_node *np,
                             		const char *propname,
                             		u32 *out_value);
    int of_property_read_u16(const struct device_node *np,
                             		const char *propname,
                             		u16 *out_value);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    上述的接口可以从设备树中或者整形变量,比如:

    // dts
            dao: dao-test {
                    compatible = "dao-test";
                    num = <12>;
            };
    
    u32 value;
    np指向dao节点,此时通过 of_property_read_u32(np, "num", &value)获取“num”指向的内容,此时value=12
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    从设备树获取字符串变量

     int of_property_read_string(const struct device_node *np,
                                       const char *propname,
                                       const char **out_string);
    
    • 1
    • 2
    • 3

    而使用方式如下:

    // dts
            dao: dao-test {
                    compatible = "dao-test";
                    num = <12>;
                	str_info = "test_info";
            };
    
    const char *info;
    np指向dao节点,此时通过 of_property_read_string(np, "str_info", &info)获取“str_info”指向的内容,此时info指向的内容是“test_info”。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    更多的api可参考内核include/linux/of.h中的接口进行使用。

    devicetree转换

    设备树是在内核阶段使用的,编辑阶段,是dts的文本状态,而在内核使用时,则是将其转换为dtb二进制文件,系统在启动过程中,uboot再将其加载传递给内核进行使用。而这个设备树的转换则是通过dtc工具进行转换的,dtc工具一般在内核源码中有包含,dtc支持以下命令:

    root@root#./scripts/dtc/dtc --help
    Usage: dtc [options] <input file>
    
    Options: -[qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AThv]
      -q, --quiet
            Quiet: -q suppress warnings, -qq errors, -qqq all
      -I, --in-format <arg>
            Input formats are:
                    dts - device tree source text
                    dtb - device tree blob
                    fs  - /proc/device-tree style directory
      -o, --out <arg>
            Output file
      -O, --out-format <arg>
            Output formats are:
                    dts - device tree source text
                    dtb - device tree blob
                    asm - assembler source
      -V, --out-version <arg>
            Blob version to produce, defaults to 17 (for dtb and asm output)
      -d, --out-dependency <arg>
            Output dependency file
      -R, --reserve <arg>
            Make space for <number> reserve map entries (for dtb and asm output)
      -S, --space <arg>
            Make the blob at least <bytes> long (extra space)
      -p, --pad <arg>
            Add padding to the blob of <bytes> long (extra space)
      -a, --align <arg>
            Make the blob align to the <bytes> (extra space)
      -b, --boot-cpu <arg>
            Set the physical boot cpu
      -f, --force
            Try to produce output even if the input tree has errors
      -i, --include <arg>
            Add a path to search for include files
      -s, --sort
            Sort nodes and properties before outputting (useful for comparing trees)
      -H, --phandle <arg>
            Valid phandle formats are:
                    legacy - "linux,phandle" properties only
                    epapr  - "phandle" properties only
                    both   - Both "linux,phandle" and "phandle" properties
      -W, --warning <arg>
            Enable/disable warnings (prefix with "no-")
      -E, --error <arg>
            Enable/disable errors (prefix with "no-")
      -@, --symbols
            Enable generation of symbols
      -A, --auto-alias
            Enable auto-alias of labels
      -T, --annotate
            Annotate output .dts with input source file and line (-T -T for more details)
      -h, --help
            Print this help and exit
      -v, --version
            Print version and exit
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    dtc支持的参数较多,但我们常用的就是-I -i -O -o这几个参数,通过他们指定输入输出文件和格式,得到dtb文件后再附加到内核镜像。

  • 相关阅读:
    操作系统和计算机网络连环问,你能坚持到第几问?
    厨卫电器行业数字化集采管理系统:优化产业供应结构,实现采购业务流程集中管控
    实践,制作一个高扩展、可视化低代码前端,详实、完整
    Python基础——注释、缩进、语法、标识符、关键字
    Vue快速入门二:Vue绑定事件、Vue中的this指向、增加class选择器、动态创建标签
    k8s集群环境搭建
    数控加工题,每个图片能做一道就好,help同学吧
    QT for andriod
    二叉树前中后序遍历【非递归】
    uniapp制作——交友盲盒
  • 原文地址:https://blog.csdn.net/weixin_41944449/article/details/132799957