关于这部分请参考S3C2440的芯片手册或者博文TQ2440中断系统
下面简单介绍:
从图中可以看到,中断主要分为两级,我们可以理解为是两个中断控制器的嵌套或者级联。S3C2440总共支持60个中断源,包含了主中断源和子中断源。
寄存器功能介绍:
1、SRCPND 地址: 0x4A000000 功能:每一位代表一个主中断,置1表示有对应的主中断请求,对应位写入1可以清除中断
2、INTMOD 地址: 0x4A000004 功能:设置对应的主中断为IRQ还是FIQ, 置1表示FIQ
3、INTMSK 地址: 0x4A000008 功能:置1表示对应的主中断被屏蔽(不会影响SRCPND)
4、INTPND 地址: 0x4A000010 功能:表示对应的主中断被request,只可能有一位被置位,写入1可以清除中断
5、INTOFFSET 地址:0x4A000014 功能:存放的是发生中断请求的主中断号
6、SUBSRCPND 地址:0x4A000018 功能:每一位代表一个子中断,置一表示对应子中断请求,对应位写入1清除子中断请求
7、INTSUBMSK 地址:0x4A00001C 功能:置1表示对应的子中断被屏蔽
32个主中断:
图一
15个子中断:
图二
图三
外部中断:
EINT0~7对应的GPIO是GPF0~7
EINT8~23对应的GPIO是GPG0~15
1、中断控制器
intc:interrupt-controller@4a000000 {
compatible = "samsung,s3c2410-irq";
reg =
interrupt-controller;
#interrupt-cells =
};
2、引用
serial@50000000 {
compatible = "samsung,s3c2440-uart";
reg =
interrupts =
status = "okay";
clock-names = "uart";
clocks =
pinctrl-names = "default";
pinctrl-0 =
};
i2c:i2c@54000000 {
compatible = "samsung,s3c2410-i2c";
reg =
interrupts =
#address-cells =
#size-cells =
};
上面的serial和i2c设备比较典型,一个引用的是主中断,另一个引用的是子中断。从中断控制器的#interrupt-cells属性知道,要描述一个中断需要四个参数,每一个参数的含义需要由中断控制器的驱动来解释,具体是有中断控制器的irq_domain_ops中的xlate来解释,对于s3c2440就是drivers/irqchip/irq-s3c24xx.c中的s3c24xx_irq_xlate_of。
1 /* Translate our of irq notation
2 * format:
3 */
4 static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n,
5 const u32 *intspec, unsigned int intsize,
6 irq_hw_number_t *out_hwirq, unsigned int *out_type)
7 {
8 struct s3c_irq_intc *intc;
9 struct s3c_irq_intc *parent_intc;
10 struct s3c_irq_data *irq_data;
11 struct s3c_irq_data *parent_irq_data;
12 int irqno;
13
14 if (WARN_ON(intsize < 4)) //如果参数个数不能小于4
15 return -EINVAL;
16 // 从这里知道,第一个参数不能大于2,只能是0和1, 0表示主中断,2表示子中断
17 if (intspec[0] > 2 || !s3c_intc[intspec[0]]) {
18 pr_err("controller number %d invalidn", intspec[0]);
19 return -EINVAL;
20 }
21 // s3c_intc[0]表示主中断控制器,s3c_intc[1]表示子中断控制器
22 intc = s3c_intc[intspec[0]];
23
24 // 第三个参数表示的是硬件中断号,从这里知道,主中断的硬件中断是0~31,子中断的硬件中断是32及其以上
25 *out_hwirq = intspec[0] * 32 + intspec[2];
26 // 第四个参数表示的是中断类型,可以查看IRQ_TYPE_SENSE_MASK定义,就知道含义:
27 // 1表示上升沿触发,2表示下降沿触发,3表示双边沿触发,4表示高电平触发,8表示低电平触发,12表示高低电平触发
28 *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK;
29 // 如果是主中断,则intc->parent为NULL, 否则非空
30 parent_intc = intc->parent;
31 if (parent_intc) { // 子中断
32 irq_data = &intc->irqs[intspec[2]];
33 // 对于子中断,第二个参数才有意义,表示该子中断所隶属的主中断的硬件中断号
34 irq_data->parent_irq = intspec[1];
35 parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
36 parent_irq_data->sub_intc = intc;
37 // sub_bits中记录该主中断下的子中断被被使用的情况
38 parent_irq_data->sub_bits |= (1UL << intspec[2]);
39 // 将主中断号映射成虚拟中断号
40 /* parent_intc is always s3c_intc[0], so no offset */
41 irqno = irq_create_mapping(parent_intc->domain, intspec[1]);
42 if (irqno < 0) {
43 pr_err("irq: could not map parent interruptn");
44 return irqno;
45 }
46 // 这里设置irqno对应的irq_desc的handle_irq为s3c_irq_demux
47 // 从函数名称中就可以看出, 这个函数会再次进行检测该主中断的哪个子中断被请求
48 irq_set_chained_handler(irqno, s3c_irq_demux);
49 }
50
51 return 0;
52 }
从这里我们知道,interrupts属性中的四个参数中的含义:
以串口的
三、中断控制器驱动
中断控制器驱动:drivers/irqchip/irq-s3c24xx.c
初始化入口:
1 static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = {
2 { // 主中断
3 .name = "intc",
4 .offset = 0,
5 }, { // 子中断
6 .name = "subintc",
7 .offset = 0x18, // 寄存器地址偏移
8 .parent = &s3c_intc[0],
9 }
10 };
11
12 int __init s3c2410_init_intc_of(struct device_node *np,
13 struct device_node *interrupt_parent)
14 {
15 return s3c_init_intc_of(np, interrupt_parent,
16 s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));
17 }
18 IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of);
在内核启动的时候,函数s3c2410_init_intc_of会被调用。
下面我们分析函数s3c_init_intc_of:
1 static int __init s3c_init_intc_of(struct device_node *np,
2 struct device_node *interrupt_parent,
3 struct s3c24xx_irq_of_ctrl *s3c_ctrl, int num_ctrl)
4 {
5 struct s3c_irq_intc *intc;
6 struct s3c24xx_irq_of_ctrl *ctrl;
7 struct irq_domain *domain;
8 void __iomem *reg_base;
9 int i;
10
11 // 对中断控制器的reg属性所表示地址空间进行映射
12 reg_base = of_iomap(np, 0);
13
14 // 为该中断控制器创建irq_domain,一共支持64个中断,对应的irq_domain_ops是s3c24xx_irq_ops_of
15 domain = irq_domain_add_linear(np, num_ctrl * 32,
16 &s3c24xx_irq_ops_of, NULL);
17 // 依次处理两个中断控制器
18 for (i = 0; i < num_ctrl; i++) {
19 ctrl = &s3c_ctrl[i];
20
21 pr_debug("irq: found controller %sn", ctrl->name);
22 // 主和子中断控制器各分配一个s3c_irq_intc
23 intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
24 // 主和子中断控制器共享一个irq_domain
25 intc->domain = domain;
26 // 为主和子中断控制器下的每个中断各分配一个s3c_irq_data结构体
27 intc->irqs = kzalloc(sizeof(struct s3c_irq_data) * 32,
28 GFP_KERNEL);
29
30 if (ctrl->parent) { // 子中断控制器
31 intc->reg_pending = reg_base + ctrl->offset; // SUBSRCPND
32 intc->reg_mask = reg_base + ctrl->offset + 0x4; // INTSUBMSK
33
34 // 由于先处理的是s3c2410_ctrl[0],所以在处理子中断的时候,*(ctrl->parent)非空
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』