对设备树、DTS语法、设备树中常用函数 的认识(简单总结)

2024-09-04 05:04

本文主要是介绍对设备树、DTS语法、设备树中常用函数 的认识(简单总结),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        设备树(Device Tree)是一种数据结构,用于描述硬件的板级设备信息。它由一系列被命名的节点(node)和属性(property)组成,这些节点和属性共同构成了描述硬件设备的树形结构。设备树主要用于嵌入式系统和复杂硬件平台的开发中,特别是当硬件设备的种类和数量众多,且每个设备都有其独特的配置和特性时。

1、设备树的主要组成部分

  1. DTS(Device Tree Source)文件

    • DTS文件是设备树的源码文件,采用ASCII文本格式编写,文件扩展名为.dts。
    • DTS文件通过树形结构描述板级设备信息,如CPU数量、内存基地址、外设接口(如IIC、SPI)上连接的设备等。
    • 每个设备在DTS文件中表示为一个节点,节点通过属性来描述设备信息,属性是键值对的形式。
  2. DTSI(Device Tree Include)文件

    • DTSI文件类似于C语言中的头文件,用于描述SOC级别的内部外设信息,如CPU架构、主频、外设寄存器地址范围等。
    • DTS文件可以引用DTSI文件,以减少代码冗余,便于维护和共享。
  3. DTC(Device Tree Compiler)工具

    • DTC工具用于将DTS文件编译成二进制格式的DTB(Device Tree Blob)文件。
    • DTC工具的源码位于Linux内核的scripts/dtc目录下。
  4. DTB(Device Tree Blob)文件

    • DTB文件是DTS文件编译后的二进制文件,由Linux内核解析。
    • DTB文件包含了设备树的完整信息,用于在系统启动阶段配置和初始化硬件设备。

2、设备树的作用

  • 分离硬件描述与内核代码:设备树将硬件描述信息与内核代码分离,避免了硬编码方式带来的问题,如内核臃肿、修改硬件信息需重新编译内核等。
  • 简化硬件适配:对于同一SOC的不同主板,只需更换设备树文件即可实现无差异支持,无需更换内核文件。
  • 提高系统可移植性:设备树的使用使得Linux系统更容易移植到不同的硬件平台上。

3、设备树的使用方法

  1. 编写DTS文件

    • 根据硬件平台的实际情况,编写描述板级设备信息的DTS文件。
    • 使用设备树语法定义节点和属性,确保信息的准确性和完整性。
  2. 编译DTS文件

    • 使用DTC工具将DTS文件编译成DTB文件。编译过程通常在系统编译阶段完成。
    • 编译命令示例:make dtbs(在Linux内核源码根目录下执行)
  3. 加载DTB文件

    • 在系统启动阶段,bootloader负责加载启动镜像并提取其中的DTB文件。
    • Bootloader将DTB文件传递给内核,内核根据其中的设备树信息来配置和初始化硬件设备。
  4. 内核解析DTB文件

    • 内核在接收到DTB文件后,会对其进行解析。
    • 解析过程中,内核会根据设备树中的节点和属性来创建对应的设备对象,并为它们设置相应的属性和配置。
  5. 设备树匹配与驱动加载

    • 内核在解析设备树的过程中,会根据设备节点的“compatible”属性来匹配相应的驱动程序。
    • 一旦找到匹配的驱动程序,内核就会将其加载并用于设备的初始化和管理。

综上所述,设备树是Linux系统中一种非常重要的硬件描述机制,它通过树形结构描述板级设备信息,简化了硬件适配过程,提高了系统的可移植性和灵活性。在使用设备树时,需要掌握DTS文件的编写方法、DTC工具的使用以及内核对DTB文件的解析过程。

4、DTS语法

        DTS(Device Tree Source)是一种基于文本的描述硬件设备的语言,它允许开发者以一种结构化的方式来定义硬件的配置信息。DTS语法相对简单但严格,以下是对DTS语法的详细解析:

一、文件结构

DTS文件采用树状结构来组织设备信息,每个文件通常包含一个根节点(/),根节点下可以有多个子节点,子节点下还可以有更深层次的子节点,以此类推。

二、节点(Node)

节点是DTS文件的基本组成单元,用于表示硬件设备或总线。节点的基本语法如下:

[label:]node-name[@unit-address]{  [properties definitions];  [child nodes];  
};
  • label:可选的标签,用于方便地引用节点。
  • node-name:节点名称,由数字、大小写字母、逗号(,)、点(.)、下划线(_)等组成,且必须以字母开头。
  • unit-address:可选的设备地址,用于唯一标识具有相同节点名的不同设备。
  • properties definitions:节点的属性定义,描述设备的特性和参数。
  • child nodes:子节点,节点下可以嵌套子节点,形成树状结构。

三、属性(Property)

属性用于描述节点的特性和参数,其基本语法如下:

[label:]property-name = value;
  • label:可选的标签,用于引用属性。
  • property-name:属性名称。
  • value:属性值,可以是字符串、整数、数组等类型。

属性值的具体表示方式如下:

  • 字符串:用双引号(")括起来,如compatible = "arm,cortex-a7";
  • 整数:用尖括号(< >)括起来,如reg = <0x1000 0x100>;。64位整数由两个32位整数表示,如<0x00000001 0x00000000>
  • 数组:用尖括号括起来的整数列表,如interrupts = <17 0xc>;
  • 字节序列:用方括号([ ])括起来的字节列表,每个字节用两个十六进制数表示,如local-mac-address = [00 00 12 34 56 78];

四、特殊属性和节点

1. compatible属性

用于指定设备的兼容信息,通常由制造商和设备型号组成,如compatible = "fsl,imx6ull-gpmi-nand";。这个属性是驱动和设备匹配的关键。

2. status属性

表示设备的运行状态,可选值包括okaydisabledfail等。

3. #address-cells和#size-cells属性

        这两个属性的值都是无符号 32 位整形, #address-cells #size-cells 这两个属性可以用在任
何拥有子节点的设备中,用于描述子节点的地址信息。 #address-cells 属性值决定了子节点 reg
性中地址信息所占用的字长 (32 ) #size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性
都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度, reg 属性的格式一为:

reg = <address1 length1 address2 length2 address3 length3……>
每个“ address length ”组合表示一个地址范围,其中 address 是起始地址, length 是地址长
度, #address-cells 表明 address 这个数据所占用的字长, #size-cells 表明 length 这个数据所占用
的字长。

4. reg属性

用于描述设备的地址范围,格式通常为reg = <address length [address2 length2] ...>;

5.ranges属性

        ranges属性的值可以为空,或者按照(child-bus-address, parent-bus-address, length)的格式编写的数字矩阵。每个元素代表一个地址映射项,包含三部分:子地址(child-bus-address)、父地址(parent-bus-address)和地址空间长度(length)。

6. chosen节点

chosen节点不表示一个实际的硬件设备,而是用于向内核传递启动参数,如bootargs

7. aliases节点

aliases节点用于定义别名,方便在设备树中引用其他节点。 

五、包含dtsi文件和宏定义

        DTS文件可以包含dtsi文件,类似于C语言中的头文件包含。dtsi文件通常包含一些通用的设备树定义,可以在多个DTS文件中共享。此外,DTS文件还可以使用宏定义来简化属性的编写,这些宏定义通常定义在专门的头文件中。

六、编译与反编译

        DTS文件需要通过设备树编译器(dtc)编译成设备树二进制文件(dtb),才能被内核解析。同时,dtb文件也可以通过dtc反编译回dts文件,以便于修改和调试。

七、DTS语法举例

/ {  model = "Example Board with Example Device";  compatible = "generic-board", "vendor,example-device";  // Memory节点,描述物理内存的布局  memory@80000000 {  device_type = "memory";  reg = <0x80000000 0x40000000>; // 起始地址0x80000000,大小0x40000000(1GB)  };  // Cpus节点,描述CPU信息  cpus {  #address-cells = <1>;  #size-cells = <0>;  cpu@0 {  device_type = "cpu";  compatible = "arm,cortex-a9";  reg = <0>; // 标识CPU核心0  enable-method = "psci"; // 启用方法,使用PSCI协议  status = "okay";  };  };  // Chosen节点,用于传递系统指定的运行时参数给内核  chosen {  bootargs = "console=ttyO0,115200n8 root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait";  };  // Aliases节点,定义别名以便更方便地引用设备树中的其他节点  aliases {  serial0 = &uart0;  ethernet0 = &eth0;  };  // 串口(UART)设备节点  uart0: uart@40002000 {  compatible = "ns16550";  reg = <0x40002000 0x1000>;  interrupts = <18>;  clock-frequency = <1843200>;  };  // 以太网设备节点  eth0: ethernet@40008000 {  compatible = "smc,smc91111";  reg = <0x40008000 0x1000>;  interrupts = <23>;  mac-address = [00 12 34 56 78 9A];  fixed-link {  speed = <100>;  full-duplex;  };  };  // I2C控制器节点  i2c1: i2c@40020000 {  compatible = "i2c-compatible";  reg = <0x40020000 0x1000>;  #address-cells = <1>;  #size-cells = <0>;  // I2C设备节点(EEPROM)  eeprom@50 {  compatible = "eeprom-compatible";  reg = <0x50>;  };  };  // 另一个串口设备节点,用于展示不同的设备实例  serial@40080000 {  compatible = "ns16550";  reg = <0x40080000 0x1000>;  interrupts = <18>;  clock-frequency = <1843200>;  };  
};

详细介绍

  1. 根节点(/`)
    • model:设备的型号或名称。
    • compatible:设备的兼容性字符串,用于匹配驱动程序。
  2. 内存节点 (memory@80000000):
    • device_type: 指明了这是一个内存设备。
    • reg: 描述了内存的物理地址和大小,这里是起始地址0x80000000,大小为0x40000000(即1GB)。
  3. CPU节点 (cpus):
    • #address-cells 和 #size-cells: 描述了CPU子节点中reg属性的地址单元和大小单元的数量。
    • cpu@0: 描述了第一个CPU核心的信息。
      • device_type: 指明了这是一个CPU设备。
      • compatible: 描述了CPU兼容的类型,这里是“arm,cortex-a9”。
      • reg: 标识了CPU核心的编号,这里是0。
      • enable-method: 描述了启用CPU的方法,这里是使用PSCI协议。
      • status: 描述了CPU的状态,这里是“okay”,表示正常。
  4. Chosen节点 (chosen):
    • bootargs: 传递了系统指定的运行时参数给内核,包括控制台设置、根文件系统设置等
  5. Aliases节点 (aliases):
    • 定义了别名以便更方便地引用设备树中的其他节点,如serial0引用uart0ethernet0引用eth0
  6. 串口(UART)设备节点 (uart0: uart@40002000):
    • compatible: 描述了UART设备兼容的类型,这里是“ns16550”。
    • reg: 描述了UART设备的物理地址和大小。
    • interrupts: 描述了UART设备使用的中断号。
    • clock-frequency: 描述了UART设备的时钟频率。
  7. 以太网设备节点 (eth0: ethernet@40008000):
    • compatible: 描述了以太网设备兼容的类型,这里是“smc,smc91111”。
    • reg: 描述了以太网设备的物理地址和大小。
    • interrupts: 描述了以太网设备使用的中断号。
    • mac-address: 描述了以太网设备的MAC地址。
    • fixed-link: 描述了以太网设备的固定链接属性,如速度和是否全双工。

        在这个DTS例子中,定义了设备的型号、兼容性、CPU、内存、串行通信和I2C控制器等硬件设备的信息。这些信息被编译成设备树二进制文件(DTB),并在系统启动时由内核解析,用于配置和初始化硬件设备。

八、DTS追加信息

        在DTS(Device Tree Source)根节点外中追加信息,通常涉及对现有的DTS文件进行编辑,以添加新的设备节点、属性或修改现有节点的配置。以下是一些步骤和注意事项,用于在DTS中追加信息:

1. 确定追加位置

        首先,需要确定在DTS文件中追加信息的具体位置。这通常取决于要添加的设备类型以及它在硬件系统中的位置。例如,如果要添加一个连接到I2C总线的传感器,你需要在I2C控制器的子节点下添加一个新的子节点。

2. 编辑DTS文件

        使用文本编辑器打开DTS文件,然后按照设备树的语法规则添加新的节点或属性。在添加新节点时,需要注意节点命名、属性格式以及可能的依赖关系。

例如,要在I2C控制器下添加一个温度传感器节点,可以添加类似以下内容的代码:

&i2c1 { /* 假设i2c1是已经存在的I2C控制器节点 */  status = "okay";  temp_sensor@48 {  compatible = "vendor,temp-sensor";  reg = <0x48>;  interrupts = <&gpio 24 IRQ_TYPE_EDGE_FALLING>; /* 假设温度传感器通过GPIO触发中断 */  };  
};

        在这个例子中,temp_sensor@48是新添加的温度传感器节点,@48指定了它在I2C总线上的地址。compatible属性用于指定温度传感器的兼容性字符串,以便内核能够找到正确的驱动程序。reg属性指定了设备在I2C总线上的地址,而interrupts属性(如果适用)指定了设备的中断配置。

3. 编译DTS文件

        修改完DTS文件后,需要使用设备树编译器(DTC)将其编译成设备树二进制文件(DTB)。这通常通过内核的构建系统来完成,可以使用make dtbs命令(在内核源码目录下)来编译所有DTS文件。

4. 部署DTB文件

        编译生成的DTB文件需要被部署到目标系统的适当位置,以便在启动时由Bootloader加载到内存中,并由内核解析。

5. 验证和调试

        在部署了修改后的DTB文件后,重新启动系统以验证新添加的设备是否按预期工作。可以使用/proc/device-tree目录下的文件来检查内核是否正确地解析了设备树,并使用适当的驱动程序来配置和管理硬件设备。

注意事项

  • 在修改DTS文件时,请确保遵循设备树的语法规则,以避免编译错误。
  • 如果不确定某个属性的用途或格式,请参考相应的绑定文档或内核文档。
  • 在修改设备树之前,最好备份原始文件,以便在出现问题时可以恢复。
  • 某些设备可能需要特定的配置步骤或额外的驱动程序支持才能正常工作。请确保已经完成了所有必要的配置和安装步骤。

九、节点命名规范

一、命名格式

        设备树中的节点名字通常遵循“node-name@unit-address”的格式,但并非所有节点都必须包含单元地址(unit-address)。这个格式允许节点名字清晰地描述节点的功能和位置。

  • node-name:节点名字,为ASCII字符串,应该能够清晰地描述出节点的功能。例如,“uart1”就表示这个节点是UART1外设。
  • @unit-address:单元地址,一般表示设备的地址或寄存器首地址。如果某个节点没有地址或者寄存器,这个部分可以省略。

        此外,还有一种常见的格式是在节点名字前使用标签(label)和冒号(:)进行标识,即“[label:]node-name[@unit-address]”。引入标签的目的是为了方便访问节点,可以直接通过&label来访问该节点,而不需要输入完整的节点名字。

二、字符限制

设备树中的节点名字长度通常为1到31个字符,且仅由特定的字符集组成。这些字符包括字母(A-Z, a-z)、数字(0-9)以及下划线(_)等。特殊字符(如空格、斜杠等)通常不被允许出现在节点名字中。

三、命名逻辑

节点名字的命名应遵循一定的逻辑,以便于理解和维护。以下是一些建议的命名逻辑:

  • 描述性功能:节点名字应尽可能描述其功能或用途,如“uart”、“gpio”、“ethernet”等。
  • 唯一性:在同一设备树中,节点名字应该是唯一的,以避免混淆。
  • 继承性:如果节点之间存在父子关系,子节点的名字可以在一定程度上继承父节点的特性或功能描述,但应确保唯一性。
  • 简洁性:在保持描述性功能的前提下,节点名字应尽量简洁明了,避免使用过长或过于复杂的名字。

四、其他注意事项

  • 大小写敏感:在设备树中,节点名字是大小写敏感的,因此在命名和引用时需要注意大小写的一致性。
  • 避免使用保留字:在命名节点时,应避免使用设备树语法中的保留字,如/(根节点路径)、#(用于特殊属性名)等。
  • 遵循惯例:在遵循上述规范的基础上,还可以参考行业内的命名惯例或标准,以提高设备树的兼容性和可移植性。

5、设备树常用 OF 操作函数

5.1. 查找节点

1 of_find_node_by_name 函数
of_find_node_by_name 函数通过 节点名字查找 指定的节点,函数原型如下:
struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
函数参数和返回值含义如下:
        from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
        name:要查找的节点名字。
        返回值:找到的节点,如果为 NULL 表示查找失败
2 of_find_node_by_type 函数
of_find_node_by_type 函数通 过 device_type 属性查找 指定的节点,函数原型如下:
struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
函数参数和返回值含义如下:
        from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
        type:要查找的节点对应的 type 字符串,也就是 device_type 属性值。
        返回值:找到的节点,如果为 NULL 表示查找失败.
3 of_find_compatible_node 函数
of_find_compatible_node 函数根据 device_type 和 compatible 这两个属性查找 指定的节点,
函数原型如下:
struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible)
函数参数和返回值含义如下:
        from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
        type:要查找的节点对应的 type 字符串,也就是 device_type 属性值,可以为 NULL ,表示
忽略掉 device_type 属性。
        compatible: 要查找的节点所对应的 compatible 属性列表。
        返回值:找到的节点,如果为 NULL 表示查找失败
4 of_find_matching_node_and_match 函数
of_find_matching_node_and_match 函数通过 of_device_id 匹配表来查找指定的节点,函数原
型如下:
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)
函数参数和返回值含义如下:
        from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
        matches of_device_id 匹配表,也就是在此匹配表里面查找节点。
        match: 找到的匹配的 of_device_id
        返回值:找到的节点,如果为 NULL 表示查找失败
5 of_find_node_by_path 函数
of_find_node_by_path 函数 通过路径来查找 指定的节点,函数原型如下:
inline struct device_node *of_find_node_by_path(const char *path)
函数参数和返回值含义如下:
        path:带有全路径的节点名,可以使用节点的别名,比如“ /backlight ”就是 backlight 这个
节点的全路径。
        返回值:找到的节点,如果为 NULL 表示查找失败

5.2 查找父/子节点的函数

1 of_get_parent 函数
of_get_parent 函数用于获取指定节点的父节点 (如果有父节点的话) ,函数原型如下:
struct device_node *of_get_parent(const struct device_node *node)
函数参数和返回值含义如下:
        node:要查找的父节点的节点。
        返回值:找到的父节点。
2 of_get_next_child 函数
of_get_next_child 函数用 迭代的方式查找子节点 ,函数原型如下:
struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev)
函数参数和返回值含义如下:
        node:父节点。
        prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子节点。可以设置为
NULL ,表示从第一个子节点开始。
        返回值:找到的下一个子节点。

5.3 提取属性值的函数

1 of_find_property 函数
of_find_property 函数用于 查找指定的属性 ,函数原型如下:
property *of_find_property(const struct device_node *np, const char *name, int *lenp)
函数参数和返回值含义如下:
        np:设备节点。
        name: 属性名字。
        lenp:属性值的字节数
        返回值:找到的属性
2 of_property_count_elems_of_size 函数
of_property_count_elems_of_size 函数用 于获取属性中元素的数量 ,比如 reg 属性值是一个
数组,那么使用此函数可以获取到这个数组的大小,此函数原型如下:
int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size)
函数参数和返回值含义如下:
        np:设备节点。
        proname: 需要统计元素数量的属性名字。
        elem_size:元素长度。
        返回值:得到的属性元素数量。
3 of_property_read_u32_index 函数
of_property_read_u32_index 函数用于从属性中获取指定标号的 u32 类型数据值 ( 无符号 32
) ,比如某个属性有多个 u32 类型的值,那么就可以使用此函数来获取指定标号的数据值,此
函数原型如下:
int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value)
函数参数和返回值含义如下:
        np:设备节点。
        proname: 要读取的属性名字。
        index:要读取的值标号。
        out_value:读取到的值
        返回值:0 读取成功,负值,读取失败, -EINVAL 表示属性不存在, -ENODATA 表示没有要读取的数据, -EOVERFLOW 表示属性值列表太小。
4 of_property_read_xxx_arry 函数
        函数中的 xxx 分别是读取属性中 u8、u16、u32 u64 类型的数组数据,比如大多数的 reg
性都是数组数据,可以使用这 4 个函数一次读取出 reg 属性中的所有数据。这四个函数的原型
如下:
int of_property_read_xxx_array(const struct device_node *np, const char *propname, xxx*out_values, size_t sz)
函数参数和返回值含义如下:
        np:设备节点。
        proname: 要读取的属性名字。
        out_value:读取到的数组值,分别为 u8 u16 u32 u64
        sz: 要读取的数组元素数量。
        返回值:0 ,读取成功,负值,读取失败, -EINVAL 表示属性不存在, -ENODATA 表示没
有要读取的数据, -EOVERFLOW 表示属性值列表太小
5 of_property_read_xxx  函数
        有些属性只有一个整形值,这四个函数就是用于读取这种只有一个整形值的属性, XXX 可以是分别用于读取 u8、u16、u32 u64 类型属性值,函数原型如下:
int of_property_read_ xxx (const struct device_node *np, const char *propname, xxx *out_value)
函数参数和返回值含义如下:
        np:设备节点。
        proname: 要读取的属性名字。
        out_value:读取到的数组值。
        返回值:0 ,读取成功,负值,读取失败, -EINVAL 表示属性不存在, -ENODATA 表示没有要读取的数据, -EOVERFLOW 表示属性值列表太小。
6 of_property_read_string 函数
of_property_read_string 函数用于读取属性中字符串值,函数原型如下:
int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)
函数参数和返回值含义如下:
        np:设备节点。
        proname: 要读取的属性名字。
        out_string:读取到的字符串值。
        返回值:0 ,读取成功,负值,读取失败
7 of_n_addr_cells 函数
of_n_addr_cells 函数用于获取 #address-cells 属性值,函数原型如下:
int of_n_addr_cells(struct device_node *np)
函数参数和返回值含义如下:
        np:设备节点。
        返回值:获取到的 #address-cells 属性值。
8 of_n_size_cells 函数
of_size_cells 函数用于获取 #size-cells 属性值,函数原型如下:
int of_n_size_cells(struct device_node *np)
函数参数和返回值含义如下:
        np:设备节点。
        返回值:获取到的 #size-cells 属性值。

5.4其他常用的函数

1 of_device_is_compatible 函数
of_device_is_compatible 函数用于查看节点的 compatible 属性是否有包含 compat 指定的字
符串,也就是检查设备节点的兼容性,函数原型如下:
int of_device_is_compatible(const struct device_node *device, const char *compat)
函数参数和返回值含义如下:
        device:设备节点。
        compat:要查看的字符串。
        返回值:0 ,节点的 compatible 属性中不包含 compat 指定的字符串;正数,节点的 compatible 属性中包含 compat 指定的字符串。
2 of_get_address 函数
of_get_address 函数用于获取地址相关属性,主要是“ reg ”或者“ assigned-addresses ”属性
值,函数原型如下:
const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags)
函数参数和返回值含义如下:
        dev:设备节点。
        index:要读取的地址标号。
        size:地址长度。
        flags:参数,比如 IORESOURCE_IO IORESOURCE_MEM
        返回值:读取到的地址数据首地址,为 NULL 的话表示读取失败。
3 of_translate_address 函数
of_translate_address 函数负责将从设备树读取到的地址转换为物理地址,函数原型如下:
u64 of_translate_address(struct device_node *dev,const __be32*in_addr)
函数参数和返回值含义如下:
        dev:设备节点。
        in_addr:要转换的地址。
        返回值:得到的物理地址,如果为 OF_BAD_ADDR 的话表示转换失败
4 of_address_to_resource 函数
of_address_to_resource 函数是从设 备树里面提取资源值,但是本质上就是将 reg 属性值,然后将其转换为 resource 结构体类型, 函数原型如下所示
int of_address_to_resource(struct device_node *dev, int index, struct resource *r)
函数参数和返回值含义如下:
        dev:设备节点。
        index:地址资源标号。
        r:得到的 resource 类型的资源值。
        返回值:0 ,成功;负值,失败
5 of_iomap 函数
of_iomap 函数用于直接内存映射,在驱动程序的编写中会通过 ioremap 函数来完成物理地址到虚拟地址的映射,采用设备树以后就可以直接通过 of_iomap 函数来获取内存地址所对应的虚拟地址,不需要使用 ioremap 函数了。当然也可以使用 ioremap 函数来完成物理地址到虚拟地址 的内存映射,只是在采用设备树以后,大部分的驱动都使用 of_iomap 函数了。 of_iomap 函数本 质上也是将 reg 属性中地址信息转换为虚拟地址,如果 reg 属性有多段的话,可以通过 index 参 数指定要完成内存映射的是哪一段, of_iomap 函数原型如下:
void __iomem *of_iomap(struct device_node *np, int index)
函数参数和返回值含义如下:
        np:设备节点。
        index reg 属性中要完成内存映射的段,如果 reg 属性只有一段的话 index 就设置为 0
        返回值:经过内存映射后的虚拟内存首地址,如果为 NULL 的话表示内存映射失败。

小结

        到此对于设备树的相关认识就大致总结到这里,在设备树的相关知识中,个人认为重点内容有如下几点:设备树语法、设备树的操作函数、等内容。

这篇关于对设备树、DTS语法、设备树中常用函数 的认识(简单总结)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1135066

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

每天认识几个maven依赖(ActiveMQ+activemq-jaxb+activesoap+activespace+adarwin)

八、ActiveMQ 1、是什么? ActiveMQ 是一个开源的消息中间件(Message Broker),由 Apache 软件基金会开发和维护。它实现了 Java 消息服务(Java Message Service, JMS)规范,并支持多种消息传递协议,包括 AMQP、MQTT 和 OpenWire 等。 2、有什么用? 可靠性:ActiveMQ 提供了消息持久性和事务支持,确保消

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象