当前位置: 首页 > news >正文

Linux驱动开发—设备树分析:GPIO,中断,时钟信息,CPU信息

书接上回:Linux驱动开发—设备树基本概念,语法详解-CSDN博客

文章目录

    • 使用设备树描述中断
    • 使用设备树描述CPU节点
      • CPU 节点
      • 缓存节点
      • 总结
    • 使用设备树描述时钟
      • 总结
    • 使用设备树描述GPIO
      • 示例设备树节点
      • 逐行解析
      • GPIO 单元

使用设备树描述中断

在NXP 官方中截取部分设备树源码分析为例。

gpio@5d0a0000 {compatible = "fsl,imx8qm-gpio\0fsl,imx35-gpio";reg = <0x00 0x5d0a0000 0x00 0x10000>;interrupts = <0x00 0x8a 0x04>;gpio-controller;#gpio-cells = <0x02>;power-domains = <0x10e>;interrupt-controller;#interrupt-cells = <0x02>;linux,phandle = <0xea>;phandle = <0xea>;
};

分析中断信息,主要关注以下几种字段;

interrupts: 定义与此GPIO控制器相关的中断属性。

  • 0x00: 中断类型。
  • 0x8a: 中断号。
  • 0x04: 中断触发类型,通常表示上升沿触发。

interrupt-controller: 表示这是一个中断控制器节点。interrupt-controller 属性是一个布尔属性,用于标识该节点是一个中断控制器。它不需要赋值,只要在节点中声明即可。操作系统在解析设备树时,会识别该节点为一个中断控制器,从而应用相应的处理逻辑。

#interrupt-cells: 定义中断描述的单元数量,这里为2。在设备树中,每个中断源都需要一个描述,用于向操作系统传达如何配置和处理该中断源。

中断也可能是多级引用—中断控制器的级联,如下源码所示

	interrupt-controller@51a00000 {compatible = "arm,gic-v3";reg = <0x00 0x51a00000 0x00 0x10000 0x00 0x51b00000 0x00 0xc0000 0x00 0x52000000 0x00 0x2000 0x00 0x52010000 0x00 0x1000 0x00 0x52020000 0x00 0x20000>;#interrupt-cells = <0x03>;interrupt-controller;interrupts = <0x01 0x09 0x3f04>;interrupt-parent = <0x01>;linux,phandle = <0x01>;phandle = <0x01>;};mu@5d1c0000 {compatible = "fsl,imx8-mu";reg = <0x00 0x5d1c0000 0x00 0x10000>;interrupts = <0x00 0xb1 0x04>;interrupt-parent = <0x01>;fsl,scu_ap_mu_id = <0x00>;status = "okay";};

interrupt-parent: 指向父中断控制器的引用,值为0x01

interrupts: 定义与此消息单元相关的中断属性。

  • 0x00: 中断类型。
  • 0xb1: 中断号。
  • 0x04: 中断触发类型(通常表示上升沿触发)。

interrupt-controller: 表示这是一个中断控制器节点。

#interrupt-cells: 定义中断描述的单元数量,这里为3。表示每个中断描述需要三个单元。

  • 第一个单元:中断类型或源。
  • 第二个单元:中断号。
  • 第三个单元:中断触发类型或标志。

使用设备树描述CPU节点

每个CPU节点包含了描述该CPU核心的属性,例如兼容性、寄存器地址、时钟频率等。以NXP IMX8QM为例

	cpus {#address-cells = <0x02>;#size-cells = <0x00>;idle-states {entry-method = "psci";cpu-sleep {compatible = "arm,idle-state";arm,psci-suspend-param = <0x00>;entry-latency-us = <0x2bc>;exit-latency-us = <0xfa>;min-residency-us = <0x3e8>;};cluster-sleep {compatible = "arm,idle-state";arm,psci-suspend-param = <0x1000000>;entry-latency-us = <0x3e8>;exit-latency-us = <0x2bc>;min-residency-us = <0xa8c>;wakeup-latency-us = <0x5dc>;};};cpu@0 {device_type = "cpu";compatible = "arm,cortex-a53";reg = <0x00 0x00>;enable-method = "psci";next-level-cache = <0x02>;operating-points = <0x124f80 0x00 0x10d880 0x00 0xdbba0 0x00 0x927c0 0x00>;clocks = <0x03 0x01>;clock-latency = <0xee6c>;#cooling-cells = <0x02>;linux,phandle = <0x6e>;phandle = <0x6e>;};cpu@1 {device_type = "cpu";compatible = "arm,cortex-a53";reg = <0x00 0x01>;enable-method = "psci";next-level-cache = <0x02>;};cpu@2 {device_type = "cpu";compatible = "arm,cortex-a53";reg = <0x00 0x02>;enable-method = "psci";next-level-cache = <0x02>;};cpu@3 {device_type = "cpu";compatible = "arm,cortex-a53";reg = <0x00 0x03>;enable-method = "psci";next-level-cache = <0x02>;};l2-cache0 {compatible = "cache";linux,phandle = <0x02>;phandle = <0x02>;};cpu@100 {device_type = "cpu";compatible = "arm,cortex-a72\0arm,armv8";reg = <0x00 0x100>;enable-method = "psci";next-level-cache = <0x04>;operating-points = <0x185a60 0x00 0x13c680 0x00 0x101d00 0x00 0x927c0 0x00>;clocks = <0x03 0x03>;clock-latency = <0xee6c>;#cooling-cells = <0x02>;linux,phandle = <0x05>;phandle = <0x05>;};cpu@101 {device_type = "cpu";compatible = "arm,cortex-a72\0arm,armv8";reg = <0x00 0x101>;enable-method = "psci";next-level-cache = <0x04>;linux,phandle = <0x06>;phandle = <0x06>;};l2-cache1 {compatible = "cache";linux,phandle = <0x04>;phandle = <0x04>;};};

CPU 节点

cpus节点里面包含物理CPU布局,也就是CPU的布局全部在此节点下描述

注:有些设备树中描述大小核CPU,必须要用cpu-map,使用Cluster描述同一类型CPU,但是NXP中没有使用这种命名命名方式,但是也将大小核心分开描述了

第一个簇 (Cluster) 的 CPU 节点

cpu@0cpu@3: 定义四个 Cortex-A53 CPU核心。

  • device_type: 设备类型为cpu
  • compatible: 兼容属性,标识为 arm,cortex-a53
  • reg: CPU的地址单元,分别为 0x00 0x00, 0x00 0x01, 0x00 0x02, 0x00 0x03
  • enable-method: 启用方法为 psci
  • next-level-cache: 下一层缓存的引用,值为 0x02
  • operating-points: 操作点,包含频率和电压对。
  • clocks: 时钟源。
  • clock-latency: 时钟延迟,值为 0xee6c
  • #cooling-cells: 冷却单元的数量,值为 0x02
  • linux,phandlephandle: 句柄,用于唯一标识该节点。

第二个簇 (Cluster) 的 CPU 节点

	cpu@100 {device_type = "cpu";compatible = "arm,cortex-a72\0arm,armv8";reg = <0x00 0x100>;enable-method = "psci";next-level-cache = <0x04>;operating-points = <0x185a60 0x00 0x13c680 0x00 0x101d00 0x00 0x927c0 0x00>;clocks = <0x03 0x03>;clock-latency = <0xee6c>;#cooling-cells = <0x02>;linux,phandle = <0x05>;phandle = <0x05>;};cpu@101 {device_type = "cpu";compatible = "arm,cortex-a72\0arm,armv8";reg = <0x00 0x101>;enable-method = "psci";next-level-cache = <0x04>;linux,phandle = <0x06>;phandle = <0x06>;};

cpu@100cpu@101: 定义两个 Cortex-A72 CPU核心。

  • device_type: 设备类型为cpu
  • compatible: 兼容属性,标识为 arm,cortex-a72arm,armv8
  • reg: CPU的地址单元,分别为 0x00 0x1000x00 0x101
  • enable-method: 启用方法为 psci
  • next-level-cache: 下一层缓存的引用,值为 0x04
  • operating-points: 操作点,包含频率和电压对。
  • clocks: 时钟源。
  • clock-latency: 时钟延迟,值为 0xee6c
  • #cooling-cells: 冷却单元的数量,值为 0x02
  • linux,phandlephandle: 句柄,用于唯一标识该节点。

缓存节点

	l2-cache0 {compatible = "cache";linux,phandle = <0x02>;phandle = <0x02>;};l2-cache1 {compatible = "cache";linux,phandle = <0x04>;phandle = <0x04>;};

l2-cache0l2-cache1: 定义两个二级缓存(L2缓存)。

  • compatible: 兼容属性,标识为 cache
  • linux,phandlephandle: 句柄,用于唯一标识该节点。

总结

这段设备树描述了一个含有两个簇(Cluster)的多核系统,其中第一个簇包含四个Cortex-A53 CPU核心,第二个簇包含两个Cortex-A72 CPU核心。每个CPU节点包含兼容性、寄存器地址、启用方法、时钟、操作点等属性。还定义了两个二级缓存节点,并描述了系统的空闲状态。这样,操作系统可以根据设备树信息正确地初始化和管理各个CPU核心及其相关硬件。

使用设备树描述时钟

例如下方NXP源码

prg@560c0000 {compatible = "fsl,imx8qm-prg";reg = <0x00 0x560c0000 0x00 0x10000>;clocks = <0x03 0x144 0x03 0x13b>;clock-names = "apb\0rtram";power-domains = <0x0f>;status = "okay";linux,phandle = <0x79>;phandle = <0x79>;};

时钟属性

clocks = <0x03 0x141 0x03 0x138>;
clock-names = "apb\0rtram";

clocks: 指定设备所需的时钟源。

  • <0x03 0x141>: 时钟控制器(索引为 0x03)中的时钟索引 0x141
  • <0x03 0x138>: 时钟控制器(索引为 0x03)中的时钟索引 0x138

clock-names: 为时钟源命名。

  • "apb\0rtram": 两个时钟源的名称分别是 apbrtram

下一个例子:

i2c@56226000 节点描述了一个 I2C 控制器的硬件信息,重点关注时钟相关的属性

i2c@56226000 {compatible = "fsl,imx8qm-lpi2c";reg = <0x00 0x56226000 0x00 0x1000>;interrupts = <0x08 0x04>;interrupt-parent = <0x8a>;clocks = <0x03 0x1d3 0x03 0x2f6>;clock-names = "per\0ipg";assigned-clocks = <0x03 0x1d3>;assigned-clock-rates = <0x16e3600>;power-domains = <0x8b>;status = "okay";#address-cells = <0x01>;#size-cells = <0x00>;pinctrl-names = "default";pinctrl-0 = <0x8c>;clock-frequency = <0x186a0>;};

时钟属性解析

clocks = <0x03 0x1d3 0x03 0x2f6>;
clock-names = "per\0ipg";
assigned-clocks = <0x03 0x1d3>;
assigned-clock-rates = <0x16e3600>;

clocks 属性指定了该 I2C 控制器所依赖的时钟源。

<0x03 0x1d3><0x03 0x2f6>

  • 0x03 是时钟控制器的引用(即时钟控制器节点)。
  • 0x1d30x2f6 是时钟控制器中不同的时钟索引。

这表示该 I2C 控制器需要两个时钟源,分别位于时钟控制器 0x030x1d30x2f6 索引处。

assigned-clocks 属性指定要配置的时钟源。在这个例子中,是 <0x03 0x1d3>(即 per 时钟)。

assigned-clock-rates 属性定义了该时钟的频率,这里是 0x16e3600,即 24MHz

总结

在驱动开发过程中,不需要过多关注如何在设备树中编写时钟信息,而是更应该关注如何在驱动代码中获取和解析这些时钟信息。时钟信息的具体内容和配置通常由硬件工程师或系统工程师来编写和验证。驱动开发者通过设备树提供的接口和 Linux 内核的时钟管理 API 来操作时钟,而不需要深入了解时钟的硬件实现细节。这种分工可以提高开发效率和代码的可维护性。

使用设备树描述GPIO

使用设备树描述一个 GPIO 控制器时,需要定义该控制器的基本属性,如兼容性、寄存器地址、中断、GPIO 单元的数量等。以NXP源码为例

gpio@5d0a0000 {compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio";reg = <0x00 0x5d0a0000 0x00 0x10000>;interrupts = <0x00 0x8a 0x04>;gpio-controller;#gpio-cells = <2>;power-domains = <0x10e>;interrupt-controller;#interrupt-cells = <2>;linux,phandle = <0xea>;phandle = <0xea>;
};

使用设备树描述一个 GPIO 控制器时,需要定义该控制器的基本属性,如兼容性、寄存器地址、中断、GPIO 单元的数量等。以下是一个描述 GPIO 控制器的示例:

示例设备树节点

gpio@5d0a0000 {compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio";reg = <0x00 0x5d0a0000 0x00 0x10000>;interrupts = <0x00 0x8a 0x04>;gpio-controller;#gpio-cells = <2>;power-domains = <0x10e>;interrupt-controller;#interrupt-cells = <2>;linux,phandle = <0xea>;phandle = <0xea>;
};

逐行解析

  1. 节点名称和地址

    gpio@5d0a0000 {
    
    • gpio@5d0a0000:表示 GPIO 控制器节点,其地址为 0x5d0a0000
  2. 兼容性

    compatible = "fsl,imx8qm-gpio", "fsl,imx35-gpio";
    
    • compatible 属性表示设备兼容的驱动,优先级从左到右。
  3. 寄存器地址

    reg = <0x00 0x5d0a0000 0x00 0x10000>;
    
    • reg 属性定义设备的寄存器地址范围。这里表示起始地址 0x5d0a0000,大小为 0x10000 字节。
  4. 中断

    interrupts = <0x00 0x8a 0x04>;
    
    • interrupts 属性定义设备使用的中断。0x00 表示中断类型,0x8a 是中断号,0x04 是中断触发方式。
  5. GPIO 控制器标志

    gpio-controller;
    #gpio-cells = <2>;
    
    • gpio-controller 属性表示这是一个 GPIO 控制器。
    • #gpio-cells 属性定义每个 GPIO 描述的单元数,这里为 2
  6. 电源域

    power-domains = <0x10e>;
    
    • power-domains 属性指定该设备所属的电源域。
  7. 中断控制器标志

    interrupt-controller;
    #interrupt-cells = <2>;
    
    • interrupt-controller 属性表示这是一个中断控制器。
    • #interrupt-cells 属性定义每个中断描述的单元数,这里为 2
  8. phandle

    linux,phandle = <0xea>;
    phandle = <0xea>;
    
    • linux,phandlephandle 属性是节点的唯一标识符,用于引用该节点。

GPIO 单元

在设备树中,#gpio-cells 属性用于定义 GPIO 控制器节点中的 GPIO 单元(cells)的数量和结构。这些单元描述了 GPIO 控制器的每个 GPIO 引脚的特性和配置。在具体应用中,GPIO 单元通常用于描述某个设备连接到的特定 GPIO 引脚及其配置方式。

常见的单元包括:

  1. GPIO 引脚编号:GPIO 控制器中引脚的编号。
  2. 标志(flags):通常表示 GPIO 的输入/输出方向、上拉/下拉配置等。

在这个例子中,#gpio-cells = <2>; 表示每个 GPIO 引脚用两个单元来描述。

具体使用示例**—万年不变的点一个LED灯**

假设有一个LED灯连接到某个 GPIO 引脚,可以这么描述这个LED灯

led {compatible = "led_dev";gpios = <&gpio1 5 0>;
};

这里,gpios 属性定义了一个连接到 GPIO 控制器的 GPIO 引脚,使用了三个参数:

  1. GPIO 控制器的 phandle&gpio1 是一个指向 GPIO 控制器节点的引用。指定哪个 GPIO 控制器负责管理该引脚。
  2. GPIO 引脚编号5 表示 GPIO 控制器中的第 5 号引脚。
  3. 标志(flags)0 表示无特殊标志(通常用于表示 GPIO 引脚的配置,如输入/输出方向等)。标志的具体定义依赖于平台和 GPIO 控制器的实现。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Postgresql数据库中通过函数实现将不确定列的数据插入到表中
  • c++中std::endl 和“\n“ 这两个换行符有什么区别
  • uniapp——列表图片加载太多且空间占用太大的处理方法(降低清晰度)
  • git的基本操作和原理
  • MoE-LLaVA: Mixture of Experts for Large Vision-Language Models
  • Elastic Observability 8.15:AI 助手、OTel 和日志质量增强功能
  • Filebeat+Kafka+ELK
  • RabbitMQ再回首--往事如梦
  • 代码随想录算法训练营第45天|LeetCode 115.不同的子序列、583. 两个字符串的删除操作、72. 编辑距离
  • Netty技术全解析:DelimiterBasedFrameDecoder类深度解析
  • MySQL增删改查(基础)
  • Java入门基础17:集合框架2(可变参数、Collections、Map系列集合、集合的嵌套、Stream流)
  • 不知道msvcp140.dll丢失的解决方法有哪些?看这篇文章教你修复丢失的msvcp140.dll
  • 8月9日笔记
  • Leetcode 17.电话号码的字母组合
  • [iOS]Core Data浅析一 -- 启用Core Data
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • 30秒的PHP代码片段(1)数组 - Array
  • Hibernate最全面试题
  • java概述
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • Shell编程
  • Spring框架之我见(三)——IOC、AOP
  • 搭建gitbook 和 访问权限认证
  • 电商搜索引擎的架构设计和性能优化
  • 来,膜拜下android roadmap,强大的执行力
  • 微服务框架lagom
  • 微信小程序设置上一页数据
  • mysql面试题分组并合并列
  • 第二十章:异步和文件I/O.(二十三)
  • 浅谈sql中的in与not in,exists与not exists的区别
  • ​ArcGIS Pro 如何批量删除字段
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • # 达梦数据库知识点
  • #前后端分离# 头条发布系统
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • %@ page import=%的用法
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (Pytorch框架)神经网络输出维度调试,做出我们自己的网络来!!(详细教程~)
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (学习总结16)C++模版2
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • *** 2003
  • .net core 6 redis操作类
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .net 使用ajax控件后如何调用前端脚本
  • .NET建议使用的大小写命名原则
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • [ JavaScript ] JSON方法
  • [ 隧道技术 ] 反弹shell的集中常见方式(四)python反弹shell
  • [ABP实战开源项目]---ABP实时服务-通知系统.发布模式
  • [ai笔记9] openAI Sora技术文档引用文献汇总
  • [C#基础知识]专题十三:全面解析对象集合初始化器、匿名类型和隐式类型