source: rtems/bsps/arm/lpc32xx/irq/irq.c @ 350b07a0

5
Last change on this file since 350b07a0 was c77cd426, checked in by Joel Sherrill <joel@…>, on 04/30/18 at 22:18:49

Drop executable permissions on .[ch] files

  • Property mode set to 100644
File size: 9.2 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc32xx_interrupt
5 *
6 * @brief Interrupt support.
7 */
8
9/*
10 * Copyright (c) 2009
11 * embedded brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * <rtems@embedded-brains.de>
16 *
17 * The license and distribution terms for this file may be
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.org/license/LICENSE.
20 */
21
22#include <rtems/score/armv4.h>
23
24#include <bsp.h>
25#include <bsp/irq.h>
26#include <bsp/irq-generic.h>
27#include <bsp/lpc32xx.h>
28#include <bsp/linker-symbols.h>
29#include <bsp/mmu.h>
30
31/*
32 * Mask out SIC 1 and 2 IRQ request. There is no need to mask out the FIQ,
33 * since a pending FIQ would be a fatal error.  The default handler will be
34 * invoked in this case.
35 */
36#define LPC32XX_MIC_STATUS_MASK (~0x3U)
37
38typedef union {
39  struct {
40    uint32_t mic;
41    uint32_t sic_1;
42    uint32_t sic_2;
43  } field;
44  uint32_t fields_table [LPC32XX_IRQ_MODULE_COUNT];
45} lpc32xx_irq_fields;
46
47static uint8_t lpc32xx_irq_priority_table [LPC32XX_IRQ_COUNT];
48
49static lpc32xx_irq_fields lpc32xx_irq_priority_masks [LPC32XX_IRQ_PRIORITY_COUNT];
50
51static lpc32xx_irq_fields lpc32xx_irq_enable;
52
53static inline bool lpc32xx_irq_priority_is_valid(unsigned priority)
54{
55  return priority <= LPC32XX_IRQ_PRIORITY_LOWEST;
56}
57
58#define LPC32XX_IRQ_BIT_OPS_DEFINE \
59  unsigned bit = index & 0x1fU; \
60  unsigned module = index >> 5
61
62#define LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE \
63  LPC32XX_IRQ_BIT_OPS_DEFINE; \
64  unsigned module_offset = module << 14; \
65  volatile uint32_t *reg = (volatile uint32_t *) \
66    ((volatile char *) &lpc32xx.mic + module_offset + register_offset)
67
68#define LPC32XX_IRQ_OFFSET_ER 0U
69#define LPC32XX_IRQ_OFFSET_RSR 4U
70#define LPC32XX_IRQ_OFFSET_SR 8U
71#define LPC32XX_IRQ_OFFSET_APR 12U
72#define LPC32XX_IRQ_OFFSET_ATR 16U
73#define LPC32XX_IRQ_OFFSET_ITR 20U
74
75static inline bool lpc32xx_irq_is_bit_set_in_register(unsigned index, unsigned register_offset)
76{
77  LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE;
78
79  return *reg & (1U << bit);
80}
81
82static inline void lpc32xx_irq_set_bit_in_register(unsigned index, unsigned register_offset)
83{
84  LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE;
85
86  *reg |= 1U << bit;
87}
88
89static inline void lpc32xx_irq_clear_bit_in_register(unsigned index, unsigned register_offset)
90{
91  LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE;
92
93  *reg &= ~(1U << bit);
94}
95
96static inline void lpc32xx_irq_set_bit_in_field(unsigned index, lpc32xx_irq_fields *fields)
97{
98  LPC32XX_IRQ_BIT_OPS_DEFINE;
99
100  fields->fields_table [module] |= 1U << bit;
101}
102
103static inline void lpc32xx_irq_clear_bit_in_field(unsigned index, lpc32xx_irq_fields *fields)
104{
105  LPC32XX_IRQ_BIT_OPS_DEFINE;
106
107  fields->fields_table [module] &= ~(1U << bit);
108}
109
110static inline unsigned lpc32xx_irq_get_index(uint32_t val)
111{
112  ARM_SWITCH_REGISTERS;
113
114  __asm__ volatile (
115    ARM_SWITCH_TO_ARM
116    "clz %[val], %[val]\n"
117    "rsb %[val], %[val], #31\n"
118    ARM_SWITCH_BACK
119    : [val] "=r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT
120    : "[val]" (val)
121  );
122
123  return val;
124}
125
126void lpc32xx_irq_set_priority(rtems_vector_number vector, unsigned priority)
127{
128  if (bsp_interrupt_is_valid_vector(vector)) {
129    rtems_interrupt_level level;
130    unsigned i = 0;
131
132    if (priority > LPC32XX_IRQ_PRIORITY_LOWEST) {
133      priority = LPC32XX_IRQ_PRIORITY_LOWEST;
134    }
135
136    lpc32xx_irq_priority_table [vector] = (uint8_t) priority;
137
138    for (i = LPC32XX_IRQ_PRIORITY_HIGHEST; i <= priority; ++i) {
139      rtems_interrupt_disable(level);
140      lpc32xx_irq_clear_bit_in_field(vector, &lpc32xx_irq_priority_masks [i]);
141      rtems_interrupt_enable(level);
142    }
143
144    for (i = priority + 1; i <= LPC32XX_IRQ_PRIORITY_LOWEST; ++i) {
145      rtems_interrupt_disable(level);
146      lpc32xx_irq_set_bit_in_field(vector, &lpc32xx_irq_priority_masks [i]);
147      rtems_interrupt_enable(level);
148    }
149  }
150}
151
152unsigned lpc32xx_irq_get_priority(rtems_vector_number vector)
153{
154  if (bsp_interrupt_is_valid_vector(vector)) {
155    return lpc32xx_irq_priority_table [vector];
156  } else {
157    return LPC32XX_IRQ_PRIORITY_LOWEST;
158  }
159}
160
161void lpc32xx_irq_set_activation_polarity(rtems_vector_number vector, lpc32xx_irq_activation_polarity activation_polarity)
162{
163  if (bsp_interrupt_is_valid_vector(vector)) {
164    rtems_interrupt_level level;
165
166    rtems_interrupt_disable(level);
167    if (activation_polarity == LPC32XX_IRQ_ACTIVE_HIGH_OR_RISING_EDGE) {
168      lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_APR);
169    } else {
170      lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_APR);
171    }
172    rtems_interrupt_enable(level);
173  }
174}
175
176lpc32xx_irq_activation_polarity lpc32xx_irq_get_activation_polarity(rtems_vector_number vector)
177{
178  if (bsp_interrupt_is_valid_vector(vector)) {
179    if (lpc32xx_irq_is_bit_set_in_register(vector, LPC32XX_IRQ_OFFSET_APR)) {
180      return LPC32XX_IRQ_ACTIVE_HIGH_OR_RISING_EDGE;
181    } else {
182      return LPC32XX_IRQ_ACTIVE_LOW_OR_FALLING_EDGE;
183    }
184  } else {
185    return LPC32XX_IRQ_ACTIVE_LOW_OR_FALLING_EDGE;
186  }
187}
188
189void lpc32xx_irq_set_activation_type(rtems_vector_number vector, lpc32xx_irq_activation_type activation_type)
190{
191  if (bsp_interrupt_is_valid_vector(vector)) {
192    rtems_interrupt_level level;
193
194    rtems_interrupt_disable(level);
195    if (activation_type == LPC32XX_IRQ_EDGE_SENSITIVE) {
196      lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ATR);
197    } else {
198      lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ATR);
199    }
200    rtems_interrupt_enable(level);
201  }
202}
203
204lpc32xx_irq_activation_type lpc32xx_irq_get_activation_type(rtems_vector_number vector)
205{
206  if (bsp_interrupt_is_valid_vector(vector)) {
207    if (lpc32xx_irq_is_bit_set_in_register(vector, LPC32XX_IRQ_OFFSET_ATR)) {
208      return LPC32XX_IRQ_EDGE_SENSITIVE;
209    } else {
210      return LPC32XX_IRQ_LEVEL_SENSITIVE;
211    }
212  } else {
213    return LPC32XX_IRQ_LEVEL_SENSITIVE;
214  }
215}
216
217void bsp_interrupt_dispatch(void)
218{
219  uint32_t status = lpc32xx.mic.sr & LPC32XX_MIC_STATUS_MASK;
220  uint32_t er_mic = lpc32xx.mic.er;
221  uint32_t er_sic_1 = lpc32xx.sic_1.er;
222  uint32_t er_sic_2 = lpc32xx.sic_2.er;
223  uint32_t psr = 0;
224  lpc32xx_irq_fields *masks = NULL;
225  rtems_vector_number vector = 0;
226  unsigned priority = 0;
227
228  if (status != 0) {
229    vector = lpc32xx_irq_get_index(status);
230  } else {
231    status = lpc32xx.sic_1.sr;
232    if (status != 0) {
233      vector = lpc32xx_irq_get_index(status) + LPC32XX_IRQ_MODULE_SIC_1;
234    } else {
235      status = lpc32xx.sic_2.sr;
236      if (status != 0) {
237        vector = lpc32xx_irq_get_index(status) + LPC32XX_IRQ_MODULE_SIC_2;
238      } else {
239        return;
240      }
241    }
242  }
243
244  priority = lpc32xx_irq_priority_table [vector];
245
246  masks = &lpc32xx_irq_priority_masks [priority];
247
248  lpc32xx.mic.er = er_mic & masks->field.mic;
249  lpc32xx.sic_1.er = er_sic_1 & masks->field.sic_1;
250  lpc32xx.sic_2.er = er_sic_2 & masks->field.sic_2;
251
252  psr = _ARMV4_Status_irq_enable();
253
254  bsp_interrupt_handler_dispatch(vector);
255
256  _ARMV4_Status_restore(psr);
257
258  lpc32xx.mic.er = er_mic & lpc32xx_irq_enable.field.mic;
259  lpc32xx.sic_1.er = er_sic_1 & lpc32xx_irq_enable.field.sic_1;
260  lpc32xx.sic_2.er = er_sic_2 & lpc32xx_irq_enable.field.sic_2;
261}
262
263void bsp_interrupt_vector_enable(rtems_vector_number vector)
264{
265  rtems_interrupt_level level;
266
267  bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
268
269  rtems_interrupt_disable(level);
270  lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ER);
271  lpc32xx_irq_set_bit_in_field(vector, &lpc32xx_irq_enable);
272  rtems_interrupt_enable(level);
273}
274
275void bsp_interrupt_vector_disable(rtems_vector_number vector)
276{
277  rtems_interrupt_level level;
278
279  bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
280
281  rtems_interrupt_disable(level);
282  lpc32xx_irq_clear_bit_in_field(vector, &lpc32xx_irq_enable);
283  lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ER);
284  rtems_interrupt_enable(level);
285}
286
287void lpc32xx_set_exception_handler(
288  Arm_symbolic_exception_name exception,
289  void (*handler)(void)
290)
291{
292  if ((unsigned) exception < MAX_EXCEPTIONS) {
293    uint32_t *table = (uint32_t *) bsp_vector_table_begin + MAX_EXCEPTIONS;
294
295    table [exception] = (uint32_t) handler;
296
297    #ifndef LPC32XX_DISABLE_MMU
298      rtems_cache_flush_multiple_data_lines(table, 64);
299      rtems_cache_invalidate_multiple_instruction_lines(NULL, 64);
300    #endif
301  }
302}
303
304rtems_status_code bsp_interrupt_facility_initialize(void)
305{
306  size_t i = 0;
307
308  /* Set default priority */
309  for (i = 0; i < LPC32XX_IRQ_COUNT; ++i) {
310    lpc32xx_irq_priority_table [i] = LPC32XX_IRQ_PRIORITY_LOWEST;
311  }
312
313  /* Enable SIC 1 and 2 at all priorities */
314  for (i = 0; i < LPC32XX_IRQ_PRIORITY_COUNT; ++i) {
315    lpc32xx_irq_priority_masks [i].field.mic = 0xc0000003;
316  }
317
318  /* Disable all interrupts except SIC 1 and 2 */
319  lpc32xx_irq_enable.field.sic_2 = 0x0;
320  lpc32xx_irq_enable.field.sic_1 = 0x0;
321  lpc32xx_irq_enable.field.mic = 0xc0000003;
322  lpc32xx.sic_1.er = 0x0;
323  lpc32xx.sic_2.er = 0x0;
324  lpc32xx.mic.er = 0xc0000003;
325
326  /* Set interrupt types to IRQ */
327  lpc32xx.mic.itr = 0x0;
328  lpc32xx.sic_1.itr = 0x0;
329  lpc32xx.sic_2.itr = 0x0;
330
331  /* Set interrupt activation polarities */
332  lpc32xx.mic.apr = 0x3ff0efe0;
333  lpc32xx.sic_1.apr = 0xfbd27184;
334  lpc32xx.sic_2.apr = 0x801810c0;
335
336  /* Set interrupt activation types */
337  lpc32xx.mic.atr = 0x0;
338  lpc32xx.sic_1.atr = 0x26000;
339  lpc32xx.sic_2.atr = 0x0;
340
341  lpc32xx_set_exception_handler(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt);
342
343  return RTEMS_SUCCESSFUL;
344}
Note: See TracBrowser for help on using the repository browser.