×
单片机 > 单片机程序设计 > 详情

基于设备树的TQ2440的中断(1)

发布时间:2020-08-31 发布时间:
|

一、基础知识

关于这部分请参考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)非空


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
MSP430F5529 上手小例程2