姓名:彭东林
E-mail:pengdonglin137@163.com
QQ:405728433
平台
板子:TQ2440
内核:Linux-4.9
u-boot: 2015.04
工具链: arm-none-linux-gnueabi-gcc 4.8.3
概述
在博文基於tiny4412的Linux內核移植 --- 实例学习中断背后的知识(1)中介绍了最新的Linux下中断的知识,下面我们再结合TQ2440来分析一下。
正文
一、基础知识
关于这部分请参考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 = <0x4a000000 0x100>; interrupt-controller; #interrupt-cells = <4>; };
serial@50000000 { compatible = "samsung,s3c2440-uart"; reg = <0x50000000 0x4000>; interrupts = <1 28 0 4>, <1 28 1 4>; status = "okay"; clock-names = "uart"; clocks = <&clock PCLK_UART0>; pinctrl-names = "default"; pinctrl-0 = <0x3>; }; i2c:i2c@54000000 { compatible = "samsung,s3c2410-i2c"; reg = <0x54000000 0x100>; interrupts = <0 0 27 3>; #address-cells = <1>; #size-cells = <0>; };
1 /* Translate our of irq notation 2 * format: <ctrl_num ctrl_irq parent_irq type> 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 invalid\n", 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 interrupt\n"); 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属性中的四个参数中的含义: