summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/beagle/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/arm/beagle/irq.c')
-rw-r--r--c/src/lib/libbsp/arm/beagle/irq.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/arm/beagle/irq.c b/c/src/lib/libbsp/arm/beagle/irq.c
new file mode 100644
index 0000000000..063034498b
--- /dev/null
+++ b/c/src/lib/libbsp/arm/beagle/irq.c
@@ -0,0 +1,142 @@
+/**
+ * @file
+ *
+ * @ingroup bsp_interrupt
+ * @ingroup arm_beagle
+ *
+ * @brief Interrupt support.
+ */
+
+/*
+ * Copyright (c) 2014 Ben Gras <beng@shrike-systems.com>. All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/irq-generic.h>
+#include <bsp/linker-symbols.h>
+
+#include <rtems/score/armv4.h>
+
+#include <libcpu/arm-cp15.h>
+
+struct omap_intr
+{
+ uint32_t base;
+ int size;
+};
+
+#if IS_DM3730
+static struct omap_intr omap_intr = {
+ .base = OMAP3_DM37XX_INTR_BASE,
+ .size = 0x1000,
+};
+#endif
+
+#if IS_AM335X
+static struct omap_intr omap_intr = {
+ .base = OMAP3_AM335X_INTR_BASE,
+ .size = 0x1000,
+};
+#endif
+
+static int irqs_enabled[BSP_INTERRUPT_VECTOR_MAX+1];
+
+volatile static int level = 0;
+
+void bsp_interrupt_dispatch(void)
+{
+ /* get irq */
+ uint32_t reg = mmio_read(omap_intr.base + OMAP3_INTCPS_SIR_IRQ);
+ int irq;
+ irq = reg & OMAP3_INTR_ACTIVEIRQ_MASK;
+
+ if(!irqs_enabled[irq]) {
+ /* Ignore spurious interrupt */
+ } else {
+ bsp_interrupt_vector_disable(irq);
+
+ /* enable new interrupts, and flush data cache to make sure
+ * it hits the intc
+ */
+ mmio_write(omap_intr.base + OMAP3_INTCPS_CONTROL, OMAP3_INTR_NEWIRQAGR);
+ flush_data_cache();
+ mmio_read(omap_intr.base + OMAP3_INTCPS_SIR_IRQ);
+ flush_data_cache();
+
+ /* keep current irq masked but enable unmasked ones */
+ uint32_t psr = _ARMV4_Status_irq_enable();
+ bsp_interrupt_handler_dispatch(irq);
+
+ _ARMV4_Status_restore(psr);
+
+ bsp_interrupt_vector_enable(irq);
+ }
+}
+
+static uint32_t get_mir_reg(int vector, uint32_t *mask)
+{
+ *mask = 1UL << (vector % 32);
+
+ if(vector < 0) while(1) ;
+ if(vector < 32) return OMAP3_INTCPS_MIR0;
+ if(vector < 64) return OMAP3_INTCPS_MIR1;
+ if(vector < 96) return OMAP3_INTCPS_MIR2;
+ if(vector < 128) return OMAP3_INTCPS_MIR3;
+ while(1) ;
+}
+
+rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
+{
+ uint32_t mask, cur;
+ uint32_t mir_reg = get_mir_reg(vector, &mask);
+
+ cur = mmio_read(omap_intr.base + mir_reg);
+ mmio_write(omap_intr.base + mir_reg, cur & ~mask);
+ flush_data_cache();
+
+ irqs_enabled[vector] = 1;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
+{
+ uint32_t mask, cur;
+ uint32_t mir_reg = get_mir_reg(vector, &mask);
+
+ cur = mmio_read(omap_intr.base + mir_reg);
+ mmio_write(omap_intr.base + mir_reg, cur | mask);
+ flush_data_cache();
+
+ irqs_enabled[vector] = 0;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code bsp_interrupt_facility_initialize(void)
+{
+ int i;
+ uint32_t intc_ilrx;
+
+ /* AM335X TRM 6.2.1 Initialization Sequence */
+ mmio_write(omap_intr.base + OMAP3_INTCPS_SYSCONFIG, OMAP3_SYSCONFIG_AUTOIDLE);
+ mmio_write(omap_intr.base + OMAP3_INTCPS_IDLE, 0);
+ /* priority 0 to all IRQs */
+ for(intc_ilrx = 0x100; intc_ilrx <= 0x2fc; intc_ilrx += 4) {
+ mmio_write(omap_intr.base + intc_ilrx, 0);
+ }
+
+ /* Mask all interrupts */
+ for(i = BSP_INTERRUPT_VECTOR_MIN; i <= BSP_INTERRUPT_VECTOR_MAX; i++)
+ bsp_interrupt_vector_disable(i);
+
+ /* Install generic interrupt handler */
+ arm_cp15_set_exception_handler(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt);
+ arm_cp15_set_vector_base_address((uint32_t) bsp_vector_table_begin);
+
+ return RTEMS_SUCCESSFUL;
+}