b018cd620c8255cede2526cb68b4218dcce694e3
[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  * indipendently.
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 unic system irq handler is implemented here.
22  * This module also contains an interface to manage every source
23  * indipendently. 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  * Returns the state of the Periodic Interval Timer
38  * interrupt.
39  */
40 static bool pit_enable(void)
41 {
42         return PIT_MR & BV(PITIEN);
43 }
44
45 /**
46  * Returns the state of the Periodic Interval Timer
47  * interrupt.
48  * \return true is PIT has triggered and interrupt, false otherwise
49  */
50 static bool pit_trigger(void)
51 {
52         return PIT_SR & BV(PITS);
53 }
54
55 /**
56  * Enable/disable the Periodic Interrupt Timer
57  * interrupt.
58  */
59 static void pit_setEnable(bool enable)
60 {
61         if (enable)
62                 PIT_MR |= BV(PITIEN);
63         else
64                 PIT_MR &= ~BV(PITIEN);
65 }
66
67 /**
68  * Table containing all system irqs.
69  */
70 static SysIrq sysirq_tab[] =
71 {
72         /* PIT, Periodic Interval Timer (System timer)*/
73         {
74                 .enable = pit_enable,
75                 .trigger = pit_trigger,
76                 .setEnable = pit_setEnable,
77                 .handler = NULL,
78         },
79         /* TODO: add other system sources here */
80 };
81
82 STATIC_ASSERT(countof(sysirq_tab) == SYSIRQ_CNT);
83
84
85 /**
86  * System IRQ handler.
87  * This is the entry point for all system IRQs in AT91.
88  * This function checks for interrupt enable state of
89  * various sources (system timer, etc..) and calls
90  * the corresponding handler.
91  */
92 static void sysirq_handler(void)
93 {
94         #warning TODO add IRQ prologue/epilogue
95         for (int i = 0; i < countof(sysirq_tab); i++)
96         {
97                 if (sysirq_tab[i].enable()
98                  && sysirq_tab[i].trigger()
99                  && sysirq_tab[i].handler)
100                         sysirq_tab[i].handler();
101         }
102 }
103
104 #define SYSIRQ_PRIORITY 0 ///< default priority for system irqs.
105
106 /**
107  * Init system irq handling.
108  * \note all system interrupts are disabled.
109  */
110 void sysirq_init(void)
111 {
112         cpuflags_t flags;
113         IRQ_SAVE_DISABLE(flags);
114
115         /* Disable all system interrupts */
116         for (int i = 0; i < countof(sysirq_tab); i++)
117                 sysirq_tab[i].setEnable(false);
118
119         /* Set the vector. */
120         AIC_SVR(SYSC_ID) = sysirq_handler;
121         /* Initialize to edge triggered with defined priority. */
122         AIC_SMR(SYSC_ID) = BV(AIC_SRCTYPE_INT_EDGE_TRIGGERED) | SYSIRQ_PRIORITY;
123         /* Clear interrupt */
124         AIC_ICCR = BV(SYSC_ID);
125         IRQ_RESTORE(flags);
126 }
127
128
129 /**
130  * Helper function used to set handler for system irq \a irq.
131  */
132 void sysirq_setHandler(sysirq_t irq, sysirq_handler_t handler)
133 {
134         ASSERT(irq >= 0);
135         ASSERT(irq < SYSIRQ_CNT);
136         sysirq_tab[irq].handler = handler;
137 }
138
139 /**
140  * Helper function used to enable/disable system irq \a irq.
141  */
142 void sysirq_setEnable(sysirq_t irq, bool enable)
143 {
144         ASSERT(irq >= 0);
145         ASSERT(irq < SYSIRQ_CNT);
146         sysirq_tab[irq].setEnable(enable);
147 }
148
149 /**
150  * Helper function used to get system irq \a irq state.
151  */
152 bool sysirq_enable(sysirq_t irq)
153 {
154         ASSERT(irq >= 0);
155         ASSERT(irq < SYSIRQ_CNT);
156         return sysirq_tab[irq].enable();
157 }