[3c6fe2e] | 1 | /* |
---|
| 2 | * |
---|
| 3 | * |
---|
| 4 | * The license and distribution terms for this file may be |
---|
| 5 | * found in found in the file LICENSE in this distribution or at |
---|
| 6 | * http://www.rtems.com/license/LICENSE. |
---|
| 7 | * |
---|
| 8 | * Middleware support for PPC405 by M.Hamel ADInstruments Ltd 2008 |
---|
| 9 | * |
---|
| 10 | * $Id$ |
---|
| 11 | */ |
---|
| 12 | |
---|
| 13 | #include <rtems.h> |
---|
| 14 | #include <bsp.h> |
---|
| 15 | #include <bsp/irq.h> |
---|
| 16 | #include <bsp/irq_supp.h> |
---|
| 17 | #include <libcpu/raw_exception.h> |
---|
| 18 | #include <libcpu/powerpc-utility.h> |
---|
| 19 | |
---|
| 20 | |
---|
| 21 | /* PPC405EX UIC numbers */ |
---|
| 22 | #define UIC_DCR_BASE 0xc0 |
---|
| 23 | #define UIC0_SR (UIC_DCR_BASE+0x0) /* UIC status */ |
---|
| 24 | #define UIC0_SRS (UIC_DCR_BASE+0x1) /* UIC status set */ |
---|
| 25 | #define UIC0_ER (UIC_DCR_BASE+0x2) /* UIC enable */ |
---|
| 26 | #define UIC0_CR (UIC_DCR_BASE+0x3) /* UIC critical */ |
---|
| 27 | #define UIC0_PR (UIC_DCR_BASE+0x4) /* UIC polarity */ |
---|
| 28 | #define UIC0_TR (UIC_DCR_BASE+0x5) /* UIC triggering */ |
---|
| 29 | #define UIC0_MSR (UIC_DCR_BASE+0x6) /* UIC masked status */ |
---|
| 30 | #define UIC0_VR (UIC_DCR_BASE+0x7) /* UIC vector */ |
---|
| 31 | #define UIC0_VCR (UIC_DCR_BASE+0x8) /* UIC vector configuration */ |
---|
| 32 | |
---|
| 33 | #define UIC1_SR (UIC_DCR_BASE+0x10) /* UIC status */ |
---|
| 34 | #define UIC1_SRS (UIC_DCR_BASE+0x11) /* UIC status set */ |
---|
| 35 | #define UIC1_ER (UIC_DCR_BASE+0x12) /* UIC enable */ |
---|
| 36 | #define UIC1_CR (UIC_DCR_BASE+0x13) /* UIC critical */ |
---|
| 37 | #define UIC1_PR (UIC_DCR_BASE+0x14) /* UIC polarity */ |
---|
| 38 | #define UIC1_TR (UIC_DCR_BASE+0x15) /* UIC triggering */ |
---|
| 39 | #define UIC1_MSR (UIC_DCR_BASE+0x16) /* UIC masked status */ |
---|
| 40 | #define UIC1_VR (UIC_DCR_BASE+0x17) /* UIC vector */ |
---|
| 41 | #define UIC1_VCR (UIC_DCR_BASE+0x18) /* UIC vector configuration */ |
---|
| 42 | |
---|
| 43 | #define UIC2_SR (UIC_DCR_BASE+0x20) /* UIC status */ |
---|
| 44 | #define UIC2_SRS (UIC_DCR_BASE+0x21) /* UIC status set */ |
---|
| 45 | #define UIC2_ER (UIC_DCR_BASE+0x22) /* UIC enable */ |
---|
| 46 | #define UIC2_CR (UIC_DCR_BASE+0x23) /* UIC critical */ |
---|
| 47 | #define UIC2_PR (UIC_DCR_BASE+0x24) /* UIC polarity */ |
---|
| 48 | #define UIC2_TR (UIC_DCR_BASE+0x25) /* UIC triggering */ |
---|
| 49 | #define UIC2_MSR (UIC_DCR_BASE+0x26) /* UIC masked status */ |
---|
| 50 | #define UIC2_VR (UIC_DCR_BASE+0x27) /* UIC vector */ |
---|
| 51 | #define UIC2_VCR (UIC_DCR_BASE+0x28) /* UIC vector configuration */ |
---|
| 52 | |
---|
| 53 | enum { kUICWords = 3 }; |
---|
| 54 | |
---|
| 55 | static rtems_irq_connect_data* rtems_hdl_tblP; |
---|
| 56 | static rtems_irq_connect_data dflt_entry; |
---|
| 57 | |
---|
| 58 | static uint32_t gEnabledInts[kUICWords]; /* 1-bits mean enabled */ |
---|
| 59 | static uint32_t gIntInhibited[kUICWords]; /* 1-bits disable, overriding gEnabledInts because the interrupt |
---|
| 60 | is being processed in C_dispatch_irq_handler */ |
---|
| 61 | |
---|
| 62 | static inline int IsUICIRQ(const rtems_irq_number irqLine) |
---|
| 63 | { |
---|
| 64 | return (((int) irqLine <= BSP_UIC_IRQ_MAX_OFFSET) && |
---|
| 65 | ((int) irqLine >= BSP_UIC_IRQ_LOWEST_OFFSET) |
---|
| 66 | ); |
---|
| 67 | } |
---|
| 68 | |
---|
| 69 | static void WriteIState() |
---|
| 70 | /* Write the gEnabledInts state masked by gIntInhibited to the hardware */ |
---|
| 71 | { |
---|
[574fb67] | 72 | PPC_SET_DEVICE_CONTROL_REGISTER(UIC0_ER, |
---|
| 73 | gEnabledInts[0] & ~gIntInhibited[0]); |
---|
| 74 | PPC_SET_DEVICE_CONTROL_REGISTER(UIC1_ER, |
---|
| 75 | gEnabledInts[1] & ~gIntInhibited[1]); |
---|
| 76 | PPC_SET_DEVICE_CONTROL_REGISTER(UIC2_ER, |
---|
| 77 | gEnabledInts[2] & ~gIntInhibited[2]); |
---|
[3c6fe2e] | 78 | } |
---|
| 79 | |
---|
| 80 | void |
---|
| 81 | BSP_enable_irq_at_pic(const rtems_irq_number irq) |
---|
| 82 | /* Enable an interrupt; this can be called from inside C_dispatch_irq_handler */ |
---|
| 83 | { |
---|
| 84 | if (IsUICIRQ(irq)) { |
---|
| 85 | /* Set relevant bit in the state, write state to the UIC */ |
---|
| 86 | gEnabledInts[irq>>5] |= (0x80000000 >> (irq & 0x1F)); |
---|
| 87 | WriteIState(); |
---|
| 88 | } |
---|
| 89 | } |
---|
| 90 | |
---|
| 91 | int |
---|
| 92 | BSP_disable_irq_at_pic(const rtems_irq_number irq) |
---|
| 93 | /* Enable an interrupt; this can be called from inside C_dispatch_irq_handler */ |
---|
| 94 | { |
---|
| 95 | if (IsUICIRQ(irq)) { |
---|
| 96 | uint32_t oldState; |
---|
| 97 | int iword = irq>>5; |
---|
| 98 | uint32_t mask = (0x80000000 >> (irq & 0x1F)); |
---|
| 99 | |
---|
| 100 | oldState = gEnabledInts[iword] & mask; |
---|
| 101 | gEnabledInts[iword] &= ~mask; |
---|
| 102 | WriteIState(); |
---|
| 103 | return oldState ? 1 : 0; |
---|
| 104 | } else |
---|
| 105 | return -1; |
---|
| 106 | } |
---|
| 107 | |
---|
| 108 | int |
---|
| 109 | BSP_setup_the_pic(rtems_irq_global_settings* config) |
---|
| 110 | { |
---|
| 111 | int i; |
---|
| 112 | |
---|
| 113 | dflt_entry = config->defaultEntry; |
---|
| 114 | rtems_hdl_tblP = config->irqHdlTbl; |
---|
| 115 | for (i=0; i<kUICWords; i++) |
---|
| 116 | gIntInhibited[i] = 0; |
---|
| 117 | |
---|
[574fb67] | 118 | /* disable all interrupts */ |
---|
| 119 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_ER, 0x00000000); |
---|
| 120 | /* Set Critical / Non Critical interrupts */ |
---|
| 121 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_CR, 0x00000000); |
---|
| 122 | /* Set Interrupt Polarities */ |
---|
| 123 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_PR, 0xf7ffffff); |
---|
| 124 | /* Set Interrupt Trigger Levels */ |
---|
| 125 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_TR, 0x01e1fff8); |
---|
| 126 | /* Set Vect base=0,INT31 Highest priority */ |
---|
| 127 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_VR, 0x00000001); |
---|
| 128 | /* clear all interrupts */ |
---|
| 129 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_SR, 0xffffffff); |
---|
| 130 | |
---|
| 131 | /* disable all interrupts */ |
---|
| 132 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_ER, 0x00000000); |
---|
| 133 | /* Set Critical / Non Critical interrupts */ |
---|
| 134 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_CR, 0x00000000); |
---|
| 135 | /* Set Interrupt Polarities */ |
---|
| 136 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_PR, 0xfffac785); |
---|
| 137 | /* Set Interrupt Trigger Levels */ |
---|
| 138 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_TR, 0x001d0040); |
---|
| 139 | /* Set Vect base=0,INT31 Highest priority */ |
---|
| 140 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_VR, 0x00000001); |
---|
| 141 | /* clear all interrupts */ |
---|
| 142 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_SR, 0xffffffff); |
---|
| 143 | |
---|
| 144 | /* Disable all interrupts except cascade UIC0 and UIC1 */ |
---|
| 145 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_ER, 0x0000000a); |
---|
| 146 | /* Set Critical / Non Critical interrupts */ |
---|
| 147 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_CR, 0x00000000); |
---|
| 148 | /* Set Interrupt Polarities */ |
---|
| 149 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_PR, 0xffbfefef); |
---|
| 150 | /* Set Interrupt Trigger Levels */ |
---|
| 151 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_TR, 0x00007000); |
---|
| 152 | /* Set Vect base=0,INT31 Highest priority */ |
---|
| 153 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_VR, 0x00000001); |
---|
| 154 | /* clear all interrupts */ |
---|
| 155 | PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_SR, 0xffffffff); |
---|
[3c6fe2e] | 156 | |
---|
| 157 | return 1; |
---|
| 158 | } |
---|
| 159 | |
---|
| 160 | |
---|
| 161 | /* |
---|
| 162 | * High level IRQ handler called from shared_raw_irq_code_entry; decode and |
---|
| 163 | * dispatch. Note that this routine needs to be re-entrant |
---|
| 164 | * |
---|
| 165 | * No support for critical interrupts here yet |
---|
| 166 | */ |
---|
| 167 | |
---|
| 168 | int |
---|
| 169 | C_dispatch_irq_handler( struct _BSP_Exception_frame* frame, unsigned int excNum ) |
---|
| 170 | { |
---|
| 171 | if (excNum == ASM_EXT_VECTOR) { |
---|
| 172 | uint32_t active[kUICWords]; |
---|
| 173 | |
---|
| 174 | /* Fetch the masked flags that tell us what external ints are active. |
---|
| 175 | Likely to be only one, but we need to handle more than one, |
---|
| 176 | OR the flags into gIntInhibited */ |
---|
[574fb67] | 177 | active[0] = PPC_DEVICE_CONTROL_REGISTER(UIC0_MSR); |
---|
| 178 | active[1] = PPC_DEVICE_CONTROL_REGISTER(UIC1_MSR); |
---|
| 179 | active[2] = PPC_DEVICE_CONTROL_REGISTER(UIC2_MSR); |
---|
[3c6fe2e] | 180 | gIntInhibited[0] |= active[0]; |
---|
| 181 | gIntInhibited[1] |= active[1]; |
---|
| 182 | gIntInhibited[2] |= active[2]; |
---|
| 183 | |
---|
| 184 | /* ...and update the hardware so the active interrupts are disabled */ |
---|
| 185 | WriteIState(); |
---|
| 186 | |
---|
| 187 | /* Loop, calling bsp_irq_dispatch_list for each active interrupt */ |
---|
| 188 | while ((active[0] | active[1] | active[2]) != 0) { |
---|
| 189 | uint32_t index = -1; |
---|
| 190 | uint32_t bit, bmask; |
---|
| 191 | |
---|
| 192 | /* Find an active interrupt, searching 0..2, bit 0..bit 31 (IBM order) */ |
---|
| 193 | do { |
---|
| 194 | index++; |
---|
| 195 | asm volatile (" cntlzw %0, %1":"=r" (bit):"r" (active[index])); |
---|
| 196 | } while (bit==32); |
---|
| 197 | |
---|
| 198 | /* Call the matching handler */ |
---|
| 199 | bsp_irq_dispatch_list(rtems_hdl_tblP, (index*32)+bit, dflt_entry.hdl); |
---|
| 200 | |
---|
| 201 | /* Write a 1-bit to the appropriate status register to clear it */ |
---|
| 202 | bmask = 0x80000000 >> bit; |
---|
| 203 | switch (index) { |
---|
[574fb67] | 204 | case 0: |
---|
| 205 | PPC_SET_DEVICE_CONTROL_REGISTER(UIC0_SR, bmask); |
---|
| 206 | break; |
---|
| 207 | case 1: |
---|
| 208 | PPC_SET_DEVICE_CONTROL_REGISTER(UIC1_SR, bmask); |
---|
| 209 | break; |
---|
| 210 | case 2: |
---|
| 211 | PPC_SET_DEVICE_CONTROL_REGISTER(UIC2_SR, bmask); |
---|
| 212 | break; |
---|
[3c6fe2e] | 213 | } |
---|
| 214 | |
---|
| 215 | /* Clear in the active record and gIntInhibited */ |
---|
| 216 | active[index] &= ~bmask; |
---|
| 217 | gIntInhibited[index] &= ~bmask; |
---|
| 218 | }; |
---|
| 219 | |
---|
| 220 | /* Update the hardware again so the interrupts we have handled are unmasked */ |
---|
| 221 | WriteIState(); |
---|
| 222 | return 0; |
---|
| 223 | |
---|
| 224 | } else if (excNum == ASM_DEC_VECTOR) { /* 0x1000 remapped by C_dispatch_dec_handler_bookE */ |
---|
| 225 | bsp_irq_dispatch_list(rtems_hdl_tblP, BSP_PIT, dflt_entry.hdl); |
---|
| 226 | return 0; |
---|
| 227 | |
---|
| 228 | } else if (excNum == ASM_BOOKE_FIT_VECTOR) { /* 0x1010 mapped to 0x13 by ppc_get_vector_addr */ |
---|
| 229 | bsp_irq_dispatch_list(rtems_hdl_tblP, BSP_FIT, dflt_entry.hdl); |
---|
| 230 | return 0; |
---|
| 231 | |
---|
| 232 | } else if (excNum == ASM_BOOKE_WDOG_VECTOR) { /* 0x1020 mapped to 0x14 by ppc_get_vector_addr */ |
---|
| 233 | bsp_irq_dispatch_list(rtems_hdl_tblP, BSP_WDOG, dflt_entry.hdl); |
---|
| 234 | return 0; |
---|
| 235 | |
---|
| 236 | } else |
---|
| 237 | return -1; /* unhandled interrupt, panic time */ |
---|
| 238 | } |
---|
| 239 | |
---|