source: rtems/c/src/lib/libbsp/arm/lpc32xx/irq/irq.c @ 2f8f951b

5
Last change on this file since 2f8f951b was 2f8f951b, checked in by Kevin Kirspel <kevin-kirspel@…>, on Jan 23, 2017 at 1:51:27 PM

bsp/lpc32xx: Fix interrupt controller suppport

Enable/Disable? vector routines now check for a valid vector. Without
these guards, the Enable/Disable? vector routines will not work with the
interrupt server.

  • Property mode set to 100755
File size: 9.3 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_is_valid(rtems_vector_number vector)
54{
55  return vector <= BSP_INTERRUPT_VECTOR_MAX;
56}
57
58static inline bool lpc32xx_irq_priority_is_valid(unsigned priority)
59{
60  return priority <= LPC32XX_IRQ_PRIORITY_LOWEST;
61}
62
63#define LPC32XX_IRQ_BIT_OPS_DEFINE \
64  unsigned bit = index & 0x1fU; \
65  unsigned module = index >> 5
66
67#define LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE \
68  LPC32XX_IRQ_BIT_OPS_DEFINE; \
69  unsigned module_offset = module << 14; \
70  volatile uint32_t *reg = (volatile uint32_t *) \
71    ((volatile char *) &lpc32xx.mic + module_offset + register_offset)
72
73#define LPC32XX_IRQ_OFFSET_ER 0U
74#define LPC32XX_IRQ_OFFSET_RSR 4U
75#define LPC32XX_IRQ_OFFSET_SR 8U
76#define LPC32XX_IRQ_OFFSET_APR 12U
77#define LPC32XX_IRQ_OFFSET_ATR 16U
78#define LPC32XX_IRQ_OFFSET_ITR 20U
79
80static inline bool lpc32xx_irq_is_bit_set_in_register(unsigned index, unsigned register_offset)
81{
82  LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE;
83
84  return *reg & (1U << bit);
85}
86
87static inline void lpc32xx_irq_set_bit_in_register(unsigned index, unsigned register_offset)
88{
89  LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE;
90
91  *reg |= 1U << bit;
92}
93
94static inline void lpc32xx_irq_clear_bit_in_register(unsigned index, unsigned register_offset)
95{
96  LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE;
97
98  *reg &= ~(1U << bit);
99}
100
101static inline void lpc32xx_irq_set_bit_in_field(unsigned index, lpc32xx_irq_fields *fields)
102{
103  LPC32XX_IRQ_BIT_OPS_DEFINE;
104
105  fields->fields_table [module] |= 1U << bit;
106}
107
108static inline void lpc32xx_irq_clear_bit_in_field(unsigned index, lpc32xx_irq_fields *fields)
109{
110  LPC32XX_IRQ_BIT_OPS_DEFINE;
111
112  fields->fields_table [module] &= ~(1U << bit);
113}
114
115static inline unsigned lpc32xx_irq_get_index(uint32_t val)
116{
117  ARM_SWITCH_REGISTERS;
118
119  __asm__ volatile (
120    ARM_SWITCH_TO_ARM
121    "clz %[val], %[val]\n"
122    "rsb %[val], %[val], #31\n"
123    ARM_SWITCH_BACK
124    : [val] "=r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT
125    : "[val]" (val)
126  );
127
128  return val;
129}
130
131void lpc32xx_irq_set_priority(rtems_vector_number vector, unsigned priority)
132{
133  if (lpc32xx_irq_is_valid(vector)) {
134    rtems_interrupt_level level;
135    unsigned i = 0;
136
137    if (priority > LPC32XX_IRQ_PRIORITY_LOWEST) {
138      priority = LPC32XX_IRQ_PRIORITY_LOWEST;
139    }
140
141    lpc32xx_irq_priority_table [vector] = (uint8_t) priority;
142
143    for (i = LPC32XX_IRQ_PRIORITY_HIGHEST; i <= priority; ++i) {
144      rtems_interrupt_disable(level);
145      lpc32xx_irq_clear_bit_in_field(vector, &lpc32xx_irq_priority_masks [i]);
146      rtems_interrupt_enable(level);
147    }
148
149    for (i = priority + 1; i <= LPC32XX_IRQ_PRIORITY_LOWEST; ++i) {
150      rtems_interrupt_disable(level);
151      lpc32xx_irq_set_bit_in_field(vector, &lpc32xx_irq_priority_masks [i]);
152      rtems_interrupt_enable(level);
153    }
154  }
155}
156
157unsigned lpc32xx_irq_get_priority(rtems_vector_number vector)
158{
159  if (lpc32xx_irq_is_valid(vector)) {
160    return lpc32xx_irq_priority_table [vector];
161  } else {
162    return LPC32XX_IRQ_PRIORITY_LOWEST;
163  }
164}
165
166void lpc32xx_irq_set_activation_polarity(rtems_vector_number vector, lpc32xx_irq_activation_polarity activation_polarity)
167{
168  if (lpc32xx_irq_is_valid(vector)) {
169    rtems_interrupt_level level;
170
171    rtems_interrupt_disable(level);
172    if (activation_polarity == LPC32XX_IRQ_ACTIVE_HIGH_OR_RISING_EDGE) {
173      lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_APR);
174    } else {
175      lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_APR);
176    }
177    rtems_interrupt_enable(level);
178  }
179}
180
181lpc32xx_irq_activation_polarity lpc32xx_irq_get_activation_polarity(rtems_vector_number vector)
182{
183  if (lpc32xx_irq_is_valid(vector)) {
184    if (lpc32xx_irq_is_bit_set_in_register(vector, LPC32XX_IRQ_OFFSET_APR)) {
185      return LPC32XX_IRQ_ACTIVE_HIGH_OR_RISING_EDGE;
186    } else {
187      return LPC32XX_IRQ_ACTIVE_LOW_OR_FALLING_EDGE;
188    }
189  } else {
190    return LPC32XX_IRQ_ACTIVE_LOW_OR_FALLING_EDGE;
191  }
192}
193
194void lpc32xx_irq_set_activation_type(rtems_vector_number vector, lpc32xx_irq_activation_type activation_type)
195{
196  if (lpc32xx_irq_is_valid(vector)) {
197    rtems_interrupt_level level;
198
199    rtems_interrupt_disable(level);
200    if (activation_type == LPC32XX_IRQ_EDGE_SENSITIVE) {
201      lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ATR);
202    } else {
203      lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ATR);
204    }
205    rtems_interrupt_enable(level);
206  }
207}
208
209lpc32xx_irq_activation_type lpc32xx_irq_get_activation_type(rtems_vector_number vector)
210{
211  if (lpc32xx_irq_is_valid(vector)) {
212    if (lpc32xx_irq_is_bit_set_in_register(vector, LPC32XX_IRQ_OFFSET_ATR)) {
213      return LPC32XX_IRQ_EDGE_SENSITIVE;
214    } else {
215      return LPC32XX_IRQ_LEVEL_SENSITIVE;
216    }
217  } else {
218    return LPC32XX_IRQ_LEVEL_SENSITIVE;
219  }
220}
221
222void bsp_interrupt_dispatch(void)
223{
224  uint32_t status = lpc32xx.mic.sr & LPC32XX_MIC_STATUS_MASK;
225  uint32_t er_mic = lpc32xx.mic.er;
226  uint32_t er_sic_1 = lpc32xx.sic_1.er;
227  uint32_t er_sic_2 = lpc32xx.sic_2.er;
228  uint32_t psr = 0;
229  lpc32xx_irq_fields *masks = NULL;
230  rtems_vector_number vector = 0;
231  unsigned priority = 0;
232
233  if (status != 0) {
234    vector = lpc32xx_irq_get_index(status);
235  } else {
236    status = lpc32xx.sic_1.sr;
237    if (status != 0) {
238      vector = lpc32xx_irq_get_index(status) + LPC32XX_IRQ_MODULE_SIC_1;
239    } else {
240      status = lpc32xx.sic_2.sr;
241      if (status != 0) {
242        vector = lpc32xx_irq_get_index(status) + LPC32XX_IRQ_MODULE_SIC_2;
243      } else {
244        return;
245      }
246    }
247  }
248
249  priority = lpc32xx_irq_priority_table [vector];
250
251  masks = &lpc32xx_irq_priority_masks [priority];
252
253  lpc32xx.mic.er = er_mic & masks->field.mic;
254  lpc32xx.sic_1.er = er_sic_1 & masks->field.sic_1;
255  lpc32xx.sic_2.er = er_sic_2 & masks->field.sic_2;
256
257  psr = _ARMV4_Status_irq_enable();
258
259  bsp_interrupt_handler_dispatch(vector);
260
261  _ARMV4_Status_restore(psr);
262
263  lpc32xx.mic.er = er_mic & lpc32xx_irq_enable.field.mic;
264  lpc32xx.sic_1.er = er_sic_1 & lpc32xx_irq_enable.field.sic_1;
265  lpc32xx.sic_2.er = er_sic_2 & lpc32xx_irq_enable.field.sic_2;
266}
267
268rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
269{
270  if (lpc32xx_irq_is_valid(vector)) {
271    rtems_interrupt_level level;
272
273    rtems_interrupt_disable(level);
274    lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ER);
275    lpc32xx_irq_set_bit_in_field(vector, &lpc32xx_irq_enable);
276    rtems_interrupt_enable(level);
277  }
278
279  return RTEMS_SUCCESSFUL;
280}
281
282rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
283{
284  if (lpc32xx_irq_is_valid(vector)) {
285    rtems_interrupt_level level;
286
287    rtems_interrupt_disable(level);
288    lpc32xx_irq_clear_bit_in_field(vector, &lpc32xx_irq_enable);
289    lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ER);
290    rtems_interrupt_enable(level);
291  }
292
293  return RTEMS_SUCCESSFUL;
294}
295
296void lpc32xx_set_exception_handler(
297  Arm_symbolic_exception_name exception,
298  void (*handler)(void)
299)
300{
301  if ((unsigned) exception < MAX_EXCEPTIONS) {
302    uint32_t *table = (uint32_t *) bsp_vector_table_begin + MAX_EXCEPTIONS;
303
304    table [exception] = (uint32_t) handler;
305
306    #ifndef LPC32XX_DISABLE_MMU
307      rtems_cache_flush_multiple_data_lines(table, 64);
308      rtems_cache_invalidate_multiple_instruction_lines(NULL, 64);
309    #endif
310  }
311}
312
313rtems_status_code bsp_interrupt_facility_initialize(void)
314{
315  size_t i = 0;
316
317  /* Set default priority */
318  for (i = 0; i < LPC32XX_IRQ_COUNT; ++i) {
319    lpc32xx_irq_priority_table [i] = LPC32XX_IRQ_PRIORITY_LOWEST;
320  }
321
322  /* Enable SIC 1 and 2 at all priorities */
323  for (i = 0; i < LPC32XX_IRQ_PRIORITY_COUNT; ++i) {
324    lpc32xx_irq_priority_masks [i].field.mic = 0xc0000003;
325  }
326
327  /* Disable all interrupts except SIC 1 and 2 */
328  lpc32xx_irq_enable.field.sic_2 = 0x0;
329  lpc32xx_irq_enable.field.sic_1 = 0x0;
330  lpc32xx_irq_enable.field.mic = 0xc0000003;
331  lpc32xx.sic_1.er = 0x0;
332  lpc32xx.sic_2.er = 0x0;
333  lpc32xx.mic.er = 0xc0000003;
334
335  /* Set interrupt types to IRQ */
336  lpc32xx.mic.itr = 0x0;
337  lpc32xx.sic_1.itr = 0x0;
338  lpc32xx.sic_2.itr = 0x0;
339
340  /* Set interrupt activation polarities */
341  lpc32xx.mic.apr = 0x3ff0efe0;
342  lpc32xx.sic_1.apr = 0xfbd27184;
343  lpc32xx.sic_2.apr = 0x801810c0;
344
345  /* Set interrupt activation types */
346  lpc32xx.mic.atr = 0x0;
347  lpc32xx.sic_1.atr = 0x26000;
348  lpc32xx.sic_2.atr = 0x0;
349
350  lpc32xx_set_exception_handler(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt);
351
352  return RTEMS_SUCCESSFUL;
353}
Note: See TracBrowser for help on using the repository browser.