LINUX-I.MX6U从零开始之1.6--中断

目录

        • 一,Cortex-A7 中断系统
        • 二,中断控制器GIC
          • 2.1 GIC框架
          • 2.2 中断 ID
          • 2.3 GID逻辑分块
            • 2.3.1 Distributor( 分发器端)
            • 2.3.2 CPU Interface(CPU 接口端)
          • 2.4 CP15 协处理器
        • 三,中断使能
          • 3.1 IRQ 和 FIQ 总中断使能
          • 3.2 ID0~ID1019 中断使能和禁止
        • 四,中断优先级设置
          • 4.1 优先级数
          • 4.2 抢占优先级和子优先级位数设置
          • 4.3 优先级设置
        • 五,core_ca7.h
        • 个人理解(如有错误,还望留言指正)

一,Cortex-A7 中断系统

Cortex-A7 内核有 8 个异常中断
LINUX-I.MX6U从零开始之1.6--中断_第1张图片
复位中断(Rest), CPU 复位以后就会进入复位中断, 我们可以在复位中断服务函数里面做一些初始化工作,比如初始化 SP 指针、DDR 等等。
未定义指令中断(Undefined Instruction),如果指令不能识别的话就会产生此中断。
软中断(Software Interrupt,SWI),由 SWI 指令引起的中断,Linux 的系统调用会用 SWI 指令来引起软中断,通过软中断来陷入到内核空间。
指令预取中止中断(Prefetch Abort),预取指令的出错的时候会产生此中断。
数据访问中止中断(Data Abort),访问数据出错的时候会产生此中断。
IRQ 中断(IRQ Interrupt),外部中断,前面已经说了,芯片内部的外设中断都会引起此中断的发生。
FIQ 中断(FIQ Interrupt),快速中断,如果需要快速处理中断的话就可以使用此中。
我们常用的就是复位中断和 IRQ 中断,Cortex-A 内核 CPU 的所有外部中断都属于IQR 中断。
LINUX-I.MX6U从零开始之1.6--中断_第2张图片

二,中断控制器GIC

2.1 GIC框架

GIC 有 4 个版本:V1~V4,V1 是最老的版本,已经被废弃了。GIC V2 是给 ARMv7-A 架构使用的,比如 Cortex-A7、Cortex-A9、Cortex-A15 等,V3 和 V4 是给 ARMv8-A/R 架构使用的,也就是 64 位芯片使用的。
ARM 针对 GIC V2 开发出了 GIC400 这个中断控制器 IP 核。当 GIC 接收到外部中断信号以后就会报给 ARM 内核,但是ARM 内核只提供了四个信号给 GIC 来汇报中断情况:
VFIQ:虚拟快速 FIQ。
VIRQ:虚拟快速 IRQ。
FIQ:快速中断 IRQ。
IRQ:外部中断 IRQ。
LINUX-I.MX6U从零开始之1.6--中断_第3张图片
GICV2 的逻辑图如图所示:
LINUX-I.MX6U从零开始之1.6--中断_第4张图片
左侧部分就是中断源,中间部分就是 GIC 控制器,最右侧就是中断控制器向处理器内核发送中断信息。中间 GIC 部分将众多的中断源分为分为三类:
①、SPI(Shared Peripheral Interrupt),共享中断,顾名思义,所有 Core 共享的中断,这个是最
常见的,那些外部中断都属于 SPI 中断(注意!不是 SPI 总线那个中断) 。比如按键中断、串口中断等等,这些中断所有的 Core 都可以处理,不限定特定 Core。
②、PPI(Private Peripheral Interrupt),私有中断,我们说了 GIC 是支持多核的,每个核肯定有自己独有的中断。 这些独有的中断肯定是要指定的核心处理, 因此这些中断就叫做私有中断。
③、SGI(Software-generated Interrupt),软件中断,由软件触发引起的中断,通过向寄存器GICD_SGIR 写入数据来触发,系统会使用 SGI 中断来完成多核之间的通信。

2.2 中断 ID

中断源有很多,为了区分这些不同的中断源肯定要给他们分配一个唯一 ID,这些 ID 就是中断 ID。每一个 CPU 最多支持 1020 个中断 ID,中断 ID 号为 ID0~ID1019。这 1020 个 ID 包含了 PPI、SPI 和 SGI.
ID0~ID15:这 16 个 ID 分配给 SGI。
ID16~ID31:这 16 个 ID 分配给 PPI。
ID32~ID1019:这 988 个 ID 分配给 SPI,像 GPIO 中断、串口中断等这些外部中断。
I.MX6U 的总共使用了 128 个中断 ID,加上前面属于 PPI 和 SGI 的 32 个 ID,I.MX6U 的中断源共有 128+32=160个。
128 个中断 ID 对应的中断在《I.MX6ULL 参考手册》的“3.2 Cortex A7 interrupts”小节。
MCIMX6Y2C.h里的枚举类型 IRQn_Type,枚举出了 I.MX6U 的所有中断。

2.3 GID逻辑分块

GIC 架构分为了两个逻辑块: Distributor 和 CPU Interface, 也就是分发器端和 CPU 接口端。
例程“9_int”(原子LINUX),core_ca7.h 定义了 GIC 结构体。
结构体第 5 行是 GIC 的分发器端相关寄存器,其相对于 GIC 基地址偏移为 0X1000,获取到GIC 基地址以后只需要加上 0X1000 即可访问 GIC 分发器端寄存器。
结构体第 51 行是 GIC 的 CPU 接口端相关寄存器,其相对于 GIC 基地址的偏移为 0X2000,获取到 GIC 基地址以后只需要加上 0X2000 即可访问 GIC 的 CPU 接口段寄存器。

2.3.1 Distributor( 分发器端)

此逻辑块负责处理各个中断事件的分发问题,也就是中断事件应该发送到哪个 CPU Interface 上去。分发器收集所有的中断源,可以控制每个中断的优先级, 它总是将优先级最高的中断事件发送到 CPU 接口端。 分发器端要做的主要工作如下:
①、全局中断使能控制。
②、控制每一个中断的使能或者关闭。
③、设置每个中断的优先级。
④、设置每个中断的目标处理器列表。
⑤、设置每个外部中断的触发模式:电平触发或边沿触发。
⑥、设置每个中断属于组 0 还是组 1。

2.3.2 CPU Interface(CPU 接口端)

CPU 接口端听名字就知道是和 CPU Core 相连接的,因此每个 CPU Core 都可以在 GIC 中找到一个与之对应的 CPU Interface。CPU 接口端就是分发器和 CPU Core 之间的桥梁,CPU 接口端主要工作如下:
①、使能或者关闭发送到 CPU Core 的中断请求信号。
②、应答中断。
③、通知中断处理完成。
④、设置优先级掩码,通过掩码来设置哪些中断不需要上报给 CPU Core。
⑤、定义抢占策略。
⑥、当多个中断到来的时候,选择优先级最高的中断通知给 CPU Core。

2.4 CP15 协处理器

关于 CP15 协处理器和其相关寄存器的详细内容请参考下面两份文档:
《ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》第 1469 页“B3.17
Oranization of the CP15 registers in a VMSA implementation” 。
《Cortex-A7 Technical ReferenceManua.pdf》第 55 页“Capter 4 System Control” 。
CP15 协处理器一般用于存储系统管理,但是在中断中也会使用到,CP15 协处理器一共有
16 个 32 位寄存器。CP15 协处理器的访问通过指令完成
LINUX-I.MX6U从零开始之1.6--中断_第5张图片

三,中断使能

3.1 IRQ 和 FIQ 总中断使能

寄存器 CPSR 的 I=1 禁止 IRQ,当 I=0 使能 IRQ;F=1 禁止 FIQ,F=0 使能 FIQ。
我们还有更简单的指令来完成 IRQ 或者 FIQ 的使能和禁止.
LINUX-I.MX6U从零开始之1.6--中断_第6张图片

3.2 ID0~ID1019 中断使能和禁止

GIC 寄存器 GICD_ISENABLERn 和 GICD_ ICENABLERn 用来完成外部中断的使能和禁止,对于 Cortex-A7 内核来说中断 ID 只使用了 512 个。一个 bit 控制一个中断 ID 的使能,那么就需要 512/32=16 个 GICD_ISENABLER 寄存器来完成中断的使能。同理,也需要 16 个GICD_ICENABLER 寄存器来完成中断的禁止。其中 GICD_ISENABLER0 的 bit[15:0]对应ID15-0 的 SGI 中断,GICD_ISENABLER0 的 bit[31:16]对应 ID31-16 的 PPI 中断。剩下的GICD_ISENABLER1–GICD_ISENABLER15 就是控制 SPI 中断的。

四,中断优先级设置

4.1 优先级数

Cortex-A7 最多可以支持 256 个优先级,数字越小,优先级越高!I.MX6U 选择了 32 个优先级。在使用中断的时候需要初始化 GICC_PMR 寄存器,此寄存器用来决定使用几级优先级。
GICC_PMR 寄存器只有低 8 位有效,这 8 位最多可以设置 256 个优先级。
I.MX6U 支持 32 个优先级,所以 GICC_PMR 要设置为 0b11111000。

4.2 抢占优先级和子优先级位数设置

抢占优先级和子优先级各占多少位是由寄存器 GICC_BPR 来决定的。
寄存器GICC_BPR只有低3位有效, 其值不同, 抢占优先级和子优先级占用的位数也不同。
LINUX-I.MX6U从零开始之1.6--中断_第7张图片
为了简单起见,一般将所有的中断优先级位都配置为抢占优先级,比如 I.MX6U 的优先级位数为 5(32 个优先级), 所以可以设置 Binary point 为 2, 表示 5 个优先级位全部为抢占优先级。

4.3 优先级设置

前面已经设置好了 I.MX6U 一共有 32 个抢占优先级,数字越小优先级越高。具体要使用某个中断的时候就可以设置其优先级为 0~31。某个中断 ID 的中断优先级设置由寄存器D_IPRIORITYR 来完成,前面说了 Cortex-A7 使用了 512 个中断 ID,每个中断 ID 配有一个优先级寄存器,所以一共有 512 个 D_IPRIORITYR 寄存器。如果优先级个数为 32 的话,使用寄存器 D_IPRIORITYR 的 bit7:4 来设置优先级,也就是说实际的优先级要左移 3 位。比如要设置ID40 中断的优先级为 5,示例代码如下:

GICD_IPRIORITYR[40] = 5 << 3;

五,core_ca7.h

core_ca7.h中关于中断主要有10个函数:

个人理解(如有错误,还望留言指正)

I.MX6U 有很多中断,这里主要说的是IRQ总中断,串口中断啥的都在里面,有中断就有中断源,中断源由中断ID配置。GID逻辑分块是配置中断模式和中断优先级的,而中断模式地址是由 CP15 协处理器获得。
设置 GICC_PMR,配置优先级个数, I.MX6U 支持 32 级优先级。
设置抢占优先级和子优先级位数,将所有的位数都设置为抢占优先级。
设置指定中断 ID 的优先级,也就是设置外设优先级。

你可能感兴趣的:(linux)