source: rtems/bsps/arm/lpc32xx/irq/irq.c @ ba619b7f

Last change on this file since ba619b7f was ba619b7f, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 21:38:20

bsps/arm/: Scripted embedded brains header file clean up

Updates #4625.

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