summaryrefslogtreecommitdiffstats
path: root/bsps/m68k/genmcf548x/irq/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/m68k/genmcf548x/irq/irq.c')
-rw-r--r--bsps/m68k/genmcf548x/irq/irq.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/bsps/m68k/genmcf548x/irq/irq.c b/bsps/m68k/genmcf548x/irq/irq.c
new file mode 100644
index 0000000000..f02231b67c
--- /dev/null
+++ b/bsps/m68k/genmcf548x/irq/irq.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp/irq-generic.h>
+
+#include <mcf548x/mcf548x.h>
+
+void asm_default_interrupt(void);
+
+typedef void (*void_func)(void);
+
+typedef struct {
+ rtems_interrupt_handler handler;
+ void *arg;
+ const char *info;
+} interrupt_control;
+
+static interrupt_control interrupt_controls[BSP_INTERRUPT_VECTOR_MAX + 1];
+
+static uint32_t vector_to_reg(rtems_vector_number vector)
+{
+ return ((vector + 32U) >> 5) & 0x1;
+}
+
+static uint32_t vector_to_bit(rtems_vector_number vector)
+{
+ return 1U << (vector & 0x1fU);
+}
+
+static volatile uint32_t *vector_to_imr(rtems_vector_number vector)
+{
+ volatile uint32_t *imr = &MCF548X_INTC_IMRH;
+
+ return &imr[vector_to_reg(vector)];
+}
+
+static rtems_vector_number exception_vector_to_vector(
+ rtems_vector_number exception_vector
+)
+{
+ return exception_vector - 64U;
+}
+
+static rtems_vector_number vector_to_exception_vector(
+ rtems_vector_number vector
+)
+{
+ return vector + 64U;
+}
+
+void bsp_interrupt_vector_enable(rtems_vector_number vector)
+{
+ volatile uint32_t *imr = vector_to_imr(vector);
+ uint32_t bit = vector_to_bit(vector);
+ rtems_interrupt_level level;
+
+ bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
+
+ rtems_interrupt_disable(level);
+ *imr &= ~bit;
+ rtems_interrupt_enable(level);
+}
+
+void bsp_interrupt_vector_disable(rtems_vector_number vector)
+{
+ volatile uint32_t *imr = vector_to_imr(vector);
+ uint32_t bit = vector_to_bit(vector);
+ rtems_interrupt_level level;
+
+ bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
+
+ rtems_interrupt_disable(level);
+ *imr |= bit;
+ rtems_interrupt_enable(level);
+}
+
+static void_func get_exception_handler(rtems_vector_number vector)
+{
+ void **vbr;
+ void_func *exception_table;
+
+ m68k_get_vbr(vbr);
+
+ exception_table = (void_func *)vbr;
+
+ return exception_table[vector_to_exception_vector(vector)];
+}
+
+static void set_exception_handler(rtems_vector_number vector, void_func handler)
+{
+ void **vbr;
+ void_func *exception_table;
+
+ m68k_get_vbr(vbr);
+
+ exception_table = (void_func *)vbr;
+
+ exception_table[vector_to_exception_vector(vector)] = handler;
+}
+
+static void dispatch_handler(rtems_vector_number exception_vector)
+{
+ const interrupt_control *ic =
+ &interrupt_controls[exception_vector_to_vector(exception_vector)];
+
+ (*ic->handler)(ic->arg);
+}
+
+static uint8_t get_intc_icr(rtems_vector_number vector)
+{
+ volatile uint8_t *icr = &MCF548X_INTC_ICR0;
+
+ return icr[vector];
+}
+
+rtems_status_code rtems_interrupt_handler_install(
+ rtems_vector_number vector,
+ const char *info,
+ rtems_option options,
+ rtems_interrupt_handler handler,
+ void *arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if (bsp_interrupt_is_valid_vector(vector)) {
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+
+ if (
+ get_exception_handler(vector) == asm_default_interrupt
+ && get_intc_icr(vector) != 0
+ ) {
+ interrupt_control *ic = &interrupt_controls[vector];
+
+ ic->handler = handler;
+ ic->arg = arg;
+ ic->info = info;
+
+ _ISR_Vector_table[vector_to_exception_vector(vector)]
+ = dispatch_handler;
+ set_exception_handler(vector, _ISR_Handler);
+ bsp_interrupt_vector_enable(vector);
+ } else {
+ sc = RTEMS_RESOURCE_IN_USE;
+ }
+
+ rtems_interrupt_enable(level);
+ } else {
+ sc = RTEMS_INVALID_ID;
+ }
+
+ return sc;
+}
+
+static bool is_occupied_by_us(rtems_vector_number vector)
+{
+ return get_exception_handler(vector) == _ISR_Handler
+ && _ISR_Vector_table[vector_to_exception_vector(vector)]
+ == dispatch_handler;
+}
+
+rtems_status_code rtems_interrupt_handler_remove(
+ rtems_vector_number vector,
+ rtems_interrupt_handler handler,
+ void *arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if (bsp_interrupt_is_valid_vector(vector)) {
+ rtems_interrupt_level level;
+ interrupt_control *ic = &interrupt_controls[vector];
+
+ rtems_interrupt_disable(level);
+
+ if (
+ is_occupied_by_us(vector)
+ && ic->handler == handler
+ && ic->arg == arg
+ ) {
+ bsp_interrupt_vector_disable(vector);
+ set_exception_handler(vector, asm_default_interrupt);
+
+ memset(ic, 0, sizeof(*ic));
+ } else {
+ sc = RTEMS_UNSATISFIED;
+ }
+
+ rtems_interrupt_enable(level);
+ } else {
+ sc = RTEMS_INVALID_ID;
+ }
+
+ return sc;
+}
+
+rtems_status_code rtems_interrupt_handler_iterate(
+ rtems_vector_number vector,
+ rtems_interrupt_per_handler_routine routine,
+ void *arg
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if (bsp_interrupt_is_valid_vector(vector)) {
+ if (is_occupied_by_us(vector)) {
+ const interrupt_control *ic = &interrupt_controls[vector];
+
+ (*routine)(arg, ic->info, RTEMS_INTERRUPT_UNIQUE, ic->handler, ic->arg);
+ }
+ } else {
+ sc = RTEMS_INVALID_ID;
+ }
+
+ return sc;
+}