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

嵌入式系统内核镜像相关(十六)

文章目录

  • 前言
  • 一、翻译bindings文档
    • 1.1 interrupts.txt内容解释
      • 1.1.1 中断客户端节点(Interrupt client nodes)
      • 1.1.2 中断控制器节点(Interrupt controller nodes)
        • 1.1.2.1 一个单元格(one cell)
        • 1.1.2.2 两个单元格(two cells)
    • 1.2 xilinx,intc.txt内容解释
      • 1.2.1 必需属性(Required properties):
      • 1.2.2 可选属性(Optional properties):
      • 1.2.3 2个示例:
    • 1.3 arm,gic.txt内容解释
      • 1.3.1 主要节点所需属性
      • 1.3.2 可选属性
      • 1.3.3 示例
        • 1.3.3.1 基本用例
        • 1.3.3.2 GIC 虚拟化扩展(VGIC)
        • 1.3.3.3 GICv2m 扩展支持 MSI/MSI-x(可选)
    • 1.4 arm,gic-v3.txt内容解释
      • 1.4.1 主要节点所需属性
      • 1.4.2 可选属性
      • 1.4.3 子节点
      • 1.4.4 示例
    • 1.5 arm,nvic.txt内容解释
      • 1.5.1 主要节点所需属性
      • 1.5.2 示例
    • 1.6 st,stm32-exti.txt内容解释
      • 1.6.1 必需属性
      • 1.6.2 示例
    • 1.7 st,sti-irq-syscfg.txt内容解释
      • 1.7.1 必需属性
      • 1.7.2 可选属性
      • 1.7.3 示例
  • 二、中断移植(卡在设备树中断触发类型的赋值)
    • 2.1 前情概述——不支持gpio_to_irq函数
    • 2.2 irq_of_parse_and_map函数
    • 2.3 interrupts和interrupt-parent的格式以及编号占用情况
    • 2.4 UG585中中断一章的翻译
      • 2.4.1 环境
      • 2.4.2 功能描述
      • 2.4.3 寄存器概述
      • 2.4.4 编程模型
    • 2.5 回到实验部分
  • 总结


前言

本篇处理中断相关例程的移植。在《嵌入式系统内核镜像相关(十二)》中提到了中断移植的难点,本篇着手解决该问题。


一、翻译bindings文档

先找到devicetreebindings中与中断相关的文档:

dention@ubuntu:~/petalinux_proj/test_peta/proj_peta$ find ./ -name "xilinx,intc.txt"
./build/tmp/work-shared/plnx-zynq7/kernel-source/Documentation/devicetree/bindings/interrupt-controller/xilinx,intc.txt

如下,选中的5个文档可能与我们的项目移植有关!

在这里插入图片描述

包括了arm,gic.txtarm,gic-v3.txtarm,nvic.txtinterrupts.txtxilinx,intc.txt等5个文件。

参考野火的中断子系统教程讲解了GICNVIC的区别!

贴点kimichat整理的内容:

GIC(Generic Interrupt Controller)和 NVIC(Nested Vectored Interrupt Controller)是两种不同的中断控制器。

GIC

  • 是ARM架构中的一部分,用于处理来自多个源的中断请求,并将其分发到多个处理器核心。GIC设计用于多核处理器系统,能够支持多个中断源和多个处理器核心之间的中断管理。
  • GIC分为不同的版本,如GICv1(已弃用)、GICv2、GICv3和GICv4,每个版本都支持不同的中断处理特性和系统规模。GICv3引入了属性层次(affinity hierarchies),以支持更多的核心,并且增加了redistributor组件和LPI(Locality-Partitioned Interrupts)来处理消息中断。
  • 通常集成在系统级芯片(SoC)中,与CPU核心紧密集成,提供高效的中断处理。

NVIC

  • 是Cortex-M系列微控制器中的中断控制器,专为单核或简单的多核系统设计。
  • 提供了中断优先级设置,支持抢占式和子优先级,允许中断嵌套。
  • 通常与Cortex-M内核紧密集成,提供快速的中断响应和处理。
  • 支持有限数量的中断源,适合中低端的微控制器应用,而不是为大型多核系统设计的。
  • 设计相对简单,易于在微控制器中实现,通常用于嵌入式系统和简单的控制应用。

GIC适用于需要处理大量中断和多核处理器的复杂系统,而NVIC则适用于中断源较少、对中断处理要求不是特别高的单核或简单多核微控制器系统。GIC设计用于多核处理器系统,能够支持多个中断源和多个处理器核心之间的中断管理。NVIC是Cortex-M系列微控制器中的中断控制器,专为单核或简单的多核系统设计,提供了中断优先级设置,支持抢占式和子优先级,允许中断嵌套。GIC通常集成在系统级芯片(SoC)中,与CPU核心紧密集成,提供高效的中断处理。NVIC通常与Cortex-M内核紧密集成,提供快速的中断响应和处理。GIC和NVIC的主要区别在于它们的设计目的、应用场景和支持的系统规模。GIC适用于需要处理大量中断和多核处理器的复杂系统,而NVIC则适用于中断源较少、对中断处理要求不是特别高的单核或简单多核微控制器系统。

1.1 interrupts.txt内容解释

直接翻译内容了,如下:

1.1.1 中断客户端节点(Interrupt client nodes)

描述生成中断的设备的节点必须包含“interrupts”属性、“interrupts-extended”属性或两者都有。如果两者都存在,后者应优先;前者可能仅出于与不认识后者的软件兼容而提供。这些属性包含中断说明符的列表,每个输出中断一个。中断说明符的格式由中断被路由到的中断控制器决定;有关详细信息,请参见下面的第2节。

示例:
interrupt-parent = <&intc1>; // 中断父控制器
interrupts = <5 0>, <6 0>; // 中断说明符列表

“interrupt-parent”属性用于指定中断被路由到的控制器,并包含一个指向中断控制器节点的单一phandle。此属性是可继承的,因此可以在中断客户端节点或其任何父节点中指定。“interrupts”属性中列出的中断始终相对于节点的中断父控制器。

“interrupts-extended”属性是当节点需要引用多个中断父控制器时使用的特殊形式。此属性中的每个条目都包含父phandle和中断说明符。“interrupts-extended”仅当设备具有多个中断父控制器时才应使用。

示例:
interrupts-extended = <&intc1 5 1>, <&intc2 1 0>; // 扩展中断说明符列表

1.1.2 中断控制器节点(Interrupt controller nodes)

设备通过“interrupt-controller”属性被标记为中断控制器。这是一个空的布尔属性。额外的“#interrupt-cells”属性定义了指定单个中断所需的单元格数。

中断控制器的绑定负责定义中断说明符的长度和格式。下面两种变体常用:

1.1.2.1 一个单元格(one cell)

“#interrupt-cells”属性设置为1,单个单元格定义了中断在控制器内的索引。

示例:

vic: intc@10140000 {compatible = "arm,versatile-vic";interrupt-controller;#interrupt-cells = <1>;reg = <0x10140000 0x1000>;
};sic: intc@10003000 {compatible = "arm,versatile-sic";interrupt-controller;#interrupt-cells = <1>;reg = <0x10003000 0x1000>;interrupt-parent = <&vic>;interrupts = <31>; /* 级联到 vic */
};
1.1.2.2 两个单元格(two cells)

“#interrupt-cells”属性设置为2,第一个单元格定义了中断在控制器内的索引,而第二个单元格用于指定以下任何标志:

bits[3:0] 触发类型和电平标志1 = 低到高边沿触发2 = 高到低边沿触发4 = 高电平电平敏感8 = 低电平电平敏感

示例:

i2c@7000c000 {gpioext: gpio-adnp@41 {compatible = "ad,gpio-adnp";reg = <0x41>;interrupt-parent = <&gpio>;interrupts = <160 1>;gpio-controller;#gpio-cells = <1>;interrupt-controller;#interrupt-cells = <2>;nr-gpios = <64>;};sx8634@22b {compatible = "sm,sx8634";reg = <0x2b>;interrupt-parent = <&gpioext>;interrupts = <3 0x8>;#address-cells = <1>;#size-cells = <0>;threshold = <0x40>;sensitivity = <7>;};
};

1.2 xilinx,intc.txt内容解释

直接翻译内容,如下:

Xilinx 中断控制器(Xilinx Interrupt Controller)是一个在构建时配置的软核IP,用于指定中断的数量和每种中断的类型。这些细节在运行时不能更改。

1.2.1 必需属性(Required properties):

  • compatible:应为 “xlnx,xps-intc-1.00.a”
  • reg:指定寄存器的基本物理地址和大小。
  • interrupt-controller:标识该节点为中断控制器。
  • #interrupt-cells:指定编码一个中断源所需的单元格数。该值应至少为1。Xilinx设备树通常使用2,但第二个值未被使用。
  • xlnx,kind-of-intr:一个32位值,指定每个可能的中断类型(1 = 边沿触发,0 = 电平触发)。中断类型通常通过生成中断的设备树节点来确定,但在这种情况下,中断类型由中断控制器基于其实现方式来确定。
  • xlnx,num-intr-inputs:指定控制器特定实现支持的中断数量(1-32)。

1.2.2 可选属性(Optional properties):

  • interrupt-parent:指定它所链接(级联)的中断控制器。
  • interrupts:指定它所链接的父控制器的中断。

1.2.3 2个示例:

示例1:

axi_intc_0: interrupt-controller@41800000 {#interrupt-cells = <2>;compatible = "xlnx,xps-intc-1.00.a";interrupt-controller;reg = <0x41800000 0x10000>;xlnx,kind-of-intr = <0x1>;xlnx,num-intr-inputs = <0x1>;
};

级联示例(Chained Example):

中断链接到Zynq的GIC(Generic Interrupt Controller)的硬件中断61(29 + 32)。

axi_intc_0: interrupt-controller@41800000 {#interrupt-cells = <2>;compatible = "xlnx,xps-intc-1.00.a";interrupt-controller;interrupt-parent = <&ps7_scugic_0>;interrupts = <0 29 4>;reg = <0x41800000 0x10000>;xlnx,kind-of-intr = <0x1>;xlnx,num-intr-inputs = <0x1>;
};

1.3 arm,gic.txt内容解释

翻译如下:

ARM 通用中断控制器(ARM Generic Interrupt Controller):ARM SMP 核心通常与 GIC 相关联,提供每个处理器的中断(Private Interrupts,PI)、共享处理器中断(Shared Processor Interrupts,SPI)和软件生成的中断(Software Generated Interrupts,SGI)。

主 GIC 直接连接到 CPU,通常具有 PI 和 SGI。

次级 GIC 级联到上级中断控制器,并且没有 PI 或 SGI。

1.3.1 主要节点所需属性

  • compatible:应为以下之一:

    • “arm,arm1176jzf-devchip-gic”
    • “arm,arm11mp-gic”
    • “arm,cortex-a15-gic”
    • “arm,cortex-a7-gic”
    • “arm,cortex-a9-gic”
    • “arm,eb11mp-gic”
    • “arm,gic-400”
    • “arm,pl390”
    • “arm,tc11mp-gic”
    • “brcm,brahma-b15-gic”
    • “nvidia,tegra210-agic”
    • “qcom,msm-8660-qgic”
    • “qcom,msm-qgic2”
  • interrupt-controller:标识该节点为中断控制器。

  • #interrupt-cells:指定编码一个中断源所需的单元格数。类型应为 <u32>,值应为 3。

    第 1 个单元是中断类型;0 表示 SPI 中断,1 表示 PI 中断。

    第 2 个单元包含中断类型的中断号。
    SPI 中断在范围 [0-987] 内。PI 中断在范围 [0-15] 内。

    第 3 个单元是标志位,编码如下:

    • bits[3:0] 触发类型和电平标志。
      • 1 = 低到高边沿触发
      • 2 = 高到低边沿触发(SPIs 无效)
      • 4 = 高电平电平敏感
      • 8 = 低电平电平敏感(SPIs 无效)。
    • bits[15:8] PI 中断 CPU 掩码。每个位对应连接到 GIC 的 8 个可能的 CPU。位设置为 ‘1’ 表示中断连接到该 CPU。仅对 PI 中断有效。
    • 请注意 PI 中断的可配置性是 IMPLEMENTATION DEFINED,因此不能保证存在(2014 年的大多数 SoC 似乎忽略此标志的设置并使用硬件默认值)。
  • reg:指定 GIC 寄存器的基本物理地址(s)和大小。第一个区域是 GIC 分发器寄存器基本地址和大小。第二个区域是 GIC CPU 接口寄存器基本地址和大小。

1.3.2 可选属性

  • interrupts:次级 GIC 的父中断控制器上的中断源,或主 GIC 上的 VGIC 维护中断(见下文)。

  • cpu-offset:在分发器和 CPU 接口区域内每个 CPU 的偏移,当 GIC 没有分区寄存器时使用。偏移是 cpu-offset * cpu-nr。

  • clocks:phandle 和特定时钟对的列表,每个时钟名称中的每个条目一个。

  • clock-names:GIC 时钟输入(s)的名称列表。有效的时钟名称取决于 GIC 变体:

    • “ic_clk”(对于 “arm,arm11mp-gic”)
    • “PERIPHCLKEN”(对于 “arm,cortex-a15-gic”)
    • “PERIPHCLK”,“PERIPHCLKEN”(对于 “arm,cortex-a9-gic”)
    • “clk”(对于 “arm,gic-400” 和 “nvidia,tegra210”)
    • “gclk”(对于 “arm,pl390”)
  • power-domains:由 phandle 指定的电源控制器的绑定定义的 phandle 和 PM 域指定符,当 GIC 是电源或时钟域的一部分时使用。

1.3.3 示例

1.3.3.1 基本用例

示例如下:

intc: interrupt-controller@fff11000 {compatible = "arm,cortex-a9-gic";#interrupt-cells = <3>;#address-cells = <1>;interrupt-controller;reg = <0xfff11000 0x1000>,<0xfff10100 0x100>;
};
1.3.3.2 GIC 虚拟化扩展(VGIC)

对于支持虚拟化扩展的 ARM 核心,必须描述附加属性(仅当 GIC 是主中断控制器时存在)。

必需属性:

  • reg:额外的区域指定 VGIC 寄存器的基本物理地址和大小。第一个附加区域是 GIC 虚拟接口控制寄存器基本地址和大小。第二个附加区域是 GIC 虚拟 CPU 接口寄存器基本地址和大小。

  • interrupts:VGIC 维护中断。

示例:

interrupt-controller@2c001000 {compatible = "arm,cortex-a15-gic";#interrupt-cells = <3>;interrupt-controller;reg = <0x2c001000 0x1000>,<0x2c002000 0x2000>,<0x2c004000 0x2000>,<0x2c006000 0x2000>;interrupts = <1 9 0xf04>;
};
1.3.3.3 GICv2m 扩展支持 MSI/MSI-x(可选)

某些 GIC-400 版本的支持通过 V2M 寄存器框架的 MSI/MSI-x。这通过指定 v2m 子节点来启用。

必需属性:

  • compatible:这里的值应包含 “arm,gic-v2m-frame”。

  • msi-controller:标识该节点为 MSI 控制器。

  • reg:GICv2m MSI 接口寄存器基本地址和大小

可选属性:

  • arm,msi-base-spi:当 MSI_TYPER 寄存器包含不正确的值时,此属性应包含 MSI 帧的 SPI 基本值,覆盖硬件值。

  • arm,msi-num-spis:当 MSI_TYPER 寄存器包含不正确的值时,此属性应包含分配给帧的 SPI 数量,覆盖硬件值。

示例:

interrupt-controller@e1101000 {compatible = "arm,gic-400";#interrupt-cells = <3>;#address-cells = <2>;#size-cells = <2>;interrupt-controller;interrupts = <1 8 0xf04>;ranges = <0 0 0 0xe1100000 0 0x100000>;reg = <0x0 0xe1110000 0 0x01000>,<0x0 0xe112f000 0 0x02000>,<0x0 0xe1140000 0 0x10000>,<0x0 0xe1160000 0 0x10000>;v2m0: v2m@8000 {compatible = "arm,gic-v2m-frame";msi-controller;reg = <0x0 0x80000 0 0x1000>;};....v2mN: v2m@9000 {compatible = "arm,gic-v2m-frame";msi-controller;reg = <0x0 0x90000 0 0x1000>;};
};

1.4 arm,gic-v3.txt内容解释

翻译如下:

ARM 通用中断控制器,版本3(ARM Generic Interrupt Controller, version 3):在Arch64 SMP核心中,经常与GICv3相关联,提供私有外设中断(Private Peripheral Interrupts,PI)、共享外设中断(Shared Peripheral Interrupts,SPI)、软件生成中断(Software Generated Interrupts,SGI)以及特定于区域的外设中断(Locality-specific Peripheral Interrupts,LPI)。

1.4.1 主要节点所需属性

  • compatible:至少应包含 “arm,gic-v3”。

  • interrupt-controller:标识该节点为中断控制器。

  • #interrupt-cells:指定编码一个中断源所需的单元格数。必须是一个至少为3的单一单元格。
    如果系统需要描述PI亲和性(affinity),则该值必须至少为4。

    第1个单元是中断类型;0表示SPI中断,1表示PI中断。其他值保留供将来使用。

    第2个单元包含中断类型的中断号。
    SPI中断在范围[0-987]内。PI中断在范围[0-15]内。

    第3个单元是标志位,编码如下:

    • bits[3:0] 触发类型和电平标志。
      • 1 = 边沿触发
      • 4 = 电平触发

    第4个单元是一个指向描述一组CPU的节点的phandle,此中断属于这些CPU。中断必须是PI,并且指向的节点必须是 “ppi-partitions” 子节点的子节点。对于非PI中断类型或未分区的PI,此单元必须为零。见下面的 “ppi-partitions” 节点描述。

    单元格5及之后保留供将来使用,如果存在则必须具有0的值。

  • reg:指定GIC寄存器的基本物理地址(s)和大小,按照以下顺序:

    • GIC 分发器接口(GICD)
    • GIC 重发器(GICR),每个重发器区域一个范围
    • GIC CPU 接口(ICC)
    • GIC 管理程序接口(GICH)
    • GIC 虚拟CPU接口(GICV)

    ICC、GICH 和 GICV 是可选的。

  • interrupts:VGIC维护中断的中断源。

1.4.2 可选属性

  • re-distributor-stride:如果使用填充页,则指定连续重发器的跨度。必须是64kB的倍数。

  • #redistributor-regions:重发器所占据的独立连续区域的数量。如果存在多个此类区域,则必须存在。

  • msi-controller:布尔属性。标识该节点为MSI控制器。仅当硬件通过mbi-ranges属性公开基于消息的中断功能时才存在。

  • mbi-ranges:对的列表,其中 “intid” 是可用于MBI的范围内的第一个SPI,而 “span” 是该范围的大小。可以提供多个范围。需要设置 “msi-controller”。

  • mbi-alias:地址属性。仅包含{SET,CLR}SPI寄存器的GICD区域的别名的基本地址,如果需要隔离,并且如果硬件支持。

1.4.3 子节点

PI亲和性可以表示为单个 “ppi-partitions” 节点,包含一组子节点,每个子节点具有以下属性:

  • affinity:应为CPU节点的phandle列表(如Documentation/devicetree/bindings/arm/cpus.txt中所述)。

GICv3有一个或多个中断翻译服务(ITS),用于将消息信号中断(MSI)路由到CPU。

这些节点必须具有以下属性:

  • compatible:至少应包含 “arm,gic-v3-its”。
  • msi-controller:布尔属性。标识该节点为MSI控制器。
  • #msi-cells:必须为<1>。单个msi单元格是将生成MSI的设备的DeviceID。
  • reg:指定ITS寄存器的基本物理地址和大小。

可选属性:

  • socio-next,synquacer-preits:(u32, u32)元组,描述未翻译的地址和pre-ITS窗口的大小。

主要GIC节点必须包含所有ITS节点的reg属性的适当#address-cells、#size-cells和ranges属性。

1.4.4 示例

gic: interrupt-controller@2cf00000 {compatible = "arm,gic-v3";#interrupt-cells = <3>;#address-cells = <2>;#size-cells = <2>;ranges;interrupt-controller;reg = <0x0 0x2f000000 0 0x10000>,	// GICD<0x0 0x2f10000 0 0x20000000>,	// GICR<0x0 0x2c00000 0 0x2000>,	// ICC<0x0 0x2c010000 0 0x2000>,	// GICH<0x0 0x2c020000 0 0x2000>;	// GICVinterrupts = <1 9 4>;msi-controller;mbi-ranges = <256 128>;gic-its@2c200000 {compatible = "arm,gic-v3-its";msi-controller;#msi-cells = <1>;reg = <0x0 0x2c200000 0 0x20000>;};
};gic: interrupt-controller@2c010000 {compatible = "arm,gic-v3";#interrupt-cells = <4>;#address-cells = <2>;#size-cells = <2>;ranges;interrupt-controller;redistributor-stride = <0x0 0x40000>;	// 256kB stride#redistributor-regions = <2>;reg = <0x0 0x2c010000 0 0x10000>,	// GICD<0x0 0x2d00000 0 0x800000>,	// GICR 1: CPUs 0-31<0x0 0x2e00000 0 0x800000>;	// GICR 2: CPUs 32-63<0x0 0x2c040000 0 0x2000>,	// ICC<0x0 0x2c060000 0 0x2000>,	// GICH<0x0 0x2c080000 0 0x2000>;	// GICVinterrupts = <1 9 4>;gic-its@2c200000 {compatible = "arm,gic-v3-its";msi-controller;#msi-cells = <1>;reg = <0x0 0x2c200000 0 0x20000>;};gic-its@2c400000 {compatible = "arm,gic-v3-its";msi-controller;#msi-cells = <1>;reg = <0x0 0x2c400000 0 0x20000>;};ppi-partitions {part0: interrupt-partition-0 {affinity = <&cpu0 &cpu2>;};part1: interrupt-partition-1 {affinity = <&cpu1 &cpu3>;};};
};
device@0 {reg = <0 0 0 4>;interrupts = <1 1 4 &part0>;
};

1.5 arm,nvic.txt内容解释

翻译如下:

ARM 嵌套向量中断控制器(ARM Nested Vectored Interrupt Controller,简称 NVIC):NVIC 提供了一个与基于 Cortex-M 处理器核心紧密耦合的中断控制器。不同 SoC(System on Chip)上实现的 NVIC 在中断数量和每个中断的优先级位数上有所不同。

1.5.1 主要节点所需属性

  • compatible:应为以下之一:

    • “arm,v6m-nvic”
    • “arm,v7m-nvic”
    • “arm,v8m-nvic”
  • interrupt-controller:标识该节点为中断控制器。

  • #interrupt-cells:指定编码一个中断源所需的单元格数。类型应为 <u32>,且值应为 2。

    第 1 个单元包含中断类型的中断号。

    第 2 个单元是中断的优先级。

  • reg:指定 NVIC 寄存器的基本物理地址和大小。这是一个固定地址(0xe000e100)和大小(0xc00)。

  • arm,num-irq-priority-bits:给定 SoC 实现的优先级位数。

1.5.2 示例

示例如下:

intc: interrupt-controller@e000e100 {compatible = "arm,v7m-nvic";#interrupt-cells = <2>;#address-cells = <1>;interrupt-controller;reg = <0xe000e100 0xc00>;arm,num-irq-priority-bits = <4>;
};

为了补充理解野火教程里面的中断例子,补充2个文档翻译!

1.6 st,stm32-exti.txt内容解释

翻译如下:

STM32 外部中断控制器(STM32 External Interrupt Controller)

1.6.1 必需属性

  • compatible:应为以下之一:
    • “st,stm32-exti”
    • “st,stm32h7-exti”
    • “st,stm32mp1-exti”
  • reg:指定寄存器的基本物理地址和大小。
  • interrupt-controller:标识该节点为中断控制器。
  • #interrupt-cells:指定编码一个中断标识符所需的单元格数,应为 2。
  • interrupts:中断引用主中断控制器(仅当 exti 控制器在同一父中断下有多个 exti 时需要:如 “st,stm32-exti” 和 “st,stm32h7-exti”)

1.6.2 示例

示例如下:

exti: interrupt-controller@40013c00 {compatible = "st,stm32-exti";interrupt-controller;#interrupt-cells = <2>;reg = <0x40013C00 0x400>;interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <76>;
};

1.7 st,sti-irq-syscfg.txt内容解释

翻译如下:

STMicroelectronics STi 系统配置控制的 IRQ:在基于 STi 的系统中;外部、CTI(Core Sight)、PMU(性能管理)和 PL310 缓存 IRQ 通过系统配置寄存器进行控制。

此驱动程序用于在使用前解除这些 IRQ 的屏蔽。

1.7.1 必需属性

  • compatible:应设置为以下之一:
    • “st,stih415-irq-sys-cfg”
    • “st,stih416-irq-sys-cfg”
    • “st,stih407-irq-sys-cfg”
    • “st,stid127-irq-sys-cfg”
  • st,syscfg:指向 Cortex-A9 IRQ 系统配置寄存器的 Phandle。
  • st,irq-device:要启用的 IRQ 数组 - 应为长度为 2 的数组。
  • st,fiq-device:要启用的 FIQ 数组 - 应为长度为 2 的数组。

1.7.2 可选属性

  • st,invert-ext:外部 IRQ 可以按意愿反转。此属性使用按位逻辑反转这些 IRQ。为了方便,已提供一些定义的数值:
    • ST_IRQ_SYSCFG_EXT_1_INV
    • ST_IRQ_SYSCFG_EXT_2_INV
    • ST_IRQ_SYSCFG_EXT_3_INV

1.7.3 示例

示例如下:

irq-syscfg {compatible    = "st,stih416-irq-sys-cfg";st,syscfg     = <&syscfg_cpu>;st,irq-device = <ST_IRQ_SYSCFG_PMU_0>,<ST_IRQ_SYSCFG_PMU_1>;st,fiq-device = <ST_IRQ_SYSCFG_DISABLED>,<ST_IRQ_SYSCFG_DISABLED>;st,invert-ext = <(ST_IRQ_SYSCFG_EXT_1_INV | ST_IRQ_SYSCFG_EXT_3_INV)>;
};

二、中断移植(卡在设备树中断触发类型的赋值)

2.1 前情概述——不支持gpio_to_irq函数

紧接着对《嵌入式系统内核镜像相关(十二)》的进行移植。

由于璞致的开发板不支持让我使用基于GPIO引脚的MIO-LED灯,因此按照原计划,就无法使用gpio_to_irq函数,如下:

在这里插入图片描述

2.2 irq_of_parse_and_map函数

因此,只能另寻他法!

其中

unsigned int irq_of_parse_and_map(struct device_node *dev, int index);

可以代替gpio_to_irq函数实现中断信息获取!

但麻烦的是,需要在设备树中注册interrupts属性以及相关的信息!

下图来自Alinx的中断开发教程:
在这里插入图片描述

下图来自野火的中断子系统开发教程:

在这里插入图片描述

2.3 interrupts和interrupt-parent的格式以及编号占用情况

很显然,我们需要了解设备树中的已有中断相关的写法,最直接的资料就是./components/plnx_workspace/device-tree/device-tree/zynq-7000.dtsi,内容如下:

// SPDX-License-Identifier: GPL-2.0+
/**  Copyright (C) 2011 - 2015 Xilinx** This software is licensed under the terms of the GNU General Public* License version 2, as published by the Free Software Foundation, and* may be copied, distributed, and modified under those terms.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the* GNU General Public License for more details.*// {#address-cells = <1>;#size-cells = <1>;compatible = "xlnx,zynq-7000";cpus {#address-cells = <1>;#size-cells = <0>;cpu0: cpu@0 {compatible = "arm,cortex-a9";device_type = "cpu";reg = <0>;clocks = <&clkc 3>;clock-latency = <1000>;cpu0-supply = <&regulator_vccpint>;operating-points = </* kHz    uV */666667  1000000333334  1000000>;};cpu1: cpu@1 {compatible = "arm,cortex-a9";device_type = "cpu";reg = <1>;clocks = <&clkc 3>;};};fpga_full: fpga-full {compatible = "fpga-region";fpga-mgr = <&devcfg>;#address-cells = <1>;#size-cells = <1>;ranges;};pmu@f8891000 {compatible = "arm,cortex-a9-pmu";interrupts = <0 5 4>, <0 6 4>;interrupt-parent = <&intc>;reg = < 0xf8891000 0x1000 0xf8893000 0x1000 >;};regulator_vccpint: fixedregulator {compatible = "regulator-fixed";regulator-name = "VCCPINT";regulator-min-microvolt = <1000000>;regulator-max-microvolt = <1000000>;regulator-boot-on;regulator-always-on;};amba: amba {u-boot,dm-pre-reloc;compatible = "simple-bus";#address-cells = <1>;#size-cells = <1>;interrupt-parent = <&intc>;ranges;adc: adc@f8007100 {compatible = "xlnx,zynq-xadc-1.00.a";reg = <0xf8007100 0x20>;interrupts = <0 7 4>;interrupt-parent = <&intc>;clocks = <&clkc 12>;};can0: can@e0008000 {compatible = "xlnx,zynq-can-1.0";status = "disabled";clocks = <&clkc 19>, <&clkc 36>;clock-names = "can_clk", "pclk";reg = <0xe0008000 0x1000>;interrupts = <0 28 4>;interrupt-parent = <&intc>;tx-fifo-depth = <0x40>;rx-fifo-depth = <0x40>;};can1: can@e0009000 {compatible = "xlnx,zynq-can-1.0";status = "disabled";clocks = <&clkc 20>, <&clkc 37>;clock-names = "can_clk", "pclk";reg = <0xe0009000 0x1000>;interrupts = <0 51 4>;interrupt-parent = <&intc>;tx-fifo-depth = <0x40>;rx-fifo-depth = <0x40>;};gpio0: gpio@e000a000 {compatible = "xlnx,zynq-gpio-1.0";#gpio-cells = <2>;clocks = <&clkc 42>;gpio-controller;interrupt-controller;#interrupt-cells = <2>;interrupt-parent = <&intc>;interrupts = <0 20 4>;reg = <0xe000a000 0x1000>;};i2c0: i2c@e0004000 {compatible = "cdns,i2c-r1p10";status = "disabled";clocks = <&clkc 38>;interrupt-parent = <&intc>;interrupts = <0 25 4>;reg = <0xe0004000 0x1000>;#address-cells = <1>;#size-cells = <0>;};i2c1: i2c@e0005000 {compatible = "cdns,i2c-r1p10";status = "disabled";clocks = <&clkc 39>;interrupt-parent = <&intc>;interrupts = <0 48 4>;reg = <0xe0005000 0x1000>;#address-cells = <1>;#size-cells = <0>;};intc: interrupt-controller@f8f01000 {compatible = "arm,cortex-a9-gic";#interrupt-cells = <3>;interrupt-controller;reg = <0xF8F01000 0x1000>,<0xF8F00100 0x100>;};L2: cache-controller@f8f02000 {compatible = "arm,pl310-cache";reg = <0xF8F02000 0x1000>;interrupts = <0 2 4>;arm,data-latency = <3 2 2>;arm,tag-latency = <2 2 2>;cache-unified;cache-level = <2>;};mc: memory-controller@f8006000 {compatible = "xlnx,zynq-ddrc-a05";reg = <0xf8006000 0x1000>;};ocmc: ocmc@f800c000 {compatible = "xlnx,zynq-ocmc-1.0";interrupt-parent = <&intc>;interrupts = <0 3 4>;reg = <0xf800c000 0x1000>;};uart0: serial@e0000000 {compatible = "xlnx,xuartps", "cdns,uart-r1p8";status = "disabled";clocks = <&clkc 23>, <&clkc 40>;clock-names = "uart_clk", "pclk";reg = <0xE0000000 0x1000>;interrupts = <0 27 4>;};uart1: serial@e0001000 {compatible = "xlnx,xuartps", "cdns,uart-r1p8";status = "disabled";clocks = <&clkc 24>, <&clkc 41>;clock-names = "uart_clk", "pclk";reg = <0xE0001000 0x1000>;interrupts = <0 50 4>;};spi0: spi@e0006000 {compatible = "xlnx,zynq-spi-r1p6";reg = <0xe0006000 0x1000>;status = "disabled";interrupt-parent = <&intc>;interrupts = <0 26 4>;clocks = <&clkc 25>, <&clkc 34>;clock-names = "ref_clk", "pclk";#address-cells = <1>;#size-cells = <0>;};spi1: spi@e0007000 {compatible = "xlnx,zynq-spi-r1p6";reg = <0xe0007000 0x1000>;status = "disabled";interrupt-parent = <&intc>;interrupts = <0 49 4>;clocks = <&clkc 26>, <&clkc 35>;clock-names = "ref_clk", "pclk";#address-cells = <1>;#size-cells = <0>;};qspi: spi@e000d000 {clock-names = "ref_clk", "pclk";clocks = <&clkc 10>, <&clkc 43>;compatible = "xlnx,zynq-qspi-1.0";status = "disabled";interrupt-parent = <&intc>;interrupts = <0 19 4>;reg = <0xe000d000 0x1000>;#address-cells = <1>;#size-cells = <0>;};smcc: memory-controller@e000e000 {#address-cells = <1>;#size-cells = <1>;status = "disabled";clock-names = "memclk", "apb_pclk";clocks = <&clkc 11>, <&clkc 44>;compatible = "arm,pl353-smc-r2p1", "arm,primecell";interrupt-parent = <&intc>;interrupts = <0 18 4>;ranges ;reg = <0xe000e000 0x1000>;nand0: flash@e1000000 {status = "disabled";compatible = "arm,pl353-nand-r2p1";reg = <0xe1000000 0x1000000>;#address-cells = <0x1>;#size-cells = <0x1>;};nor0: flash@e2000000 {status = "disabled";compatible = "cfi-flash";reg = <0xe2000000 0x2000000>;#address-cells = <1>;#size-cells = <1>;};};gem0: ethernet@e000b000 {compatible = "cdns,zynq-gem", "cdns,gem";reg = <0xe000b000 0x1000>;status = "disabled";interrupts = <0 22 4>;clocks = <&clkc 30>, <&clkc 30>, <&clkc 13>;clock-names = "pclk", "hclk", "tx_clk";#address-cells = <1>;#size-cells = <0>;};gem1: ethernet@e000c000 {compatible = "cdns,zynq-gem", "cdns,gem";reg = <0xe000c000 0x1000>;status = "disabled";interrupts = <0 45 4>;clocks = <&clkc 31>, <&clkc 31>, <&clkc 14>;clock-names = "pclk", "hclk", "tx_clk";#address-cells = <1>;#size-cells = <0>;};sdhci0: mmc@e0100000 {compatible = "arasan,sdhci-8.9a";status = "disabled";clock-names = "clk_xin", "clk_ahb";clocks = <&clkc 21>, <&clkc 32>;interrupt-parent = <&intc>;interrupts = <0 24 4>;reg = <0xe0100000 0x1000>;};sdhci1: mmc@e0101000 {compatible = "arasan,sdhci-8.9a";status = "disabled";clock-names = "clk_xin", "clk_ahb";clocks = <&clkc 22>, <&clkc 33>;interrupt-parent = <&intc>;interrupts = <0 47 4>;reg = <0xe0101000 0x1000>;};slcr: slcr@f8000000 {u-boot,dm-pre-reloc;#address-cells = <1>;#size-cells = <1>;compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd";reg = <0xF8000000 0x1000>;ranges;clkc: clkc@100 {u-boot,dm-pre-reloc;#clock-cells = <1>;compatible = "xlnx,ps7-clkc";fclk-enable = <0xf>;clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x","cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x","dci", "lqspi", "smc", "pcap", "gem0", "gem1","fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1","sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1","dma", "usb0_aper", "usb1_aper", "gem0_aper","gem1_aper", "sdio0_aper", "sdio1_aper","spi0_aper", "spi1_aper", "can0_aper", "can1_aper","i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper","gpio_aper", "lqspi_aper", "smc_aper", "swdt","dbg_trc", "dbg_apb";reg = <0x100 0x100>;};rstc: rstc@200 {compatible = "xlnx,zynq-reset";reg = <0x200 0x48>;#reset-cells = <1>;syscon = <&slcr>;};pinctrl0: pinctrl@700 {compatible = "xlnx,pinctrl-zynq";reg = <0x700 0x200>;syscon = <&slcr>;};};dmac_s: dmac@f8003000 {compatible = "arm,pl330", "arm,primecell";reg = <0xf8003000 0x1000>;interrupt-parent = <&intc>;interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3","dma4", "dma5", "dma6", "dma7";interrupts = <0 13 4>,<0 14 4>, <0 15 4>,<0 16 4>, <0 17 4>,<0 40 4>, <0 41 4>,<0 42 4>, <0 43 4>;#dma-cells = <1>;#dma-channels = <8>;#dma-requests = <4>;clocks = <&clkc 27>;clock-names = "apb_pclk";};devcfg: devcfg@f8007000 {compatible = "xlnx,zynq-devcfg-1.0";interrupt-parent = <&intc>;interrupts = <0 8 4>;reg = <0xf8007000 0x100>;clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>;clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3";syscon = <&slcr>;};efuse: efuse@f800d000 {compatible = "xlnx,zynq-efuse";reg = <0xf800d000 0x20>;};global_timer: timer@f8f00200 {compatible = "arm,cortex-a9-global-timer";reg = <0xf8f00200 0x20>;interrupts = <1 11 0x301>;interrupt-parent = <&intc>;clocks = <&clkc 4>;};ttc0: timer@f8001000 {interrupt-parent = <&intc>;interrupts = <0 10 4>, <0 11 4>, <0 12 4>;compatible = "cdns,ttc";clocks = <&clkc 6>;reg = <0xF8001000 0x1000>;};ttc1: timer@f8002000 {interrupt-parent = <&intc>;interrupts = <0 37 4>, <0 38 4>, <0 39 4>;compatible = "cdns,ttc";clocks = <&clkc 6>;reg = <0xF8002000 0x1000>;};scutimer: timer@f8f00600 {interrupt-parent = <&intc>;interrupts = <1 13 0x301>;compatible = "arm,cortex-a9-twd-timer";reg = <0xf8f00600 0x20>;clocks = <&clkc 4>;};usb0: usb@e0002000 {compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";status = "disabled";clocks = <&clkc 28>;interrupt-parent = <&intc>;interrupts = <0 21 4>;reg = <0xe0002000 0x1000>;phy_type = "ulpi";};usb1: usb@e0003000 {compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";status = "disabled";clocks = <&clkc 29>;interrupt-parent = <&intc>;interrupts = <0 44 4>;reg = <0xe0003000 0x1000>;phy_type = "ulpi";};watchdog0: watchdog@f8005000 {clocks = <&clkc 45>;compatible = "cdns,wdt-r1p2";interrupt-parent = <&intc>;interrupts = <0 9 1>;reg = <0xf8005000 0x1000>;timeout-sec = <10>;};};
};

就中断控制器,zynq-7000.dtsi而言,规定了中断控制器ARM Cortex-A9系列GIC(通用中断控制器)兼容。如下:

在这里插入图片描述
其中#interrupt-cells = <3>;指定中断源需要3个cells来唯一标识。这3个cells通常包含了中断类型、中断号和中断标志位掩码等信息。

其中reg = <0xF8F01000 0x1000>, <0xF8F00100 0x100>;定义了中断控制器的寄存器映射。它包含了两个寄存器区域的物理地址和长度。第一个寄存器区域的基地址是 0xF8F01000,长度是 0x1000(即 4096 字节)。第二个寄存器区域的基地址是 0xF8F00100,长度是 0x100(即 256 字节)。

直接看下各个设备的中断信息,整理如下:

以下是提取的带有 interrupt-parent =interrupts = 的行,并对应到所在的设备:

  • pmu@f8891000:

    • interrupt-parent = <&intc>
    • interrupts = <0 5 4>, <0 6 4>
  • adc@f8007100:

    • interrupt-parent = <&intc>
    • interrupts = <0 7 4>
  • can0@e0008000:

    • interrupt-parent = <&intc>
    • interrupts = <0 28 4>
  • can1@e0009000:

    • interrupt-parent = <&intc>
    • interrupts = <0 51 4>
  • gpio0@e000a000:

    • interrupt-parent = <&intc>
    • interrupts = <0 20 4>
  • i2c0@e0004000:

    • interrupt-parent = <&intc>
    • interrupts = <0 25 4>
  • i2c1@e0005000:

    • interrupt-parent = <&intc>
    • interrupts = <0 48 4>
  • intc@f8f01000:

    • interrupt-parent = <&intc>
    • interrupts = <1>
  • oc@f800c000:

    • interrupt-parent = <&intc>
    • interrupts = <0 3 4>
  • uart0@e0000000:

    • interrupt-parent = <&intc>
    • interrupts = <0 27 4>
  • uart1@e0001000:

    • interrupt-parent = <&intc>
    • interrupts = <0 50 4>
  • spi0@e0006000:

    • interrupt-parent = <&intc>
    • interrupts = <0 26 4>
  • spi1@e0007000:

    • interrupt-parent = <&intc>
    • interrupts = <0 49 4>
  • qspi@e000d000:

    • interrupt-parent = <&intc>
    • interrupts = <0 19 4>
  • mmc@e0100000:

    • interrupt-parent = <&intc>
    • interrupts = <0 24 4>
  • mmc@e0101000:

    • interrupt-parent = <&intc>
    • interrupts = <0 47 4>
  • dmac@f8003000:

    • interrupt-parent = <&intc>
    • interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>
  • devcfg@f8007000:

    • interrupt-parent = <&intc>
    • interrupts = <0 8 4>
  • efuse@f800d000:

    • interrupt-parent = <&intc>
    • interrupts = <0 3 4>
  • timer@f8001000:

    • interrupt-parent = <&intc>
    • interrupts = <0 10 4>, <0 11 4>, <0 12 4>
  • timer@f8002000:

    • interrupt-parent = <&intc>
    • interrupts = <0 37 4>, <0 38 4>, <0 39 4>
  • timer@f8f00600:

    • interrupt-parent = <&intc>
    • interrupts = <1 13 0x301>
  • usb@e0002000:

    • interrupt-parent = <&intc>
    • interrupts = <0 21 4>
  • usb@e0003000:

    • interrupt-parent = <&intc>
    • interrupts = <0 44 4>
  • watchdog@f8005000:

    • interrupt-parent = <&intc>
    • interrupts = <0 9 1>

可以确定的是,如下SPI中断编号已经被占用:

5/6 @ pmu
7   @ adc
28  @ can0
51  @ can1
20  @ gpio0
25  @ i2c0
48  @ i2c1
2   @ L2C
3   @ ocmc
27  @ uart0
50  @ uart1
26  @ spi0
49  @ spi1
19  @ qspi
18  @ smcc
22  @ gem0
45  @ gem1
24  @ sdhci0
47  @ sdhci1
13/14/15/16/17/40/41/42/43  @ dmac
8   @ devcfg
11  @ global_timer
10/11/12  @ ttc0 (timer)
37/38/39  @ ttc1 (timer)
13  @ scutimer
21  @ usb0
44  @ usb1
9   @ watchdog0

但是问题又来了,以上是明面上被占用的中断编号,我们还不清楚规则之下不允许被占用的中断编号!

因此需要回到手册,仔细琢磨琢磨!

2.4 UG585中中断一章的翻译

回到UG585手册,和中断相关的页数不多,直接翻译文字了!

在这里插入图片描述
随后按照环境功能描述寄存器概述编程模型依次展开!

2.4.1 环境


本章描述了系统级中断环境和中断控制器的功能(参见Figure 7-1)。PS基于Arm架构,利用两个Cortex-A9处理器(CPUs)和GIC pl390中断控制器。单核设备包含一个Cortex-A9处理器(CPU),双核设备包含两个。本章讨论双核配置。

中断结构与CPUs密切相关,并接受来自I/O外设(IOP)和可编程逻辑(PL)的中断。本章包括以下关键主题:

  • 私有、共享和软件中断
  • GIC功能
  • 中断优先级和处理

私有、共享和软件中断

每个CPU都有一组私有外设中断(PPIs),使用分页寄存器进行私有访问。PPIs包括全局定时器、私有看门狗定时器、私有定时器和来自PL的FIQ/IRQ。软件生成的中断(SGIs)被路由到一个或两个CPUsSGIs通过向通用中断控制器(GIC)的寄存器写入生成,参见Register Overview部分。共享外设中断(SPIs)由PS和PL中的各种I/O和内存控制器生成。它们被路由到一个或两个CPUs。来自PS外设的SPI中断也被路由到PL

Generic Interrupt Controller (GIC)

通用中断控制器(GIC)是管理从PS和PL发送到CPUs的中断的集中资源。控制器启用、禁用、屏蔽和优先级排序中断源,并以编程方式将它们发送到选定的CPU(或CPUs),当CPU接口接受下一个中断时。此外,控制器支持安全扩展以实现安全感知系统。

该控制器基于Arm通用中断控制器架构版本1.0(GIC v1),非矢量。

寄存器通过CPU私有总线访问,以快速读写响应,避免互连中的临时阻塞或其他瓶颈。

中断分发器在将具有最高优先级的中断分派给各个CPUs之前集中所有中断源。GIC确保针对多个CPUs的中断只能由一个CPU一次处理。所有中断源都由唯一的中断ID号标识。所有中断源都有自己的可配置优先级和目标CPUs列表。

Resets and Clocks

中断控制器由重置子系统通过向SLCR中的A9_CPU_RST_CTRL寄存器的PERI_RST位写入来重置。相同的重置信号还重置CPU私有定时器和私有看门狗定时器(AWDT)。在重置时,所有挂起或正在服务的中断都被忽略。

中断控制器使用CPU_3x2x时钟(CPU频率的一半)运行。

Block Diagram

共享外设中断由包括PS中的I/O外设和PL中的逻辑的各种子系统生成。中断源在Figure 7-2中说明。

CPU Interrupt Signal Pass-through

来自PL的IRQ/FIQ可以通过GIC作为PPI#4和#1路由,或使用Figure 7-3中显示的直通多路复用器绕过GIC。此逻辑为两个CPUs实例化。直通模式通过mpcore.ICCICR寄存器启用,参见Table 7-1


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.4.2 功能描述


软件生成中断(SGI)

每个CPU可以使用软件生成中断(SGI)中断自身、另一个CPU或两个CPUs。有16个软件生成中断(参见Table 7-2)。通过向ICDSGIR寄存器写入SGI中断号并指定目标CPU(s)生成SGI。此写入通过CPU的私有总线进行。每个CPU都有自己的一组SGI寄存器,用于生成一个或多个16个软件生成中断。通过读取ICCIAR(中断确认)寄存器或向ICDICPR(中断清除-挂起)寄存器的相应位写入1来清除中断。

所有SGIs都是边缘触发的。SGIs的灵敏度类型是固定的,不能更改;ICDICFR0寄存器是只读的,因为它指定了所有16个SGIs的灵敏度类型。

CPU私有外设中断(PPI)

每个CPU连接到一组私有的五个外设中断。PPIs列在Table 7-3中。

PPIs的灵敏度类型是固定的,不能更改;因此,ICDICFR1寄存器是只读的,因为它指定了所有5个PPIs的灵敏度类型。请注意,来自PL的快速中断(FIQ)信号和中断(IRQ)信号被反转然后发送到中断控制器。因此,它们在PS-PL接口处为高电平有效,尽管ICDICFR1寄存器将它们反映为低电平有效。

共享外设中断(SPI)

一组大约60个来自各种模块的中断可以被路由到一个或两个CPUsPL。中断控制器管理这些中断的优先级和接收。

除了IRQ #61到#68和#84到#91,所有中断灵敏度类型都由请求源固定,不能更改。GIC必须编程以适应这些灵敏度类型。

对于电平灵敏度类型的中断,请求源必须提供一种机制,以便中断处理程序在中断被确认后清除中断。此要求适用于任何IRQF2P[n](来自PL)具有高电平灵敏度类型。

对于上升沿灵敏度类型的中断,请求源必须提供足够宽的脉冲以便GIC捕获。这通常至少为2个CPU_2x3x周期。此要求适用于任何IRQF2P[n](来自PL)具有上升沿灵敏度类型。

ICDICFR2ICDICFR5寄存器配置所有SPIs的中断类型。每个中断都有一个2位字段,指定灵敏度类型和处理模型。

SPI中断列在Table 7-4中。

中断灵敏度、目标和处理

进入GIC的中断有三种类型,如本节中所述:SPIPPISGI。一般来说,中断信号包括灵敏度设置,无论一个或两个CPUs处理中断,以及目标哪个CPUCPUs:零、一个或两个。然而,大多数中断信号的功能包括固定设置,而其他是部分可编程的。

有两组控制寄存器用于灵敏度、处理和目标:

  • mpcore.ICDICFR[5:0]寄存器:灵敏度和处理。参见Figure 7-4
  • mpcore.ICDIPTR[23:0]寄存器:目标CPU(s)。参见Figure 7-5

共享外设中断(SPI)

SPI中断可以目标为任意数量的CPUs,但只有一个CPU处理中断。如果中断目标为两个CPUs并且它们同时响应GIC,则MPcore确保只有一个CPU读取活动中断ID#。另一个CPU接收Spurious ID# 1023中断或下一个挂起中断,具体取决于时间。这消除了中断服务程序中锁定的要求。通过ICDIPTR [23:8]寄存器完成对CPU的目标。每个SPI中断的灵敏度必须编程以匹配Table 7-4、PS和PL共享外设中断(SPI)中列出的灵敏度。灵敏度使用ICDICFR [5:2]寄存器进行编程。

私有外设中断(PPI)

每个CPU都有自己的一组私有PPI中断,具有固定功能;这些中断的灵敏度、处理和目标不可编程。每个中断只转到其自己的CPU并由该CPU处理。ICDICFR [1]寄存器是只读的,ICDIPTR [5:2]寄存器基本上保留。

软件生成中断(SGI)

SGI中断始终是边缘敏感的,当软件向ICDSGIR寄存器写入中断号时生成。所有在ICDIPTR [23:8]中定义的目标CPUs必须处理中断以清除它。参见Figure 7-4Figure 7-5

等待中断事件信号(WFI)

CPU可以进入等待状态,在该状态中它等待中断(或事件)信号生成。发送到PL的等待中断信号在Application Processing Unit中描述。


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4.3 寄存器概述


ICCICD寄存器是pl390 GIC寄存器集的一部分。有60个SPI中断。这远远少于pl390可以支持的数量,因此在ICD中的中断使能、状态、优先级和处理器目标寄存器比pl390可能的要少得多。ICCICD寄存器的摘要列在Table 7-5中。

写保护锁

中断控制器提供了防止对关键配置寄存器进行写访问的功能。这是通过向APU_CTRL[CFGSDDISABLE]位写入1来完成的。

APU_CTRL寄存器是SoC的系统级控制寄存器集SLCR的一部分。它控制安全中断控制寄存器的写行为。

推荐:如果用户想要设置CFGSDDISABLE位,建议在软件配置中断控制器寄存器后的用户软件启动过程中进行。CFGSDDISABLE位只能通过上电复位(POR)清除。在设置CFGSDDISABLE位后,它将受保护的寄存器位更改为只读,因此这些安全中断的行为不能更改,即使在安全域中执行的恶意代码存在。


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4.4 编程模型

中断优先级

所有中断请求(PPISGISPI)都被分配一个唯一的ID号。控制器使用ID号进行仲裁。中断分发器保存每个CPU的挂起中断列表,然后在将其发送到CPU接口之前选择最高优先级的中断。优先级相同的中断通过选择最低ID来解决。

优先级逻辑是物理复制的,以实现同时为每个CPU选择最高优先级中断。中断分发器保存中断、处理器和激活信息的中央列表,并负责触发软件中断到CPUs

SGIPPI分发器寄存器是分组的,为每个连接的处理器提供单独的副本。硬件确保针对多个CPUs的中断一次只能由一个CPU处理。

中断分发器将最高挂起中断传输到CPU接口。它接收中断已被确认的信息,然后可以更改相应中断的状态。只有确认中断的CPU才能结束该中断。

中断处理

当IRQ线断言时,GIC对挂起中断的响应在Arm文档:IHI0048B_gic_architecture_specification.pdf(参见附录B,附加资源和法律声明)中描述。有关更多信息,请参阅第1.4.2节中的注释以及第3.2.4节中的附加信息。

如果中断在GIC中挂起并且IRQ被取消断言,则中断在GIC中变为非活动状态(CPU从未看到它)。

如果中断在GIC中处于活动状态(因为CPU接口已确认中断),那么软件ISR通过首先检查GIC寄存器,然后轮询I/O外设中断状态寄存器来确定原因。

Arm编程主题

Arm GIC架构规范包括以下编程主题:

  • GIC寄存器访问
  • 分发器和CPU接口
  • GIC安全扩展的影响
  • PU接口寄存器
  • 保存和恢复控制器状态

传统中断和安全扩展

当使用传统中断(IRQFIQ)时,如果中断处理程序以安全模式访问IRQ和FIQ(通过ICCICR[AckCtl]=1),则在读取中断ID时偶尔会发生竞态条件。在IRQ处理程序中也有看到FIQ ID的风险,因为GIC只知道处理程序正在读取的安全状态,而不知道是哪种类型的处理程序。

有两种可行的解决方案:

  • 仅将IRQ信号发送到重新进入的IRQ处理程序,并在GIC中使用抢占功能。
  • 使用FIQ和IRQ,ICCICR[AckCtl]=0,并使用TLB表以非安全模式处理IRQ,并以安全模式处理FIQ。

2.5 回到实验部分

如下SPI中断编号已经被占用,对比表7-4

5/6 @ pmu    在表7-4中 中断编号为  37/38
7   @ adc    在表7-4中 中断编号为  39
28  @ can0   在表7-4中 中断编号为  60
51  @ can1   在表7-4中 中断编号为  83
20  @ gpio0  在表7-4中 中断编号为  52
25  @ i2c0   在表7-4中 中断编号为  57
48  @ i2c1   在表7-4中 中断编号为  80
2   @ L2C    在表7-4中 中断编号为  34
3   @ ocmc   在表7-4中 中断编号为  35
27  @ uart0  在表7-4中 中断编号为  59
50  @ uart1  在表7-4中 中断编号为  82
26  @ spi0   在表7-4中 中断编号为  58
49  @ spi1   在表7-4中 中断编号为  81
19  @ qspi   在表7-4中 中断编号为  51
18  @ smcc   在表7-4中 中断编号为  50
22  @ gem0   在表7-4中 中断编号为  54
45  @ gem1   在表7-4中 中断编号为  77
24  @ sdhci0 在表7-4中 中断编号为  56
47  @ sdhci1 在表7-4中 中断编号为  79
13/14/15/16/17/40/41/42/43  @ dmac  在表7-4中 中断编号为  45/46/47/48/49/72/73/74/75
8   @ devcfg 在表7-4中 中断编号为  40
11  @ global_timer  在表7-4中 中断编号为  43
10/11/12  @ ttc0 (timer) 在表7-4中 中断编号为  42/43/44
37/38/39  @ ttc1 (timer) 在表7-4中 中断编号为  69/70/71
21  @ usb0   在表7-4中 中断编号为  53
44  @ usb1   在表7-4中 中断编号为  76
9   @ watchdog0 在表7-4中 中断编号为  41 (SWDT)

因此从表7-4中可以获取到的保留位有:

4  @ reserved  在表7-4中 中断编号为  36
61/62/63  @ reserved   在表7-4中 中断编号为  93/94/95

另外从设备树模板上来说,在指定好中断控制器后,我需要做的是继承中断控制器并指定中断编号和触发方式!如下:

			interrupt-parent = <&intc>;interrupts = <x y z>;   // 其中y可以是36、93、94、95,z是触发方式

然后看看interrupts的要求:

  • #interrupt-cells:指定编码一个中断源所需的单元格数。类型应为 <u32>,值应为 3。

    第 1 个单元是中断类型;0 表示 SPI 中断,1 表示 PI 中断。

    第 2 个单元包含中断类型的中断号。
    SPI 中断在范围 [0-987] 内。PI 中断在范围 [0-15] 内。

    第 3 个单元是标志位,编码如下:

    • bits[3:0] 触发类型和电平标志。
      • 1 = 低到高边沿触发
      • 2 = 高到低边沿触发(SPIs 无效)
      • 4 = 高电平电平敏感
      • 8 = 低电平电平敏感(SPIs 无效)。

因此interrupts = <x y z>;中的x=0表示SPI中断,y同注释,但是z就出问题了!

在这里插入图片描述
在这里插入图片描述
三处reserved均没有指定触发类型

因此对于z的赋值显得十分为难!所以没法儿再继续下去了!

但也不是没有收获!最起码中断的用户手册刷了一遍!

先把这个问题记录一下吧,以便于后续回头阅读!

如上对中断移植思路的分析,Alinx中基于中断的阻塞IO非阻塞IO异步IO都没法儿接着做了!不过基于Alinx的这些教程,还是学到了知识!

驱动开发的移植暂时先告一个段落吧!

放一下后续可以参考的驱动开发代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
#include <asm/mach/map.h>
#include <asm/io.h>/* 设备节点名称 */
#define DEVICE_NAME       "gpio_leds_our8"
/* 设备号个数 */
#define DEVID_COUNT       1
/* 驱动个数 */
#define DRIVE_COUNT       1
/* 主设备号 */
#define MAJOR_U
/* 次设备号 */
#define MINOR_U           0/* gpio 寄存器虚拟地址 */
static u32 *GPIO_DIRM_0;
/* gpio 使能寄存器 */
//static u32 *GPIO_OEN_0;
/* gpio 控制寄存器 */
static u32 *GPIO_DATA_0;
/* AMBA 外设时钟使能寄存器 */
//static u32 *APER_CLK_CTRL;/* 把驱动代码中会用到的数据打包进设备结构体 */
struct alinx_char_dev{dev_t devid; //设备号struct cdev cdev; //字符设备struct class *class; //类struct device *device; //设备struct device_node *nd; //设备树的设备节点
/** 并发处理 **/spinlock_t         lock;              //自旋锁变量
/** gpio **/int                alinx_key_gpio;    //gpio号int                key_sts;           //记录按键状态, 为1时被按下
/** 中断 **/unsigned int       irq;               //中断号
/** 定时器 **/struct timer_list  timer;             //定时器};/* 声明设备结构体 */
static struct alinx_char_dev alinx_char = {.cdev = {.owner = THIS_MODULE,},
};/* 中断服务函数 */
static irqreturn_t key_handler(int irq, void *dev)
{/* 按键按下或抬起时会进入中断 *//* 开启50毫秒的定时器用作防抖动 */mod_timer(&alinx_char.timer, jiffies + msecs_to_jiffies(50));return IRQ_RETVAL(IRQ_HANDLED);
}/* 定时器服务函数 */
void timer_function(struct timer_list *timer)
{unsigned long flags;/* 获取锁 */spin_lock_irqsave(&alinx_char.lock, flags);/* value用于获取按键值 */unsigned char value;/* 获取按键值 *///value = gpio_get_value(alinx_char.alinx_key_gpio);uint32_t reg_value = *GPIO_DATA_0;uint8_t bits_to_or = (reg_value >> 5) & 0xF;bits_to_or |= (1 << 3);  // 对应于第9位bits_to_or |= (1 << 2);  // 对应于第8位bits_to_or |= (1 << 1);  // 对应于第7位bits_to_or |= (1 << 0);  // 对应于第6位value = bits_to_or;if(value == 0){/* 按键按下, 状态置1 */alinx_char.key_sts = 1;}else{/* 按键抬起 */}/* 释放锁 */spin_unlock_irqrestore(&alinx_char.lock, flags);
}/* open 函数实现, 对应到 Linux 系统调用函数的 open 函数 */
static int gpio_leds_open(struct inode *inode_p, struct file *file_p)
{/* MIO_0 时钟使能 *///*APER_CLK_CTRL |= 0x00400000;/* MIO_0 设置成输出 */*GPIO_DIRM_0 |= 0x000001E0;/* MIO_0 使能 *///*GPIO_OEN_0 |= 0x0000000F;printk("gpio_test module open\n");return 0;
}/* write 函数实现, 对应到 Linux 系统调用函数的 write 函数 */
/*
static ssize_t gpio_leds_write(struct file *file_p, const char __user *buf, size_t len, loff_t *loff_t_p)
{int rst;char writeBuf[5] = {0};printk("gpio_test module write\n");rst = copy_from_user(writeBuf, buf, len);if(0 != rst){return -1;}if(1 != len){printk("gpio_test len err\n");return -2;}if(1 == writeBuf[0]){*GPIO_DATA_0 |= 0x0000000F;printk("gpio_test ON\n");}else if(0 == writeBuf[0]){*GPIO_DATA_0 &= 0xFFFFFFF0;printk("gpio_test OFF\n");}else{printk("gpio_test para err\n");return -3;}return 0;
}*//* read函数实现, 对应到Linux系统调用函数的write函数 */
static ssize_t gpio_leds_read(struct file *file_p, char __user *buf, size_t len, loff_t *loff_t_p)
{unsigned long flags;int ret;/* 获取锁 */spin_lock_irqsave(&alinx_char.lock, flags);/* keysts用于读取按键状态 *//* 返回按键状态值 */ret = copy_to_user(buf, &alinx_char.key_sts, sizeof(alinx_char.key_sts));/* 清除按键状态 */alinx_char.key_sts = 0;/* 释放锁 */spin_unlock_irqrestore(&alinx_char.lock, flags);return 0;
}/* release 函数实现, 对应到 Linux 系统调用函数的 close 函数 */
static int gpio_leds_release(struct inode *inode_p, struct file *file_p)
{printk("gpio_test module release\n");return 0;
}/* file_operations 结构体声明, 是上面 open、write 实现函数与系统调用函数对应的关键 */
static struct file_operations ax_char_fops = {.owner = THIS_MODULE,.open = gpio_leds_open,//.write = gpio_leds_write,.read = gpio_leds_read,.release = gpio_leds_release,
};/* 模块加载时会调用的函数 */
static int __init gpio_led_init(void)
{/* 用于接受返回值 */u32 ret = 0;/** 并发处理 **//* 初始化自旋锁 */spin_lock_init(&alinx_char.lock);/* 存放 reg 数据的数组 */u32 reg_data[10];/* 通过节点名称获取节点 */alinx_char.nd = of_find_node_by_name(NULL, "alinxkey");/* 4、获取 reg 属性内容 */ret = of_property_read_u32_array(alinx_char.nd, "reg", reg_data, 4);if(ret < 0){printk("get reg failed!\r\n");return -1;}else{/* do nothing */}/* 把需要修改的物理地址映射到虚拟地址 */GPIO_DIRM_0 = ioremap(reg_data[0], reg_data[1]);GPIO_DATA_0 = ioremap(reg_data[2], reg_data[3]);/** 中断 **//* 获取中断号 *///alinx_char.irq = gpio_to_irq(alinx_char.alinx_key_gpio);alinx_char.irq = irq_of_parse_and_map(alinx_char.nd, 1);if(alinx_char.irq < 0){printk("irq %d request failed\r\n", alinx_char.irq);return -EFAULT;}    /* 申请中断 */ret = request_irq(alinx_char.irq,key_handler,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"alinxkey",NULL);if(ret < 0){printk("irq %d request failed\r\n", alinx_char.irq);return -EFAULT;}/** 定时器 **/__init_timer(&alinx_char.timer, timer_function, 0);/** 字符设备框架 **//* 注册设备号 */alloc_chrdev_region(&alinx_char.devid, MINOR_U, DEVID_COUNT, DEVICE_NAME);/* 初始化字符设备结构体 */cdev_init(&alinx_char.cdev, &ax_char_fops);/* 注册字符设备 */cdev_add(&alinx_char.cdev, alinx_char.devid, DRIVE_COUNT);/* 创建类 */alinx_char.class = class_create(THIS_MODULE, DEVICE_NAME);if(IS_ERR(alinx_char.class)){return PTR_ERR(alinx_char.class);}/* 创建设备节点 */alinx_char.device = device_create(alinx_char.class, NULL,alinx_char.devid, NULL, DEVICE_NAME);if (IS_ERR(alinx_char.device)){return PTR_ERR(alinx_char.device);}return 0;
}/* 卸载模块 */
static void __exit gpio_led_exit(void)
{/** 中断 **//* 释放中断 */free_irq(alinx_char.irq, NULL);/** 定时器 **//* 删除定时器 */del_timer_sync(&alinx_char.timer);/** 字符设备框架 **//* 注销字符设备 */cdev_del(&alinx_char.cdev);/* 注销设备号 */unregister_chrdev_region(alinx_char.devid, DEVID_COUNT);/* 删除设备节点 */device_destroy(alinx_char.class, alinx_char.devid);/* 删除类 */class_destroy(alinx_char.class);/* 释放对虚拟地址的占用 */iounmap(GPIO_DIRM_0);iounmap(GPIO_OEN_0);iounmap(GPIO_DATA_0);iounmap(APER_CLK_CTRL);printk("gpio_led_dev_exit_ok\n");
}/* 标记加载、卸载函数 */
module_init(gpio_led_init);
module_exit(gpio_led_exit);/* 驱动描述信息 */
MODULE_AUTHOR("Alinx");
MODULE_ALIAS("gpio_led");
MODULE_DESCRIPTION("DEVICE TREE GPIO LED driver");
MODULE_VERSION("v1.0");
MODULE_LICENSE("GPL");

以上还需要再修改!

设备树如下:

/include/ "system-conf.dtsi"/ {  model ="ZYNQ7035"; compatible = "xlnx,zynq-7000"; usb_phy0: phy0@e0002000 {compatible = "ulpi-phy";#phy-cells = <0>;reg = <0xe0002000 0x1000>;view-port = <0x0170>;drv-vbus;};alinxled {compatible = "alinxled";reg = <0xE000A284 0x04 /* gpio 方向寄存器 */0xE000A288 0x04 /* gpio 使能寄存器 */0xE000A048 0x04 /* gpio 控制寄存器 */0xF800012C 0x04 /* AMBA 外设时钟使能寄存器 */>;};alinxkey {compatible = "alinxkey";reg = <0xE000A284 0x04 /* gpio 方向寄存器 */0xE000A048 0x04 /* gpio 控制寄存器 */0xF800012C 0x04 /* AMBA 外设时钟使能寄存器 */>;interrupt-parent = <&intc>;interrupts = <0 y z>;   // 其中y可以是36、93、94、95};
};&usb0 {status = "okay";dr_mode = "host";usb-phy = <&usb_phy0>;
};&uart0 {
u-boot,dm-pre-reloc;
};&uart1 {
u-boot,dm-pre-reloc;
};

总结

本文总结了中断相关的设备树内容、UG585手册以及探索了基于中断的驱动存在的问题。

http://www.xdnf.cn/news/15674.html

相关文章:

  • 数据查找 二叉查找树
  • # Redis-stable 如何在Linux系统上安装和配置
  • java常见的jvm内存分析工具
  • C语言-一维数组,二维数组
  • 菱形继承 虚继承
  • 快速安装GitLab指南
  • go安装使用gin 框架
  • web3 区块链技术与用
  • 【论文精读】基于共识的分布式量子分解算法用于考虑最优传输线切换的安全约束机组组合
  • Django母婴商城项目实践(五)- 数据模型的搭建
  • UniApp TabBar 用户头像方案:绕过原生限制的实践
  • Selenium 攻略:从元素操作到 WebDriver 实战
  • STM32之L298N电机驱动模块
  • 【iOS】MRC与ARC
  • Fish Speech:开源多语言语音合成的革命性突破
  • 伺服电机与步进电机要点详解
  • 专题:2025智能体研究报告|附70份报告PDF、原数据表汇总下载
  • 质变科技亮相可信数据库发展大会,参编《数据库发展研究报告2025》
  • Linux学习之认识Linux的基本指令
  • 前端性能优化“核武器”:新一代图片格式(AVIF/WebP)与自动化优化流程实战
  • 多模态大模型重构人机交互,全感官时代已来
  • 微服务项目总结
  • 短视频矩阵系统:选择与开发的全方位指南
  • Python网络爬虫实现selenium对百度识图二次开发以及批量保存Excel
  • Java学习------使用Jemter测试若依项目自定义的功能
  • Unity 常见数据结构分析与实战展示 C#
  • APIs案例及知识点串讲(下)
  • CES Asia 2025备受瞩目,跨国企业锁定亚洲战略首发契机
  • 基于Ubuntu22.04源码安装配置RabbitVCS过程记录
  • ARM64高速缓存,内存属性及MAIR配置