Marvell-linux研究—irq.c源代码分析

来源:互联网 发布:总裁助理条件知乎 编辑:程序博客网 时间:2024/05/27 20:21

Marvell-linux研究—irq.c源代码分析

 

转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd

作者联系方式:李先静 <xianjimli at hotmail dot com>

更新时间:2007-7-13

 

轮询、中断和DMA是外设与CPU通信的三种基本方式。在PXA3xx中,中断分为基本中断源(Primary Sources of interrupts)和二级中断源(Secondary Sources of interrupts)。多个二级中断源共享一个基本中断源(Primary Sources of interrupts),比如32DMA通道共享一个基本中断源,发生中断时,光知道是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             /* Don't mess with enabled GPIOs using preconfigured edges or
139                GPIOs set to alternate function during probe */
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         /* printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio); */
151
152 #ifndef CONFIG_CPU_MONAHANS
153         pxa_gpio_mode(gpio | GPIO_IN);
154 #else
155         G CDR(gpio) &= (1 << (gpio & 0x1f)); /* Set Direction Input */
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中断的类型,也就是触发中断的条件,上升沿触发、下降沿触发、两者同时触发、或者禁止触发,这些设置通过写GRERGFER两个寄存器生效,同时会保存到GPIO_IRQ_rising_edgeGPIO_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呢?原来GPIO0GPIO1是独自占用基本中断源(Primary Sources of interrupts)的,而其它GPIO则共享10号中断。所以把GPIO0GPIO1称为low_gpio,而把其它GPIO称为muxed_gpio

 

Irqchip中的ack函数,用来确认中断被处理了,通常用来清除二级中断的状态,这里清除GEDR中相应的位。

 

197 static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
198                                    struct pt_regs *regs)
199 {
200         unsigned int mask;
201         int loop;
202
203         do {
204                 loop = 0;
205
206                 mask = GEDR0 & ~3;
207                 if (mask) {
208                         GEDR0 = mask;
209                         irq = IRQ_GPIO(2);
210                         desc = irq_desc + irq;
211                         mask >>= 2;
212                         do {
213                                 if (mask & 1)
214                                         desc_handle_irq(irq, desc, regs);
215                                 irq++;
216                                 desc++;
217                                 mask >>= 1;
218                         } while (mask);
219                         loop = 1;
220                 }
221
222                 mask = GEDR1;
223                 if (mask) {
224                         GEDR1 = mask;
225                         irq = IRQ_GPIO(32);
226                         desc = irq_desc + irq;
227                         do {
228                                 if (mask & 1)
229                                         desc_handle_irq(irq, desc, regs);
230                                 irq++;
231                                 desc++;
232                                 mask >>= 1;
233                         } while (mask);
234                         loop = 1;
235                 }
236
237                 mask = GEDR2;
238                 if (mask) {
239                         GEDR2 = mask;
240                         irq = IRQ_GPIO(64);
241                         desc = irq_desc + irq;
242                         do {
243                                 if (mask & 1)
244                                         desc_handle_irq(irq, desc, regs);
245                                 irq++;
246                                 desc++;
247                                 mask >>= 1;
248                         } while (mask);
249                         loop = 1;
250                 }
251
252 #if PXA_LAST_GPIO >= 96
253                 mask = GEDR3;
254                 if (mask) {
255                         GEDR3 = mask;
256                         irq = IRQ_GPIO(96);
257                         desc = irq_desc + irq;
258                         do {
259                                 if (mask & 1)
260                                         desc_handle_irq(irq, desc, regs);
261                                 irq++;
262                                 desc++;
263                                 mask >>= 1;
264                         } while (mask);
265                         loop = 1;
266                 }
267 #endif
268         } while (loop);
269 }

 

这函数用来调用所有GPIO(>=2)的中断处理函数,总共有4GEDR寄存器,它循环检查所有状态,直到处理全部GPIO为止。外层循环看似有点奇怪,其实它的目的是保证,把最近发生的中断也处理掉,即使这个中断发生在当前函数执行过程之中。

 

279 static void pxa_mask_muxed_gpio(unsigned int irq)
280 {
281         int gpio = irq - IRQ_GPIO(2) + 2;
282         
283         u32 tem=0;
284         if ( GRER(gpio) & GPIO_bit(gpio)) {
285                 __set_bit (gpio, GPIO_IRQ_rising_edge);
286         } else{
287                 __clear_bit (gpio, GPIO_IRQ_rising_edge);
288         }
289         
290         if (GFER(gpio) & GPIO_bit(gpio)) {
291                 __set_bit (gpio, GPIO_IRQ_falling_edge);
292         } else{
293                 __clear_bit (gpio, GPIO_IRQ_falling_edge);
294         }
295         
296         __clear_bit(gpio, GPIO_IRQ_mask);
297         GRER(gpio) &= ~GPIO_bit(gpio);
298         GFER(gpio) &= ~GPIO_bit(gpio);
299         
300         tem = GRER(gpio);
301         tem = GFER(gpio);
302 }
303
304 static void pxa_unmask_muxed_gpio(unsigned int irq)
305 {
306         int gpio = irq - IRQ_GPIO(2) + 2;
307         int idx = gpio >> 5;
308         u32 tem=0;
309         __set_bit(gpio, GPIO_IRQ_mask);
310         GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx];
311         GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx];
312         tem = GRER(gpio);
313 }
314
315 static struct irqchip pxa_muxed_gpio_chip = {
316         .ack            = pxa_ack_muxed_gpio,
317         .mask           = pxa_mask_muxed_gpio,
318         .unmask         = pxa_unmask_muxed_gpio,
319         .set_type       = pxa_gpio_irq_type,
320 };

 

pxa_mask_muxed_gpio保存GPIO当前中断设置,然后屏蔽相应的中断。pxa_unmask_muxed_gpio允许GPIO中断,至于中断方式,还要由GPIO_IRQ_rising_edgeGPIO_IRQ_falling_edge中的值决定。

 

323 void __init pxa_init_irq(void)
324 {
325         int irq;
326
327 #ifdef CONFIG_CPU_MONAHANS
328         __asm__ __volatile__ ("/n/
329                         mov     r0, #0 /n/
330                         mcr     p6, 0, r0, c1, c0, 0    @ ICMR=0 /n/
331                         mcr     p6, 0, r0, c2, c0, 0    @ ICLR=0"
332                         :
333                         :
334                         : "r0");
335 #else
336         /* disable all IRQs */
337         ICMR = 0;
338         
339         /* all IRQs are IRQ, not FIQ */
340         ICLR = 0;
341 #endif
342         /* clear all GPIO edge detects */
343         GFER0 = 0;
344         GFER1 = 0;
345         GFER2 = 0;
346         GRER0 = 0;
347         GRER1 = 0;
348         GRER2 = 0;
349         GEDR0 = GEDR0;
350         GEDR1 = GEDR1;
351         GEDR2 = GEDR2;
352
353 #if defined(CONFIG_PXA27x) || defined(CONFIG_CPU_MONAHANS)
354 #ifdef CONFIG_CPU_MONAHANS
355         __asm__ __volatile__ ("/n/
356                         mov     r0, #0 /n/
357                         mcr     p6, 0, r0, c7, c0, 0    @ ICMR2=0 /n/
358                         mcr     p6, 0, r0, c8, c0, 0    @ ICLR2=0"
359                         :
360                         :
361                         : "r0");
362 #else
363         /* And similarly for the extra regs on the PXA27x */
364         ICMR2 = 0;
365         ICLR2 = 0;
366 #endif  
367
368         GFER3 = 0;
369         GRER3 = 0;
370         GEDR3 = GEDR3;
371 #endif /*#if defined(CONFIG_PXA27x) || defined(CONFIG_CPU_MONAHANS) */
372
373         /* only unmasked interrupts kick us out of idle */
374         ICCR = 1;
375
376         /* GPIO 0 and 1 must have their mask bit always set */
377         GPIO_IRQ_mask[0] = 3;
378
379         for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) {
380                 set_irq_chip(irq, &pxa_internal_chip_low);
381                 set_irq_handler(irq, do_level_IRQ);
382                 set_irq_flags(irq, IRQF_VALID);
383         }
384
385 #if PXA_INTERNAL_IRQS > 32
386         for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) {
387                 set_irq_chip(irq, &pxa_internal_chip_high);
388                 set_irq_handler(irq, do_level_IRQ);
389                 set_irq_flags(irq, IRQF_VALID);
390         }
391 #endif
392
393         for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
394                 set_irq_chip(irq, &pxa_low_gpio_chip);
395                 set_irq_handler(irq, do_edge_IRQ);
396                 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
397         }
398
399         for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) {
400                 set_irq_chip(irq, &pxa_muxed_gpio_chip);
401                 set_irq_handler(irq, do_edge_IRQ);
402                 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
403         }
404
405         /* Install handler for GPIO>=2 edge detect interrupts */
406         set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low);
407         set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler);
408 }

 

323-341 它把ICMR清零,即屏蔽所有低位中断。把ICLR清零,即把所有低位中断设置为IRQ353-366以同样的方式去设置高位中断,不知道为什么不和低位设置放在一起,这里好像与时序也没有什么关系啊。

 

343-351 清除前96GPIO的中断触发条件。

 

368-370 清除后32GPIO的中断触发条件。

 

GEDR的操作,这里的代码可能有些让人不解。其实很简单,原因是对GEDR的写操作有点特别,写1是把它清零,写0对它没有影响,把GEDR的值读出来,再写回去,这样原先为1的被清零,为0的保持不变。

 

374 ICCR中的DIM1,在低功耗模式下,它只允许未屏蔽的中断唤醒CPU

 

377 前面一行的注释说了等于没说,为什么要把GPIO0GPIO1屏蔽掉呢?原因很简单,它们使用基本中断源,如果不屏蔽,基本中断源和二级中断源同时发生,会造成不必要的混乱。

 

379-408 设置中断处理函数。

 

~~end~~

原创粉丝点击