1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2011-01-13     weety      first version
9  */
10 
11 #include <rthw.h>
12 #include "at91sam9g45.h"
13 #include "interrupt.h"
14 
15 #define AIC_IRQS    32
16 #define MAX_HANDLERS    (AIC_IRQS + PIN_IRQS)
17 
18 extern rt_atomic_t rt_interrupt_nest;
19 
20 /* exception and interrupt handler table */
21 struct rt_irq_desc irq_desc[MAX_HANDLERS];
22 
23 rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
24 rt_uint32_t rt_thread_switch_interrupt_flag;
25 
26 
27 /* --------------------------------------------------------------------
28  *  Interrupt initialization
29  * -------------------------------------------------------------------- */
30 
31 rt_uint32_t at91_extern_irq;
32 
33 #define is_extern_irq(irq) ((1 << (irq)) & at91_extern_irq)
34 
35 /*
36  * The default interrupt priority levels (0 = lowest, 7 = highest).
37  */
38 static rt_uint32_t at91sam9g45_default_irq_priority[MAX_HANDLERS] = {
39     7,  /* Advanced Interrupt Controller - FIQ    */
40     7,  /* System Controller Interrupt            */
41     1,  /* Parallel I/O Controller A,             */
42     1,  /* Parallel I/O Controller B              */
43     1,  /* Parallel I/O Controller C              */
44     0,  /* Parallel I/O Controller D/E            */
45     5,  /* True Random Number Generator           */
46     5,  /* USART 0                                */
47     5,  /* USART 1                                */
48     0,  /* USART 2                                */
49     2,  /* USART 3                                */
50     6,  /* High Speed Multimedia Card Interface 0 */
51     5,  /* Two-Wire Interface 0                   */
52     5,  /* Two-Wire Interface 1                   */
53     5,  /* Serial Peripheral Interface            */
54     0,  /* Serial Peripheral Interface            */
55     0,  /* Synchronous Serial Controller 0        */
56     0,  /* Synchronous Serial Controller 1        */
57     0,  /* Timer Counter 0,1,2,3,4,5              */
58     0,  /* Pulse Width Modulation Controller      */
59     2,  /* Touch Screen ADC Controller            */
60     3,  /* DMA Controller                         */
61     0,  /* USB Host High Speed                    */
62     5,  /* LCD Controller                         */
63     5,  /* AC97 Controller                        */
64     5,  /* Ethernet MAC                           */
65     0,  /* Image Sensor Interface                 */
66     0,  /* USB Device High Speed                  */
67     0,  /* N/A                                    */
68     0,  /* High Speed Multimedia Card Interface 1 */
69     0,  /* Reserved                               */
70     0,  /* Advanced Interrupt Controller - IRQ    */
71 };
72 
73 /**
74  * @addtogroup AT91SAM9G45
75  */
76 /*@{*/
77 
78 void rt_hw_interrupt_mask(int irq);
79 void rt_hw_interrupt_umask(int irq);
80 
rt_hw_interrupt_handle(rt_uint32_t vector,void * param)81 rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
82 {
83     rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
84     return RT_NULL;
85 }
86 
at91_gpio_irq_handle(rt_uint32_t bank,void * param)87 rt_isr_handler_t at91_gpio_irq_handle(rt_uint32_t bank, void *param)
88 {
89     rt_uint32_t isr, irq_n;
90     AT91PS_PIO pio;
91     void *parameter;
92 
93     switch (bank)
94     {
95     case 0: pio = AT91C_BASE_PIOA; break;
96     case 1: pio = AT91C_BASE_PIOB; break;
97     case 2: pio = AT91C_BASE_PIOC; break;
98     case 3: pio = AT91C_BASE_PIOD; break;
99     case 4: pio = AT91C_BASE_PIOE; break;
100     default: return RT_NULL;
101     }
102     irq_n = AIC_IRQS + 32*bank;
103     isr = readl(pio->PIO_ISR);
104     isr &= readl(pio->PIO_IMR);
105     while (isr)
106     {
107         if (isr & 1)
108         {
109             parameter = irq_desc[irq_n].param;
110             irq_desc[irq_n].handler(irq_n, parameter);
111         }
112         isr >>= 1;
113         irq_n++;
114     }
115 
116     return RT_NULL;
117 }
118 
119 unsigned int SpuriousCount = 0;
DefaultSpuriousHandler(void)120 static void DefaultSpuriousHandler( void )
121 {
122     SpuriousCount++;
123     rt_kprintf("Spurious interrupt %d occured!!!\n", SpuriousCount);
124     return ;
125 }
126 
DefaultFiqHandler(void)127 static void DefaultFiqHandler(void)
128 {
129     rt_kprintf("Unhandled FIQ occured!!!\n");
130     while (1);
131 }
132 
DefaultIrqHandler(void)133 static void DefaultIrqHandler(void)
134 {
135     rt_kprintf("Unhandled IRQ %d occured!!!\n", AT91C_BASE_AIC->AIC_ISR);
136     while (1);
137 }
138 
139 /*
140  * Initialize the AIC interrupt controller.
141  */
at91_aic_init(rt_uint32_t * priority)142 void at91_aic_init(rt_uint32_t *priority)
143 {
144     rt_uint32_t i;
145 
146     /*
147      * The IVR is used by macro get_irqnr_and_base to read and verify.
148      * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
149      */
150     AT91C_BASE_AIC->AIC_SVR[0] = (rt_uint32_t)DefaultFiqHandler;
151     for (i = 1; i < AIC_IRQS; i++) {
152         /* Put irq number in Source Vector Register: */
153         AT91C_BASE_AIC->AIC_SVR[i] = (rt_uint32_t)DefaultIrqHandler; // no-used
154         /* Active Low interrupt, with the specified priority */
155         AT91C_BASE_AIC->AIC_SMR[i] = AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE | priority[i];
156         //AT91C_AIC_SRCTYPE_FALLING
157     }
158 
159     /*
160      * Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS
161      * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU
162      */
163     AT91C_BASE_AIC->AIC_SPU = (rt_uint32_t)DefaultSpuriousHandler;
164 
165     /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */
166     for (i = 0; i < 8; i++)
167         AT91C_BASE_AIC->AIC_EOICR = 0;
168 
169     /* No debugging in AIC: Debug (Protect) Control Register */
170     AT91C_BASE_AIC->AIC_DCR = 0;
171 
172     /* Disable and clear all interrupts initially */
173     AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF;
174     AT91C_BASE_AIC->AIC_ICCR = 0xFFFFFFFF;
175 }
176 
177 
at91_gpio_irq_init()178 static void at91_gpio_irq_init()
179 {
180     int i, idx;
181     char *name[] = {"PIOA", "PIOB", "PIOC", "PIODE"};
182     rt_uint32_t aic_pids[] = { AT91C_ID_PIOA, AT91C_ID_PIOB, AT91C_ID_PIOC, AT91C_ID_PIOD_E };
183 
184     AT91C_BASE_PIOA->PIO_IDR = 0xffffffff;
185     AT91C_BASE_PIOB->PIO_IDR = 0xffffffff;
186     AT91C_BASE_PIOC->PIO_IDR = 0xffffffff;
187     AT91C_BASE_PIOD->PIO_IDR = 0xffffffff;
188     AT91C_BASE_PIOE->PIO_IDR = 0xffffffff;
189 
190     for (i = 0; i < 4; i++)
191     {
192         idx = aic_pids[i];
193         irq_desc[idx].handler = (rt_isr_handler_t)at91_gpio_irq_handle;
194         irq_desc[idx].param = RT_NULL;
195 #ifdef RT_USING_INTERRUPT_INFO
196         rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, name[i]);
197         irq_desc[idx].counter = 0;
198 #endif
199 
200         rt_hw_interrupt_umask(idx);
201     }
202 }
203 
204 
205 /**
206  * This function will initialize hardware interrupt
207  */
rt_hw_interrupt_init(void)208 void rt_hw_interrupt_init(void)
209 {
210     register rt_uint32_t idx;
211     rt_uint32_t *priority = at91sam9g45_default_irq_priority;
212 
213     at91_extern_irq = (1UL << AT91C_ID_IRQ0);
214 
215     /* Initialize the AIC interrupt controller */
216     at91_aic_init(priority);
217 
218     /* init exceptions table */
219     for(idx=0; idx < MAX_HANDLERS; idx++)
220     {
221         irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
222         irq_desc[idx].param = RT_NULL;
223 #ifdef RT_USING_INTERRUPT_INFO
224         rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
225         irq_desc[idx].counter = 0;
226 #endif
227     }
228 
229     at91_gpio_irq_init();
230 
231     /* init interrupt nest, and context in thread sp */
232     rt_interrupt_nest = 0;
233     rt_interrupt_from_thread = 0;
234     rt_interrupt_to_thread = 0;
235     rt_thread_switch_interrupt_flag = 0;
236 }
237 
at91_gpio_irq_mask(int irq)238 static void at91_gpio_irq_mask(int irq)
239 {
240     rt_uint32_t pin, bank;
241     AT91PS_PIO pio;
242 
243     bank = (irq - AIC_IRQS)>>5;
244 
245     switch (bank)
246     {
247     case 0: pio = AT91C_BASE_PIOA; break;
248     case 1: pio = AT91C_BASE_PIOB; break;
249     case 2: pio = AT91C_BASE_PIOC; break;
250     case 3: pio = AT91C_BASE_PIOD; break;
251     case 4: pio = AT91C_BASE_PIOE; break;
252     default: return;
253     }
254     pin = 1 << ((irq - AIC_IRQS) & 31);
255     pio->PIO_IDR = pin;
256 }
257 
258 /**
259  * This function will mask a interrupt.
260  * @param irq   the interrupt number
261  */
rt_hw_interrupt_mask(int irq)262 void rt_hw_interrupt_mask(int irq)
263 {
264     if (irq >= AIC_IRQS)
265     {
266         at91_gpio_irq_mask(irq);
267     }
268     else
269     {
270         /* Disable interrupt on AIC */
271         AT91C_BASE_AIC->AIC_IDCR = 1 << irq;
272     }
273 }
274 
at91_gpio_irq_umask(int irq)275 static void at91_gpio_irq_umask(int irq)
276 {
277     rt_uint32_t pin, bank;
278     AT91PS_PIO pio;
279 
280     bank = (irq - AIC_IRQS)>>5;
281 
282     switch (bank)
283     {
284     case 0: pio = AT91C_BASE_PIOA; break;
285     case 1: pio = AT91C_BASE_PIOB; break;
286     case 2: pio = AT91C_BASE_PIOC; break;
287     case 3: pio = AT91C_BASE_PIOD; break;
288     case 4: pio = AT91C_BASE_PIOE; break;
289     default: return;
290     }
291     pin = 1 << ((irq - AIC_IRQS) & 31);
292     pio->PIO_IER = pin;
293 }
294 
295 /**
296  * This function will un-mask a interrupt.
297  * @param vector the interrupt number
298  */
rt_hw_interrupt_umask(int irq)299 void rt_hw_interrupt_umask(int irq)
300 {
301     if (irq >= AIC_IRQS)
302     {
303         at91_gpio_irq_umask(irq);
304     }
305     else
306     {
307         /* Enable interrupt on AIC */
308         AT91C_BASE_AIC->AIC_IECR = 1 << irq;
309     }
310 }
311 
312 /**
313  * This function will install a interrupt service routine to a interrupt.
314  * @param vector the interrupt number
315  * @param handler the interrupt service routine to be installed
316  * @param param the interrupt service function parameter
317  * @param name the interrupt name
318  * @return old handler
319  */
rt_hw_interrupt_install(int vector,rt_isr_handler_t handler,void * param,const char * name)320 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
321                                     void *param, const char *name)
322 {
323     rt_isr_handler_t old_handler = RT_NULL;
324 
325     if (vector < MAX_HANDLERS)
326     {
327         old_handler = irq_desc[vector].handler;
328         if (handler != RT_NULL)
329         {
330             irq_desc[vector].handler = (rt_isr_handler_t)handler;
331             irq_desc[vector].param = param;
332 #ifdef RT_USING_INTERRUPT_INFO
333             rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
334             irq_desc[vector].counter = 0;
335 #endif
336         }
337     }
338 
339     return old_handler;
340 }
341 
342 /*@}*/
343 
344 /*
345 static int at91_aic_set_type(unsigned irq, unsigned type)
346 {
347     unsigned int smr, srctype;
348 
349     switch (type) {
350     case AT91C_AIC_SRCTYPE_EXT_HIGH_LEVEL:
351         srctype = AT91C_AIC_SRCTYPE_HIGH;
352         break;
353     case AT91C_AIC_SRCTYPE_EXT_POSITIVE_EDGE:
354         srctype = AT91C_AIC_SRCTYPE_RISING;
355         break;
356     case AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE:
357         // only supported on external interrupts
358         if ((irq == AT91C_ID_FIQ) || is_extern_irq(irq))
359             srctype = AT91C_AIC_SRCTYPE_LOW;
360         else
361             return -1;
362         break;
363     case AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED:
364         // only supported on external interrupts
365         if ((irq == AT91C_ID_FIQ) || is_extern_irq(irq))
366             srctype = AT91C_AIC_SRCTYPE_FALLING;
367         else
368             return -1;
369         break;
370     default:
371         return -1;
372     }
373 
374     smr = readl(AT91C_AIC_SMR(irq)) & ~AT91C_AIC_SRCTYPE;
375     AT91C_BASE_AIC->AIC_SMR[irq] = smr | srctype;
376     return 0;
377 }
378 */
rt_hw_interrupt_get_active(rt_uint32_t fiq_irq)379 rt_uint32_t rt_hw_interrupt_get_active(rt_uint32_t fiq_irq)
380 {
381 
382     //volatile rt_uint32_t irqstat;
383     rt_uint32_t id;
384     if (fiq_irq == INT_FIQ)
385         return 0;
386 
387     //IRQ
388     /* AIC need this dummy read */
389     readl(AT91C_AIC_IVR);
390     /* clear pending register */
391     id = readl(AT91C_AIC_ISR);
392 
393     return id;
394 }
395 
rt_hw_interrupt_ack(rt_uint32_t fiq_irq,rt_uint32_t id)396 void rt_hw_interrupt_ack(rt_uint32_t fiq_irq, rt_uint32_t id)
397 {
398     /* new FIQ generation */
399     if (fiq_irq == INT_FIQ)
400         return;
401 
402     /* new IRQ generation */
403     // EIOCR must be write any value after interrupt,
404     // or else can't response next interrupt
405     AT91C_BASE_AIC->AIC_EOICR = 0x0;
406 }
407 
rt_interrupt_dispatch(rt_uint32_t fiq_irq)408 void rt_interrupt_dispatch(rt_uint32_t fiq_irq)
409 {
410     rt_isr_handler_t isr_func;
411     rt_uint32_t irq;
412     void *param;
413 
414     /* get irq number */
415     irq = rt_hw_interrupt_get_active(fiq_irq);
416 
417     /* get interrupt service routine */
418     isr_func = irq_desc[irq].handler;
419     param = irq_desc[irq].param;
420 
421     /* turn to interrupt service routine */
422     isr_func(irq, param);
423 
424     rt_hw_interrupt_ack(fiq_irq, irq);
425 #ifdef RT_USING_INTERRUPT_INFO
426     irq_desc[irq].counter ++;
427 #endif
428 }
429 
430 
431 #ifdef RT_USING_FINSH
432 #ifdef RT_USING_INTERRUPT_INFO
list_irq(void)433 void list_irq(void)
434 {
435     int irq;
436 
437     rt_kprintf("number\tcount\tname\n");
438     for (irq = 0; irq < MAX_HANDLERS; irq++)
439     {
440         if (rt_strncmp(irq_desc[irq].name, "default", sizeof("default")))
441         {
442             rt_kprintf("%02ld: %10ld  %s\n", irq, irq_desc[irq].counter, irq_desc[irq].name);
443         }
444     }
445 }
446 
447 #include <finsh.h>
448 
449 #ifdef FINSH_USING_MSH
cmd_list_irq(int argc,char ** argv)450 int cmd_list_irq(int argc, char** argv)
451 {
452     list_irq();
453     return 0;
454 }
455 MSH_CMD_EXPORT_ALIAS(cmd_list_irq, list_irq, list system irq);
456 #endif
457 #endif
458 #endif
459 
460 
461