| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> 嵌入式Linux开发19——Linux设备树(万字总结) -> 正文阅读 |
|
[系统运维]嵌入式Linux开发19——Linux设备树(万字总结) |
??提示:本文参考《 Devicetree SpecificationV0.2.pdf 》、《Power_ePAPR_APPROVED_v1.12.pdf》、《IMX6UL参考手册》以及正点原子的相关教程总结的学习笔记,万字总结,水平有限,仅供参考。 文章目录
设备树的概念??设备树(Device Tree),将这个词分开就是“设备”和“树”,描述设备树的文件叫做 DTS(Device Tree Source),这个 DTS 文件采用树形结构描述板级设备,也就是开发板上的设备信息,比如CPU 数量、 内存基地址、 IIC 接口上接了哪些设备、 SPI 接口上接了哪些设备等等。 DTS、 DTB 和 DTC??上一小节说了,设备树源文件扩展名为.dts,但是我们在前面移植 Linux 的时候却一直在使用.dtb 文件,那么 DTS 和 DTB 这两个文件是什么关系呢? DTS 是设备树源码文件, DTB 是将DTS 编译以后得到的二进制文件。将.c 文件编译为.o 需要用到 gcc 编译器,那么将.dts 编译为.dtb需要什么工具呢?需要用到 DTC 工具! DTC 工具源码在 Linux 内核的 scripts/dtc 目录下。 DTS语法1.dtsi头文件??和 C 语言一样,设备树也支持头文件,设备树的头文件扩展名为.dtsi。一般.dtsi 文件用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UART、 IIC 等等。比如 imx6ull.dtsi 就是描述 I.MX6ULL 这颗 SOC 内部外设情况信息的,内容如下:
??第 54~89 行就是 cpu0 这个设备节点信息,这个节点信息描述了I.MX6ULL 这颗 SOC 所使用的 CPU 信息,比如架构是 cortex-A7,频率支持 996MHz、 792MHz、528MHz、396MHz 和 198MHz 等等。在 imx6ull.dtsi 文件中不仅仅描述了 cpu0 这一个节点信息,I.MX6ULL 这颗 SOC 所有的外设都描述的清清楚楚,比如 ecspi1~4、 uart1~8、 usbphy1~2、 i2c1~4等等,关于这些设备节点信息的具体内容我们稍后在详细的讲解。 2.设备节点??设备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息,属性就是键—值对。以下是从imx6ull.dtsi 文件中缩减出来的设备树文件内容:
??第 1 行,“/”是根节点,每个设备树文件只有一个根节点。第 2、 6 和 17 行, aliases、 cpus 和 intc 是三个子节点,在设备树中节点命名格式如下:
??其中“node-name”是节点名字,为 ASCII 字符串,节点名字应该能够清晰的描述出节点的功能,比如“uart1”就表示这个节点是 UART1 外设。“unit-address”一般表示设备的地址或寄存器首地址,如果某个节点没有地址或者寄存器的话“unit-address”可以不要,比如“cpu@0”、“interrupt-controller@00a01000”。
??引入 label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点,比如通过&cpu0 就可以访问“cpu@0”这个节点,而不需要输入完整的节点名字。再比如节点 “intc:interrupt-controller@00a01000”,节点 label 是 intc,而节点名字就很长了,为“ interruptcontroller@00a01000”。很明显通过&intc 来访问“interrupt-controller@00a01000”这个节点要方便很多!
??上述代码设置 compatible 属性的值为字符串“arm,cortex-a7”。
??上述代码设置 reg 属性的值为 0,
??上述代码设置属性 compatible 的值为“fsl,imx6ull-gpmi-nand”和“fsl, imx6ul-gpmi-nand”。 3.标准属性??节点是由一堆的属性组成,节点都是具体的设备,不同的设备需要的属性不同,用户可以自定义属性。除了用户自定义属性,有很多属性是标准属性, Linux 下的很多外设驱动都会使用这些标准属性。 3.1 compatible 属性??compatible 属性也叫做“兼容性”属性,这是非常重要的一个属性! compatible 属性的值是一个字符串列表, compatible 属性用于将设备和驱动绑定起来。字符串列表用于选择设备所要使用的驱动程序, compatible 属性的值格式如下所示:
??其中 manufacturer 表示厂商, model 一般是模块对应的驱动名字。 3.2 model属性??model 属性值也是一个字符串,一般 model 属性描述设备模块信息,比如名字什么的,比如:
3.3 status 属性??status 属性看名字就知道是和设备状态有关的, status 属性值也是字符串,字符串是设备的状态信息,可选的状态如表所示: 3.4 #address-cells 和#size-cells 属性??这两个属性的值都是无符号 32 位整形, #address-cells 和#size-cells 这两个属性可以用在任何拥有子节点的设备中,用于描述子节点的地址信息。 #address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位), #size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。 #address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度, reg 属性的格式一为:
??每个“address length”组合表示一个地址范围,其中 address 是起始地址, length 是地址长度, #address-cells 表明 address 这个数据所占用的字长, #size-cells 表明 length 这个数据所占用的字长。 3.5 reg 属性??reg 属性前面已经提到过了, reg 属性的值一般是(address, length)对。 reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息。 3.6 ranges 属性??ranges属性值可以为空或者按照(child-bus-address,parent-bus-address,length)格式编写的数字矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成: 4.根节点compatible 属性??每个节点都有 compatible 属性,根节点“/”也不例外, imx6ull-emmc.dts 文件中根节点的 compatible 属性内容如下所示:
??可以看出, compatible 有两个值:“fsl,imx6ull-14x14-evk”和“fsl,imx6ull”。前面我们说了,设备节点的 compatible 属性值是为了匹配 Linux 内核中的驱动程序,那么根节点中的 compatible属性是为了做什么工作的? 通过根节点的 compatible 属性可以知道我们所使用的设备,一般第一个值描述了所使用的硬件设备名字,比如这里使用的是“imx6ull-14x14-evk”这个设备,第二个值描述了设备所使用的 SOC,比如这里使用的是“imx6ull”这颗 SOC。 Linux 内核会通过根节点的 compoatible 属性查看是否支持此设备,如果支持的话设备就会启动 Linux 内核。 设备树在系统中的体现??Linux 内核启动的时候会解析设备树中各个节点的信息,并且在根文件系统的/proc/devicetree 目录下根据节点名字创建不同文件夹: 1. 根节点“/”各个属性??在上图中,根节点属性属性表现为一个个的文件(图中细字体文件),比如图 43.5.1 中的“#address-cells”、“#size-cells”、“compatible”、“model”和“name”这 5 个文件,它们在设备树中就是根节点的 5个属性。既然是文件那么肯定可以查看其内容,输入cat 命令来查看 model和 compatible 这两个文件的内容: 2、根节点“/”各子节点??各个文件夹(图中粗字体文件夹)就是根节点“/”的各个子节点,比如“aliases”、“ backlight”、“ chosen”和“ clocks”等等。 Linux 内核解析 DTB 文件??Linux 内核在启动的时候会解析 DTB 文件,然后在/proc/device-tree 目录下生成相应的设备树节点文件。接下来我们简单分析一下 Linux 内核是如何解析 DTB 文件的,流程图如下所示: 设备树常用OF操作函数??设备树描述了设备的详细信息,这些信息包括数字类型的、字符串类型的、数组类型的,我们在编写驱动的时候需要获取到这些信息。比如设备树使用 reg 属性描述了某个外设的寄存器地址为 0X02005482,长度为 0X400,我们在编写驱动的时候需要获取到 reg 属性的0X02005482 和 0X400 这两个值,然后初始化外设。 Linux 内核给我们提供了一系列的函数来获取设备树中的节点或者属性信息,这一系列的函数都有一个统一的前缀“of_”,所以在很多资料里面也被叫做 OF 函数。这些 OF 函数原型都定义在 include/linux/of.h 文件中。 1. 查找节点的 OF 函数??设备都是以节点的形式“挂”到设备树上的,因此要想获取这个设备的其他属性信息,必须先获取到这个设备的节点。 Linux 内核使用 device_node 结构体来描述一个节点,此结构体定义在文件 include/linux/of.h 中,定义如下:
??与查找节点有关的 OF 函数有 5 个,我们依次来看一下。 1.1 of_find_node_by_name 函数??of_find_node_by_name 函数通过节点名字查找指定的节点,函数原型如下:
??函数参数和返回值含义如下: 1.2 of_find_node_by_type 函数??of_find_node_by_type 函数通过 device_type 属性查找指定的节点,函数原型如下:
??函数参数和返回值含义如下: 1.3 of_find_compatible_node 函数??of_find_compatible_node 函数根据 device_type 和 compatible 这两个属性查找指定的节点,函数原型如下:
1.4 of_find_matching_node_and_match 函数??of_find_matching_node_and_match 函数通过 of_device_id 匹配表来查找指定的节点,函数原型如下:
??函数参数和返回值含义如下:
??函数参数和返回值含义如下: 2. 查找父/子节点的 OF 函数2.1 of_get_parent 函数??of_get_parent 函数用于获取指定节点的父节点(如果有父节点的话),函数原型如下:
??函数参数和返回值含义如下: 2.2 of_get_next_child 函数??of_get_next_child 函数用迭代的方式查找子节点,函数原型如下:
??函数参数和返回值含义如下: 3. 提取属性值的 OF 函数??节点的属性信息里面保存了驱动所需要的内容,因此对于属性值的提取非常重要, Linux 内核中使用结构体 property 表示属性,此结构体同样定义在文件 include/linux/of.h 中,内容如下:
??Linux 内核也提供了提取属性值的 OF 函数,我们依次来看一下。 3.1 of_find_property 函数??of_find_property 函数用于查找指定的属性,函数原型如下:
??函数参数和返回值含义如下: 3.2 of_property_count_elems_of_size 函数??of_property_count_elems_of_size 函数用于获取属性中元素的数量,比如 reg 属性值是一个数组,那么使用此函数可以获取到这个数组的大小,此函数原型如下:
??函数参数和返回值含义如下: 3.3 of_property_read_u32_index 函数??of_property_read_u32_index 函数用于从属性中获取指定标号的 u32 类型数据值(无符号 32位),比如某个属性有多个 u32 类型的值,那么就可以使用此函数来获取指定标号的数据值,此函数原型如下:
??函数参数和返回值含义如下: 3.4 of_property_read_u8_array 函数;of_property_read_u16_array 函数;of_property_read_u32_array 函数;of_property_read_u64_array 函数??这 4 个函数分别是读取属性中 u8、 u16、 u32 和 u64 类型的数组数据,比如大多数的 reg 属性都是数组数据,可以使用这 4 个函数一次读取出 reg 属性中的所有数据。这四个函数的原型如下:
??函数参数和返回值含义如下: 3.5 of_property_read_u8 函数;of_property_read_u16 函数;of_property_read_u32 函数;of_property_read_u64 函数??有些属性只有一个整形值,这四个函数就是用于读取这种只有一个整形值的属性,分别用于读取 u8、 u16、 u32 和 u64 类型属性值,函数原型如下:
??函数参数和返回值含义如下: 3.6 of_property_read_string 函数??of_property_read_string 函数用于读取属性中字符串值,函数原型如下:
??函数参数和返回值含义如下: 3.7 of_n_addr_cells 函数??of_n_addr_cells 函数用于获取#address-cells 属性值,函数原型如下:
??函数参数和返回值含义如下: 3.8 of_n_size_cells 函数??of_size_cells 函数用于获取#size-cells 属性值,函数原型如下:
??函数参数和返回值含义如下: 4. 其他常用的 OF 函数4.1 of_device_is_compatible 函数??of_device_is_compatible 函数用于查看节点的 compatible 属性是否有包含 compat 指定的字符串,也就是检查设备节点的兼容性,函数原型如下:
??函数参数和返回值含义如下: 4.2 of_get_address 函数??of_get_address 函数用于获取地址相关属性,主要是“reg”或者“assigned-addresses”属性值,函数原型如下:
??函数参数和返回值含义如下: 4.3 of_translate_address 函数??of_translate_address 函数负责将从设备树读取到的地址转换为物理地址,函数原型如下:
??函数参数和返回值含义如下: 4.4 of_address_to_resource 函数??IIC、 SPI、 GPIO 等这些外设都有对应的寄存器,这些寄存器其实就是一组内存空间, Linux内核使用 resource 结构体来描述一段内存空间,“resource”翻译出来就是“资源”,因此用 resource结构体描述的都是设备资源信息, resource 结构体定义在文件 include/linux/ioport.h 中,定义如下:
??对于 32 位的 SOC 来说, resource_size_t 是 u32 类型的。其中 start 表示开始地址, end 表示结束地址, name 是这个资源的名字, flags 是资源标志位,一般表示资源类型,可选的资源标志定义在文件 include/linux/ioport.h 中,如下所示:
??大 家 一 般 最 常 见 的 资 源 标 志 就 是 IORESOURCE_MEM 、 IORESOURCE_REG 和IORESOURCE_IRQ 等。接下来我们回到 of_address_to_resource 函数,此函数看名字像是从设备树里面提取资源值,但是本质上就是将 reg 属性值,然后将其转换为 resource 结体类型,函数原型如下所示:
??函数参数和返回值含义如下: 4.5 of_iomap 函数??of_iomap 函数用于直接内存映射,以前我们会通过 ioremap 函数来完成物理地址到虚拟地址的映射,采用设备树以后就可以直接通过 of_iomap 函数来获取内存地址所对应的虚拟地址,不需要使用 ioremap 函数了。当然了,你也可以使用 ioremap 函数来完成物理地址到虚拟地址的内存映射,只是在采用设备树以后,大部分的驱动都使用 of_iomap 函数了。 of_iomap 函数本质上也是将 reg 属性中地址信息转换为虚拟地址,如果 reg 属性有多段的话,可以通过 index 参数指定要完成内存映射的是哪一段, of_iomap 函数原型如下:
??函数参数和返回值含义如下: |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 9:55:32- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |