zoukankan      html  css  js  c++  java
  • Marvelllinux研究—irq.c源代码分析

    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~~

  • 相关阅读:
    Ubuntu16.04 + CUDA 8.0 (GTX 1050ti)
    关于MapD的集群建立
    2-7 单位和坐标系
    2-6 光线投射
    2-5 事件系统(Event System)
    2-4 Rect Transform(矩形)组件的属性
    2-3 RectangleTransform矩形组件
    2-2 Graphic Raycasrer组件(光线投射)
    2-1 Ui元素-画布
    1-5 事件方法的执行顺序
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167706.html
Copyright © 2011-2022 走看看