轮询、中断和DMA是外设与CPU通信的三种基本方式。在PXA3xx中,中断分为基本中断源(Primary Sources of interrupts)和二级中断源(Secondary Sources of interrupts)。多个二级中断源共享一个基本中断源(Primary Sources of interrupts),比如32路DMA通道共享一个基本中断源,发生中断时,光知道是DMA中断还不够,需要查询DMA相关寄存器,以确定具体的中断源。
通过编程可以控制基本中断源(Primary Sources of interrupts)的优先级和类型(IRQ/FIQ),二级中断源主要是软件上的概念,CPU不需要关心这些,甚至不知道所谓二级中断源的存在,所以不能设置二级中断源的优先级和类型(IRQ/FIQ)。
下面我们来看mach-pxa/irq.c中的代码:
35 static void pxa_mask_low_irq(unsigned int irq)
36 {
37 #ifdef CONFIG_CPU_MONAHANS
38 unsigned int temp = ~(1 << (irq + PXA_IRQ_SKIP));
39 __asm__ __volatile__ ("\n\
40 mrc p6, 0, r1, c1, c0, 0 @ Read out ICMR\n\
41 and r1, r1, %0 \n\
42 mcr p6, 0, r1, c1, c0, 0 @ Write back"
43 :
44 :"r"(temp)
45 :"r1");
46 #else
47 ICMR &= ~(1 << (irq + PXA_IRQ_SKIP));
48 #endif
49 }
50
51 static void pxa_unmask_low_irq(unsigned int irq)
52 {
53 #ifdef CONFIG_CPU_MONAHANS
54 unsigned int temp = (1 << (irq + PXA_IRQ_SKIP));
55 __asm__ __volatile__ ("\n\
56 mrc p6, 0, r1, c1, c0, 0 @ Read out ICMR\n\
57 orr r1, r1, %0 \n\
58 mcr p6, 0, r1, c1, c0, 0 @ Write back"
59 :
60 :"r"(temp)
61 :"r1");
62 #else
63 ICMR |= (1 << (irq + PXA_IRQ_SKIP));
64 #endif
65 }
66
67 static struct irqchip pxa_internal_chip_low = {
68 .ack = pxa_mask_low_irq,
69 .mask = pxa_mask_low_irq,
70 .unmask = pxa_unmask_low_irq,
71 };
79 static void pxa_mask_high_irq(unsigned int irq)
80 {
81 #ifdef CONFIG_CPU_MONAHANS
82 unsigned int temp = ~(1 << (irq - 32 + PXA_IRQ_SKIP));
83 __asm__ __volatile__ ("\n\
84 mrc p6, 0, r1, c7, c0, 0 @ Read out ICMR2\n\
85 and r1, r1, %0 \n\
86 mcr p6, 0, r1, c7, c0, 0 @ Write back"
87 :
88 :"r"(temp)
89 :"r1");
90 #else
91 ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP));
92 #endif
93 }
94
95 static void pxa_unmask_high_irq(unsigned int irq)
96 {
97 #ifdef CONFIG_CPU_MONAHANS
98 unsigned int temp = (1 << (irq - 32 + PXA_IRQ_SKIP));
99 __asm__ __volatile__ ("\n\
100 mrc p6, 0, r1, c7, c0, 0 @ Read out ICMR2\n\
101 orr r1, r1, %0 \n\
102 mcr p6, 0, r1, c7, c0, 0 @ Write back"
103 :
104 :"r"(temp)
105 :"r1");
106
107 #else
108 ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP));
109 #endif
110 }
111
112 static struct irqchip pxa_internal_chip_high = {
113 .ack = pxa_mask_high_irq,
114 .mask = pxa_mask_high_irq,
115 .unmask = pxa_unmask_high_irq,
116 };
117
118 #endif
ICMR是中断屏蔽寄存器,它的位域决定哪些中断被禁止,哪些中断被启用。在PXA3xx中,中断屏蔽寄存器由两个32位的寄存器组成,最多允许64个基本中断源(实际上没有那么多,有几个位保留给将来用)。这里low是指低32位的中断,high是指高32位的中断,它们与中断优先级无关。ICMR控制低位中断,而ICMR2控制高位中断。
操作寄存器的方式有两种,一种是通过协处理器指令读写,读取用mrc指令,写入用mcr指令。操作中断相关寄存器使用6号协处理,中断寄存器与协处理寄存器对应关系可以参考表12-1。上面的汇编代码就是通过协处理器操作中断寄存器的。
另外一种方式是通过内存映射的I/O寄存器,它的形式和读取普通内存相同,使用方法简单直观,但与协处理器方式相比,它的速度稍慢。上面的else宏中的语句就属于这种方式。
130 static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
131 {
132 int gpio, idx;
133
134 gpio = IRQ_TO_GPIO(irq);
135 idx = gpio >> 5;
136
137 if (type == IRQT_PROBE) {
138
140 if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
141 GPIO_bit(gpio))
142 return 0;
143 #ifndef CONFIG_CPU_MONAHANS
144 if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
145 return 0;
146 #endif
147 type = __IRQT_RISEDGE | __IRQT_FALEDGE;
148 }
149
150
151
152 #ifndef CONFIG_CPU_MONAHANS
153 pxa_gpio_mode(gpio | GPIO_IN);
154 #else
155 G CDR(gpio) &= (1 << (gpio & 0x1f));
156 #endif
157
158 if (type & __IRQT_RISEDGE) {
159 __set_bit (gpio, GPIO_IRQ_rising_edge);
160 }
161 else {
162 __clear_bit (gpio, GPIO_IRQ_rising_edge);
163 }
164
165 if (type & __IRQT_FALEDGE) {
166 __set_bit (gpio, GPIO_IRQ_falling_edge);
167 }
168 else {
169 __clear_bit (gpio, GPIO_IRQ_falling_edge);
170 }
171
172 GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx];
173 GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx];
174 return 0;
175 }
这个函数用来设置GPIO中断的类型,也就是触发中断的条件,上升沿触发、下降沿触发、两者同时触发、或者禁止触发,这些设置通过写GRER和GFER两个寄存器生效,同时会保存到GPIO_IRQ_rising_edge和GPIO_IRQ_falling_edge两个变量里。
181 static void pxa_ack_low_gpio(unsigned int irq)
182 {
183 GEDR0 = (1 << (irq - IRQ_GPIO0));
184 }
185
186 static struct irqchip pxa_low_gpio_chip = {
187 .ack = pxa_ack_low_gpio,
188 .mask = pxa_mask_low_irq,
189 .unmask = pxa_unmask_low_irq,
190 .set_type = pxa_gpio_irq_type,
191 };
GPIO不都一样吗?为什么还来个low_gpio呢?原来GPIO0和GPIO1是独自占用基本中断源(Primary Sources of interrupts)的,而其它GPIO则共享10号中断。所以把GPIO0和GPIO1称为low_gpio,而把其它GPIO称为muxed_gpio。
阅读(801) | 评论(0) | 转发(0) |