历史上的今天
今天是:2025年02月11日(星期二)
2020年02月11日 | 基于设备树的TQ2440的中断(1)
2020-02-11 来源:eefocus
一、基础知识
关于这部分请参考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)非空
35 // 是主中断控制器对应的s3c_irq_intc
36 if (*(ctrl->parent)) {
37 intc->parent = *(ctrl->parent);
38 } else {
39 pr_warn("irq: parent of %s missingn",
40 ctrl->name);
41 kfree(intc->irqs);
42 kfree(intc);
43 continue;
44 }
45 } else { // 主中断控制器
46 intc->reg_pending = reg_base + ctrl->offset; //SRCPND
47 intc->reg_mask = reg_base + ctrl->offset + 0x08; //INTMSK
48 intc->reg_intpnd = reg_base + ctrl->offset + 0x10; //INTPND
49 }
50
51 s3c24xx_clear_intc(intc); // 清除中断
52 s3c_intc[i] = intc;
53 }
54 // 将handle_arch_irq设置为s3c24xx_handle_irq, 这样在发生中断后,会从汇编entry-armv.S中
55 // 调转到s3c24xx_handle_irq
56 set_handle_irq(s3c24xx_handle_irq);
57
58 return 0;
59 }
中断控制启动的初始化,结构体s3c24xx_irq_ops_of中的map和xlate还没有分析,放到下面分析。
四、interrupts属性的解析
在内核启动期间解析设备树,将device_node转换为platform_device的时候会处理节点中的interrupts属性,将其转换为irq resource,同时在所属的irq domain中建立起hwirq到virq的映射,下面列出主要的函数调用,期间就会调用上面中断控制器的irq_domain的s3c24xx_irq_ops_of中的xlate和map:
上一篇:移植Python2到TQ2440
史海拾趣
|
关于IO0PIN指令的疑惑 最近在调一个键盘程序(LPC2103),用到了IO0PIN读端口指令(据说这是飞利浦系列的BUG),发现这个指令没有手册上说的那么简单呐,直接读是读不出来的。有人说要读一个输入状态的端口,要先把它设为输出,然后置高,最后再设 ...… 查看全部问答> |
|
我已经从把摄像头采集的数据保存使用 mmap 内存映射来获取了图像,当用write函数得出的是jpeg格式的 我想得到bmp格式的图片怎么做,跪求,急用。谢谢各位。 … 查看全部问答> |
|
用verilog HDL 实现一个网络加密的算法(md5),有没有哪位高手能给点帮助,我邮箱是poppy220@126.com 先谢过啦!^_^ … 查看全部问答> |
|
最近刚刚开始接触STM32,今天调试串口的时候发现一个很无奈的问题,源代码基本都是使用keil自带的demo,就不列举了。修改以下这些设置:/* PLLCLK = 12MHz * 6= 72 MHz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6 ...… 查看全部问答> |
|
想了想,还是把它出掉好了,STM32+W5100+SPI Flash+TFT,有点给力 这其实不是个开发板,而是个接近完成的产品(接近完成是指研发流程已经走完,但还未能进入市场)但资源比较给力---------------> STM32ZET6,带外部总线于是可以用总线挂TFT---------------> W5100,硬件TCP/IP协议 ...… 查看全部问答> |




