fc9f687fc188ddd002de35d75d4f39bf1913bf21
[bertos.git] / drv / at91 / sysirq.c
1 /**
2  * \file
3  * <!--
4  * Copyright 2007 Develer S.r.l. (http://www.develer.com/)
5  * This file is part of DevLib - See README.devlib for information.
6  * -->
7  *
8  * \version $Id$
9  *
10  * \author Francesco Sacchi <batt@develer.com>
11  *
12  * \brief System IRQ handler for Atmel AT91 ARM7 processors.
13  *
14  * In Atmel AT91 ARM7TDMI processors, there are various
15  * peripheral interrupt sources.
16  * In general, every source has its own interrupt vector, so it
17  * is possible to assign a specific handler for each interrupt
18  * independently.
19  * However, there are a few sources called "system sources" that
20  * share a common IRQ line and vector, called "system IRQ".
21  * So a unique system IRQ handler is implemented here.
22  * This module also contains an interface to manage every source
23  * independently. It is possible to assign to every system IRQ
24  * a specific IRQ handler.
25  *
26  * \see sysirq_setHandler
27  * \see sysirq_setEnable
28  */
29
30 #include "sysirq.h"
31 #include "at91.h"
32 #include <cfg/cpu.h>
33
34 #warning Very untested!
35
36 /**
37  * Enable/disable the Periodic Interrupt Timer
38  * interrupt.
39  */
40 INLINE static void pit_setEnable(bool enable)
41 {
42         if (enable)
43                 PIT_MR |= BV(PITIEN);
44         else
45                 PIT_MR &= ~BV(PITIEN);
46 }
47
48 /**
49  * Table containing all system irqs.
50  */
51 static SysIrq sysirq_tab[] =
52 {
53         /* PIT, Periodic Interval Timer (System timer)*/
54         {
55                 .enabled = false,
56                 .setEnable = pit_setEnable,
57                 .handler = NULL,
58         },
59         /* TODO: add other system sources here */
60 };
61
62 STATIC_ASSERT(countof(sysirq_tab) == SYSIRQ_CNT);
63
64
65 /**
66  * System IRQ dispatcher.
67  * This is the entry point for all system IRQs in AT91.
68  * This function checks for interrupt enable state of
69  * various sources (system timer, etc..) and calls
70  * the corresponding handler.
71  */
72 static void sysirq_dispatcher(void)
73 {
74         #warning TODO add IRQ prologue/epilogue
75         for (int i = 0; i < countof(sysirq_tab); i++)
76         {
77                 if (sysirq_tab[i].enabled
78                  && sysirq_tab[i].handler)
79                         sysirq_tab[i].handler();
80         }
81 }
82
83 #define SYSIRQ_PRIORITY 0 ///< default priority for system irqs.
84
85
86 MOD_DEFINE(sysirq);
87
88 /**
89  * Init system IRQ handling.
90  * \note all system interrupts are disabled.
91  */
92 void sysirq_init(void)
93 {
94         cpuflags_t flags;
95         IRQ_SAVE_DISABLE(flags);
96
97         /* Disable all system interrupts */
98         for (int i = 0; i < countof(sysirq_tab); i++)
99                 sysirq_tab[i].setEnable(false);
100
101         /* Set the vector. */
102         AIC_SVR(SYSC_ID) = sysirq_handler;
103         /* Initialize to edge triggered with defined priority. */
104         AIC_SMR(SYSC_ID) = BV(AIC_SRCTYPE_INT_EDGE_TRIGGERED) | SYSIRQ_PRIORITY;
105         /* Clear interrupt */
106         AIC_ICCR = BV(SYSC_ID);
107
108         IRQ_RESTORE(flags);
109         MOD_INIT(sysirq);
110 }
111
112
113 /**
114  * Helper function used to set handler for system IRQ \a irq.
115  */
116 void sysirq_setHandler(sysirq_t irq, sysirq_handler_t handler)
117 {
118         ASSERT(irq >= 0);
119         ASSERT(irq < SYSIRQ_CNT);
120         sysirq_tab[irq].handler = handler;
121 }
122
123 /**
124  * Helper function used to enable/disable system IRQ \a irq.
125  */
126 void sysirq_setEnable(sysirq_t irq, bool enable)
127 {
128         ASSERT(irq >= 0);
129         ASSERT(irq < SYSIRQ_CNT);
130
131         sysirq_tab[irq].setEnable(enable);
132         sysirq_enabled = enable;
133 }
134
135 /**
136  * Helper function used to get system IRQ \a irq state.
137  */
138 bool sysirq_enabled(sysirq_t irq)
139 {
140         ASSERT(irq >= 0);
141         ASSERT(irq < SYSIRQ_CNT);
142         return sysirq_tab[irq].enabled;
143 }