1 /**
2  * \file
3  *
4  * \brief INTC software driver for AVR UC3 devices.
5  *
6  * Copyright (c) 2009-2018 Microchip Technology Inc. and its subsidiaries.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Subject to your compliance with these terms, you may use Microchip
13  * software and any derivatives exclusively with Microchip products.
14  * It is your responsibility to comply with third party license terms applicable
15  * to your use of third party software (including open source software) that
16  * may accompany Microchip software.
17  *
18  * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
19  * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
20  * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
21  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
22  * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
23  * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
24  * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
25  * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
26  * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
27  * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
28  * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
29  *
30  * \asf_license_stop
31  *
32  */
33 /*
34  * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
35  */
36 
37 #include <avr32/io.h>
38 #include "compiler.h"
39 #include "preprocessor.h"
40 #include "intc.h"
41 
42 /**
43  * \internal
44  * \brief Import the _evba symbol from exception.S
45  */
46 extern void _evba;
47 
48 /**
49  * \internal
50  * \brief Import the symbols _int0, _int1, _int2, _int3 defined in exception.S
51  */
52 extern void _int0, _int1, _int2, _int3;
53 
54 /**
55  * \internal
56  * \brief Values to store in the interrupt priority registers for the various
57  *  interrupt priority levels.
58  */
59 #define IPR_INT0   ((AVR32_INTC_INT0 << AVR32_INTC_IPR_INTLEVEL_OFFSET) \
60 			| ((int)&_int0 - (int)&_evba))
61 #define IPR_INT1   ((AVR32_INTC_INT1 << AVR32_INTC_IPR_INTLEVEL_OFFSET) \
62 			| ((int)&_int1 - (int)&_evba))
63 #define IPR_INT2   ((AVR32_INTC_INT2 << AVR32_INTC_IPR_INTLEVEL_OFFSET) \
64 			| ((int)&_int2 - (int)&_evba))
65 #define IPR_INT3   ((AVR32_INTC_INT3 << AVR32_INTC_IPR_INTLEVEL_OFFSET) \
66 			| ((int)&_int3 - (int)&_evba))
67 
68 /**
69  * \internal
70  * \brief Table of interrupt line handlers per interrupt group in order to
71  * optimize RAM space. Each line handler table contains a set of pointers to
72  * interrupt handlers.
73  */
74 #if (defined __GNUC__)
75 #  define DECL_INT_LINE_HANDLER_TABLE(GRP, unused) \
76 static volatile __int_handler \
77 	_int_line_handler_table_##GRP[Max(AVR32_INTC_NUM_IRQS_PER_GRP##GRP, 1)];
78 #elif (defined __ICCAVR32__)
79 #  define DECL_INT_LINE_HANDLER_TABLE(GRP, unused) \
80 static volatile __no_init __int_handler \
81 	_int_line_handler_table_##GRP[Max(AVR32_INTC_NUM_IRQS_PER_GRP##GRP, 1)];
82 #endif
83 MREPEAT(AVR32_INTC_NUM_INT_GRPS, DECL_INT_LINE_HANDLER_TABLE, ~);
84 #undef DECL_INT_LINE_HANDLER_TABLE
85 
86 /**
87  * \internal
88  * \brief Table containing for each interrupt group the number of interrupt
89  *  request lines and a pointer to the table of interrupt line handlers.
90  */
91 static const struct
92 {
93 	unsigned int           num_irqs;
94 	volatile __int_handler *_int_line_handler_table;
95 } _int_handler_table[AVR32_INTC_NUM_INT_GRPS] =
96 {
97 #define INSERT_INT_LINE_HANDLER_TABLE(GRP, unused) \
98 	{AVR32_INTC_NUM_IRQS_PER_GRP##GRP, _int_line_handler_table_##GRP},
99 	MREPEAT(AVR32_INTC_NUM_INT_GRPS, INSERT_INT_LINE_HANDLER_TABLE, ~)
100 #undef INSERT_INT_LINE_HANDLER_TABLE
101 };
102 
103 
104 /**
105  * \internal
106  * \brief Default interrupt handler.
107  */
108 #if (defined __GNUC__)
109 __attribute__((__interrupt__))
110 #elif (defined __ICCAVR32__)
111 __interrupt
112 #endif
_unhandled_interrupt(void)113 static void _unhandled_interrupt(void)
114 {
115 	// Catch unregistered interrupts.
116 	while (true);
117 }
118 
119 
120 /**
121  * \brief Gets the interrupt handler of the current event at the \a int_level
122  *        interrupt priority level (called from exception.S).
123  *
124  * \param int_level Interrupt priority level to handle.
125  *
126  * \return Interrupt handler to execute.
127  */
128 __int_handler _get_interrupt_handler(uint32_t int_level);
_get_interrupt_handler(uint32_t int_level)129 __int_handler _get_interrupt_handler(uint32_t int_level)
130 {
131 	/* ICR3 is mapped first, ICR0 last.
132 	Code in exception.S puts int_level in R12 which is used by the compiler
133 	to pass a single argument to a function. */
134 	uint32_t int_grp = AVR32_INTC.icr[AVR32_INTC_INT3 - int_level];
135 	uint32_t int_req = AVR32_INTC.irr[int_grp];
136 
137 	/* As an interrupt may disappear while it is being fetched by the CPU
138 	(spurious interrupt caused by a delayed response from an MCU peripheral
139 	to an interrupt flag clear or interrupt disable instruction), check if
140 	there are remaining interrupt lines to process.
141 	If a spurious interrupt occurs, the status register (SR) contains an
142 	execution mode and interrupt level masks corresponding to a level 0
143 	interrupt, whatever the interrupt priority level causing the spurious
144 	event. This behavior has been chosen because a spurious interrupt has
145 	not to be a priority one and because it may not cause any trouble to
146 	other interrupts.
147 	However, these spurious interrupts place the hardware in an unstable
148 	state and could give problems in other/future versions of the CPU, so
149 	the software has to be written so that they never occur. The only safe
150 	way of achieving this is to always clear or disable peripheral
151 	interrupts with the following sequence:
152 	1: Mask the interrupt in the CPU by setting GM (or IxM) in SR.
153 	2: Perform the bus access to the peripheral register that clears or
154 	disables the interrupt.
155 	3: Wait until the interrupt has actually been cleared or disabled by the
156 	peripheral. This is usually performed by reading from a register in the
157 	same peripheral (it DOES NOT have to be the same register that was
158 	accessed in step 2, but it MUST be in the same peripheral), what takes
159 	bus system latencies into account, but peripheral internal latencies
160 	(generally 0 cycle) also have to be considered.
161 	4: Unmask the interrupt in the CPU by clearing GM (or IxM) in SR.
162 	Note that steps 1 and 4 are useless inside interrupt handlers as the
163 	corresponding interrupt level is automatically masked by IxM (unless IxM
164 	is explicitly cleared by the software).*/
165 
166 	/* Get the right IRQ handler.
167 
168 	If several interrupt lines are active in the group, the interrupt line
169 	with the highest number is selected. This is to be coherent with the
170 	prioritization of interrupt groups performed by the hardware interrupt
171 	controller.
172 
173 	If no handler has been registered for the pending interrupt,
174 	_unhandled_interrupt will be selected thanks to the initialization of
175 	_int_line_handler_table_x by INTC_init_interrupts.
176 
177 	exception.S will provide the interrupt handler with a clean interrupt
178 	stack frame, with nothing more pushed onto the stack. The interrupt
179 	handler must manage the `rete' instruction, which can be done using
180 	pure assembly, inline assembly or the `__attribute__((__interrupt__))'
181 	C function attribute.*/
182 	return (int_req)
183 		? _int_handler_table[int_grp]._int_line_handler_table[32
184 			- clz(int_req) - 1]
185 		: NULL;
186 }
187 
188 
189 /**
190  * \internal
191  * \brief Init EVBA address. This operation may or may not have been done by the
192  * C startup process.
193  */
INTC_init_evba(void)194 static __inline__ void INTC_init_evba(void)
195 {
196   Set_system_register(AVR32_EVBA, (int32_t)&_evba );
197 }
198 
199 
200 /**
201  * \brief Initializes the hardware interrupt controller driver.
202  *
203  */
INTC_init_interrupts(void)204 void INTC_init_interrupts(void)
205 {
206 	uint32_t int_grp, int_req;
207 
208 	INTC_init_evba();
209 
210 	// For all interrupt groups,
211 	for (int_grp = 0; int_grp < AVR32_INTC_NUM_INT_GRPS; int_grp++)
212 	{
213 		// For all interrupt request lines of each group,
214 		for (int_req = 0;
215 			int_req < _int_handler_table[int_grp].num_irqs;
216 			int_req++)
217 		{
218 			/* Assign _unhandled_interrupt as the default interrupt
219 			handler. */
220 			_int_handler_table[int_grp]
221 				._int_line_handler_table[int_req]
222 					= &_unhandled_interrupt;
223 		}
224 
225 		/* Set the interrupt group priority register to its default
226 		value.
227 		By default, all interrupt groups are linked to the interrupt
228 		priority level 0 and to the interrupt vector _int0. */
229 		AVR32_INTC.ipr[int_grp] = IPR_INT0;
230 	}
231 }
232 
233 
234 /**
235  * \brief Registers an interrupt handler.
236  *
237  * \param handler   Interrupt handler to register.
238  * \param irq       IRQ of the interrupt handler to register.
239  * \param int_level Interrupt priority level to assign to the group of this IRQ.
240  *
241  * \warning The interrupt handler must manage the `rete' instruction, which can
242  *          be done using pure assembly, inline assembly or the
243  *          `__attribute__((__interrupt__))' C function attribute.
244  *
245  * \warning If several interrupt handlers of a same group are registered with
246  *          different priority levels, only the latest priority level set will
247  *          be effective.
248  *
249  */
INTC_register_interrupt(__int_handler handler,uint32_t irq,uint32_t int_level)250 void INTC_register_interrupt(__int_handler handler, uint32_t irq,
251 	uint32_t int_level)
252 {
253 	// Determine the group of the IRQ.
254 	uint32_t int_grp = irq / AVR32_INTC_MAX_NUM_IRQS_PER_GRP;
255 
256 	/* Store in _int_line_handler_table_x the pointer to the interrupt
257 	handler, so that _get_interrupt_handler can retrieve it when the
258 	interrupt is vectored. */
259 	_int_handler_table[int_grp]
260 		._int_line_handler_table[irq % AVR32_INTC_MAX_NUM_IRQS_PER_GRP]
261 			= handler;
262 
263 	/* Program the corresponding IPRX register to set the interrupt priority
264 	level and the interrupt vector offset that will be fetched by the core
265 	interrupt system.
266 	NOTE: The _intx functions are intermediate assembly functions between
267 	the core interrupt system and the user interrupt handler. */
268 	if (int_level == AVR32_INTC_INT0) {
269 		AVR32_INTC.ipr[int_grp] = IPR_INT0;
270 	} else if (int_level == AVR32_INTC_INT1) {
271 		AVR32_INTC.ipr[int_grp] = IPR_INT1;
272 	} else if (int_level == AVR32_INTC_INT2) {
273 		AVR32_INTC.ipr[int_grp] = IPR_INT2;
274 	} else {
275 		AVR32_INTC.ipr[int_grp] = IPR_INT3;
276 	}
277 }
278