GIC是ARM推出的一个通用的中断控制器,全志H3中使用了GIC的多核方案,符合GIC V2规格。ARM多核处理器一般搭建一个GIC来提供中断控制功能,中端控制器是连接外设中断系统和CPU系统的桥梁。
ARM上把中断分为三类:
- PPI(private peripheral interrupt) 16~31
这些中断一般是发送给特定的Cpu的,比如每个Cpu有自己对应的Physicaltimer,产生的中断信号就发送给这个特定的cpu进行处理
- SPI(shared processor interrupts)
这是常见的外部设备中断,也定义为共享中断,比如按键触发一个中断,手机触摸屏触发的中断,共享的意思是说可以多个Cpu或者说Core处理,不限定特定的Cpu。一般定义的硬件中断号范围31~1019.Cortex-A15和A9上的GIC最多支持224个SPI。
- SGI(software generated interrupts)
软件出发产生的中断,中断号范围0~15,也就是最前的16个中断,相当于IPI,简单的说Cpu_1要给Cpu_2发送特定信息,比如时间同步,全局进程调度信息,就通过软件中断方式,目标Cpu接受到这样的中断信息,可以获取到信息是哪个Cpu发送过来的,具体的中断ID是哪个数字,从而找到对应处理方式进行处理。
全志H3中断体系结构的拓扑如下所示,4个CPU核连接到root GIC,然而子中断控制器(比如GPIO控制器)不与CPU直接相连,而是上报至root GIC的某个SPI中断上,root GIC负责接收子中断控制器信息然后向某个CPU汇报。
在全志H3中,不是每个GPIO bank都可以作为中断控制器的,只有PA,PG,和PL可以作为中断控制器。PA这一bank下的PA0,PA1,PA2。。。等request line公用一个SPI-43号中断。
使用nanopi-m1的PA9 外部中断
在设备树源文件sun8i-h3-nanopi-m1.dts添加interrupt-demo节点
-
interrupt_demo: interrupt_demo {
-
compatible =
"nanopi-m1,interrupt_demo";
-
interrupt-parent = <&pio>;
-
//interrupts = <0 9 IRQ_TYPE_EDGE_FALLING>;
-
key-gpio = <&pio
0
9
GPIO_ACTIVE_LOW>;
-
};
interrupt-demo节点用interrupt-parent属性指明其中断父亲属于pinctrl,pinctrl节点的描述如下所示,其中interrupt-cells为3说明interrupt-demo节点的interrupts属性值需要3个bytes来表示,
-
pio: pinctrl@
01c20800 {
-
/* compatible is in per SoC .dtsi file */
-
reg = <
0x01c20800
0x400>;
-
interrupts = <GIC_SPI
11 IRQ_TYPE_LEVEL_HIGH>,
-
<GIC_SPI
17 IRQ_TYPE_LEVEL_HIGH>;
-
clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
-
clock-names =
"apb",
"hosc",
"losc";
-
gpio-controller;
-
#gpio-cells = <3>;
-
interrupt-controller;
-
#interrupt-cells = <3>;
-
......
-
};
驱动程序
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/platform_device.h>
-
#include <linux/gpio.h>
-
#include <linux/of.h>
-
#include <linux/of_gpio.h>
-
#include <linux/interrupt.h>
-
-
typedef
struct
-
{
-
int gpio;
-
int irq;
-
}
int_demo_data_t;
-
-
static irqreturn_t int_demo_isr(int irq, void *dev_id)
-
{
-
int_demo_data_t *data = dev_id;
-
-
printk(
"%s enter, gpio:%d, irq: %d\n", __func__, data->gpio, data->irq);
-
-
return IRQ_HANDLED;
-
}
-
-
static int int_demo_probe(struct platform_device *pdev) {
-
struct
device *dev = &pdev->dev;
-
int irq_gpio =
-1;
-
int irq =
-1;
-
int ret =
0;
-
int i =
0;
-
int_demo_data_t *data ;
-
-
printk(
"%s enter.\n", __func__);
-
-
-
data =
devm_kmalloc(dev,
sizeof(*data), GFP_KERNEL);
-
if (!data) {
-
printk(
"malloc fail for data\n");
-
return
-1;
-
}
-
-
-
-
irq_gpio =
of_get_named_gpio(dev->of_node,
"key-gpio",
0);
-
-
data[
0].gpio = irq_gpio;
-
-
irq =
gpio_to_irq(irq_gpio);
-
-
-
data[
0].irq = irq;
-
-
printk(
"%s: gpio: %d ---> irq (%d)\n", __func__, irq_gpio, irq);
-
-
ret =
devm_request_any_context_irq(dev, irq,
-
int_demo_isr, IRQF_TRIGGER_FALLING,
"key-gpio", data);
-
if (ret <
0) {
-
dev_err(dev,
"Unable to claim irq %d; error %d\n",
-
irq, ret);
-
return
-1;
-
}
-
-
-
return
0;
-
-
-
}
-
-
static int int_demo_remove(struct platform_device *pdev) {
-
-
printk(
"%s enter.\n", __func__);
-
-
return
0;
-
}
-
-
static
const
struct
of_device_id int_demo_dt_ids[] = {
-
{ .compatible =
"nanopi-m1,interrupt_demo", },
-
{},
-
};
-
-
-
static
struct
platform_driver int_demo_driver = {
-
.driver = {
-
.name =
"interrupt_demo",
-
.of_match_table = int_demo_dt_ids,
-
},
-
.probe = int_demo_probe,
-
.remove = int_demo_remove,
-
};
-
-
static int int_demo_init(void)
-
{
-
platform_driver_register(&int_demo_driver);
-
return
0;
-
}
-
static void __exit int_demo_exit(void)
-
{
-
platform_driver_unregister(&int_demo_driver);
-
}
-
-
module_init(int_demo_init);
-
module_exit(int_demo_exit);
-
-
MODULE_LICENSE(
"GPL");
-
MODULE_AUTHOR(
"WU");
编写驱动程序的Makefile,编译,加载模块
-
root
@wu
:/mnt/driver_test/irq_test
# [ 377.666140] int_demo_isr enter, gpio:9, irq: 71
-
[
377.743009] int_demo_isr enter,
gpio:
9,
irq:
71
-
[
377.927100] int_demo_isr enter,
gpio:
9,
irq:
71
-
[
378.000418] int_demo_isr enter,
gpio:
9,
irq:
71
-
[
480.665685] int_demo_isr enter,
gpio:
9,
irq:
71
-
-
-
root
@wu
:/mnt/driver_test/irq_test
# cat /proc/interrupts
-
71:
0
0
0
0 sunxi_pio_edge
9 Edge key-gpio