Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1371585
  • 博文数量: 198
  • 博客积分: 1629
  • 博客等级: 上尉
  • 技术积分: 2743
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-01 15:41
文章分类
文章存档

2023年(6)

2022年(20)

2021年(8)

2020年(3)

2018年(17)

2017年(3)

2016年(3)

2015年(9)

2014年(13)

2013年(17)

2012年(77)

2011年(22)

分类: LINUX

2012-05-16 17:21:01

轮询、中断和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) |
给主人留下些什么吧!~~