[53dd6d61] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
| 4 | * @ingroup bsp_interrupt |
---|
| 5 | * @ingroup arm_beagle |
---|
| 6 | * |
---|
| 7 | * @brief Interrupt support. |
---|
| 8 | */ |
---|
| 9 | |
---|
| 10 | /* |
---|
| 11 | * Copyright (c) 2014 Ben Gras <beng@shrike-systems.com>. All rights reserved. |
---|
| 12 | * |
---|
| 13 | * The license and distribution terms for this file may be |
---|
| 14 | * found in the file LICENSE in this distribution or at |
---|
[d4edbdbc] | 15 | * http://www.rtems.org/license/LICENSE. |
---|
[53dd6d61] | 16 | */ |
---|
| 17 | |
---|
| 18 | #include <bsp.h> |
---|
| 19 | #include <bsp/irq-generic.h> |
---|
| 20 | #include <bsp/linker-symbols.h> |
---|
[8c5c53f4] | 21 | #include <bsp/fatal.h> |
---|
[53dd6d61] | 22 | |
---|
| 23 | #include <rtems/score/armv4.h> |
---|
| 24 | |
---|
| 25 | #include <libcpu/arm-cp15.h> |
---|
| 26 | |
---|
| 27 | struct omap_intr |
---|
| 28 | { |
---|
| 29 | uint32_t base; |
---|
| 30 | int size; |
---|
| 31 | }; |
---|
| 32 | |
---|
| 33 | #if IS_DM3730 |
---|
| 34 | static struct omap_intr omap_intr = { |
---|
| 35 | .base = OMAP3_DM37XX_INTR_BASE, |
---|
| 36 | .size = 0x1000, |
---|
| 37 | }; |
---|
| 38 | #endif |
---|
| 39 | |
---|
| 40 | #if IS_AM335X |
---|
| 41 | static struct omap_intr omap_intr = { |
---|
| 42 | .base = OMAP3_AM335X_INTR_BASE, |
---|
| 43 | .size = 0x1000, |
---|
| 44 | }; |
---|
| 45 | #endif |
---|
| 46 | |
---|
[8c5c53f4] | 47 | /* Enables interrupts at the Interrupt Controller side. */ |
---|
| 48 | static inline void omap_irq_ack(void) |
---|
| 49 | { |
---|
| 50 | mmio_write(omap_intr.base + OMAP3_INTCPS_CONTROL, OMAP3_INTR_NEWIRQAGR); |
---|
[53dd6d61] | 51 | |
---|
[8c5c53f4] | 52 | /* Flush data cache to make sure all the previous writes are done |
---|
| 53 | before re-enabling interrupts. */ |
---|
| 54 | flush_data_cache(); |
---|
| 55 | } |
---|
[53dd6d61] | 56 | |
---|
| 57 | void bsp_interrupt_dispatch(void) |
---|
| 58 | { |
---|
[8c5c53f4] | 59 | const uint32_t reg = mmio_read(omap_intr.base + OMAP3_INTCPS_SIR_IRQ); |
---|
[53dd6d61] | 60 | |
---|
[8c5c53f4] | 61 | if ((reg & OMAP3_INTR_SPURIOUSIRQ_MASK) != OMAP3_INTR_SPURIOUSIRQ_MASK) { |
---|
| 62 | const rtems_vector_number irq = reg & OMAP3_INTR_ACTIVEIRQ_MASK; |
---|
[53dd6d61] | 63 | |
---|
[8c5c53f4] | 64 | bsp_interrupt_handler_dispatch(irq); |
---|
| 65 | } else { |
---|
| 66 | /* Ignore spurious interrupts. We'll still ACK it so new interrupts |
---|
| 67 | can be generated. */ |
---|
[53dd6d61] | 68 | } |
---|
[8c5c53f4] | 69 | |
---|
| 70 | omap_irq_ack(); |
---|
[53dd6d61] | 71 | } |
---|
| 72 | |
---|
[8c5c53f4] | 73 | /* There are 4 32-bit interrupt mask registers for a total of 128 interrupts. |
---|
| 74 | The IRQ number tells us which register to use. */ |
---|
| 75 | static uint32_t omap_get_mir_reg(rtems_vector_number vector, uint32_t *const mask) |
---|
[53dd6d61] | 76 | { |
---|
[8c5c53f4] | 77 | uint32_t mir_reg; |
---|
| 78 | |
---|
| 79 | /* Select which bit to set/clear in the MIR register. */ |
---|
| 80 | *mask = 1ul << (vector % 32u); |
---|
| 81 | |
---|
| 82 | if (vector < 32u) { |
---|
| 83 | mir_reg = OMAP3_INTCPS_MIR0; |
---|
| 84 | } else if (vector < 64u) { |
---|
| 85 | mir_reg = OMAP3_INTCPS_MIR1; |
---|
| 86 | } else if (vector < 96u) { |
---|
| 87 | mir_reg = OMAP3_INTCPS_MIR2; |
---|
| 88 | } else if (vector < 128u) { |
---|
| 89 | mir_reg = OMAP3_INTCPS_MIR3; |
---|
| 90 | } else { |
---|
| 91 | /* Invalid IRQ number. This should never happen. */ |
---|
| 92 | bsp_fatal(0); |
---|
| 93 | } |
---|
| 94 | |
---|
| 95 | return mir_reg; |
---|
[53dd6d61] | 96 | } |
---|
| 97 | |
---|
| 98 | rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector) |
---|
| 99 | { |
---|
| 100 | uint32_t mask, cur; |
---|
[8c5c53f4] | 101 | uint32_t mir_reg = omap_get_mir_reg(vector, &mask); |
---|
[53dd6d61] | 102 | |
---|
| 103 | cur = mmio_read(omap_intr.base + mir_reg); |
---|
| 104 | mmio_write(omap_intr.base + mir_reg, cur & ~mask); |
---|
| 105 | flush_data_cache(); |
---|
| 106 | |
---|
| 107 | return RTEMS_SUCCESSFUL; |
---|
| 108 | } |
---|
| 109 | |
---|
| 110 | rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector) |
---|
| 111 | { |
---|
| 112 | uint32_t mask, cur; |
---|
[8c5c53f4] | 113 | uint32_t mir_reg = omap_get_mir_reg(vector, &mask); |
---|
[53dd6d61] | 114 | |
---|
| 115 | cur = mmio_read(omap_intr.base + mir_reg); |
---|
| 116 | mmio_write(omap_intr.base + mir_reg, cur | mask); |
---|
| 117 | flush_data_cache(); |
---|
| 118 | |
---|
| 119 | return RTEMS_SUCCESSFUL; |
---|
| 120 | } |
---|
| 121 | |
---|
| 122 | rtems_status_code bsp_interrupt_facility_initialize(void) |
---|
| 123 | { |
---|
| 124 | int i; |
---|
| 125 | uint32_t intc_ilrx; |
---|
| 126 | |
---|
| 127 | /* AM335X TRM 6.2.1 Initialization Sequence */ |
---|
| 128 | mmio_write(omap_intr.base + OMAP3_INTCPS_SYSCONFIG, OMAP3_SYSCONFIG_AUTOIDLE); |
---|
| 129 | mmio_write(omap_intr.base + OMAP3_INTCPS_IDLE, 0); |
---|
| 130 | /* priority 0 to all IRQs */ |
---|
| 131 | for(intc_ilrx = 0x100; intc_ilrx <= 0x2fc; intc_ilrx += 4) { |
---|
| 132 | mmio_write(omap_intr.base + intc_ilrx, 0); |
---|
| 133 | } |
---|
| 134 | |
---|
| 135 | /* Mask all interrupts */ |
---|
| 136 | for(i = BSP_INTERRUPT_VECTOR_MIN; i <= BSP_INTERRUPT_VECTOR_MAX; i++) |
---|
| 137 | bsp_interrupt_vector_disable(i); |
---|
| 138 | |
---|
| 139 | /* Install generic interrupt handler */ |
---|
| 140 | arm_cp15_set_exception_handler(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt); |
---|
[1e587f7d] | 141 | arm_cp15_set_vector_base_address(bsp_vector_table_begin); |
---|
[53dd6d61] | 142 | |
---|
| 143 | return RTEMS_SUCCESSFUL; |
---|
| 144 | } |
---|