1 /* 2 * File : interrupt.c 3 * COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Change Logs: 20 * 2010-07-09 Bernard first version 21 * 2013-03-29 aozima Modify the interrupt interface implementations. 22 */ 23 24 #include <rtthread.h> 25 #include <rthw.h> 26 #include <board.h> 27 28 #if defined(RT_USING_JZ4770) || defined(RT_USING_JZ4775) || defined(RT_USING_JZ_M150) || defined(RT_USING_JZ_X1000) 29 #define INTERRUPTS_MAX 64 30 #else 31 #define INTERRUPTS_MAX 32 32 #endif 33 34 extern rt_uint32_t rt_interrupt_nest; 35 rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; 36 rt_uint32_t rt_thread_switch_interrupt_flag; 37 38 static struct rt_irq_desc isr_table[INTERRUPTS_MAX]; 39 40 /** 41 * @addtogroup Ingenic 42 */ 43 /*@{*/ 44 45 static void rt_hw_interrupt_handler(int vector, void *param) 46 { 47 rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); 48 } 49 50 /** 51 * This function will initialize hardware interrupt 52 */ 53 void rt_hw_interrupt_init(void) 54 { 55 rt_int32_t idx; 56 57 rt_memset(isr_table, 0x00, sizeof(isr_table)); 58 for (idx = 0; idx < INTERRUPTS_MAX; idx ++) 59 { 60 isr_table[idx].handler = rt_hw_interrupt_handler; 61 } 62 63 /* init interrupt nest, and context in thread sp */ 64 rt_interrupt_nest = 0; 65 rt_interrupt_from_thread = 0; 66 rt_interrupt_to_thread = 0; 67 rt_thread_switch_interrupt_flag = 0; 68 } 69 70 /** 71 * This function will mask a interrupt. 72 * @param vector the interrupt number 73 */ 74 void rt_hw_interrupt_mask(int vector) 75 { 76 /* mask interrupt */ 77 __intc_mask_irq(vector); 78 } 79 80 /** 81 * This function will un-mask a interrupt. 82 * @param vector the interrupt number 83 */ 84 void rt_hw_interrupt_umask(int vector) 85 { 86 __intc_unmask_irq(vector); 87 } 88 89 /** 90 * This function will install a interrupt service routine to a interrupt. 91 * @param vector the interrupt number 92 * @param handler the interrupt service routine to be installed 93 * @param param the interrupt service function parameter 94 * @param name the interrupt name 95 * @return old handler 96 */ 97 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, 98 void *param, const char *name) 99 { 100 rt_isr_handler_t old_handler = RT_NULL; 101 102 if(vector < INTERRUPTS_MAX) 103 { 104 old_handler = isr_table[vector].handler; 105 106 #ifdef RT_USING_INTERRUPT_INFO 107 rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); 108 #endif /* RT_USING_INTERRUPT_INFO */ 109 isr_table[vector].handler = handler; 110 isr_table[vector].param = param; 111 } 112 113 return old_handler; 114 } 115 116 #if defined(RT_USING_JZ4770) || defined(RT_USING_JZ4775) || defined(RT_USING_JZ_M150) || defined(RT_USING_JZ_X1000) 117 /* 118 * fls - find last bit set. 119 * @word: The word to search 120 * 121 * This is defined the same way as ffs. 122 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 123 */ 124 rt_inline int fls(int x) 125 { 126 __asm__("clz %0, %1" : "=r" (x) : "r" (x)); 127 128 return 32 - x; 129 } 130 #endif 131 132 #include <mipsregs.h> 133 134 void rt_interrupt_dispatch(void *ptreg) 135 { 136 int i; 137 void *param; 138 rt_isr_handler_t irq_func; 139 140 #if defined(RT_USING_JZ4770) || defined(RT_USING_JZ4775) || defined(RT_USING_JZ_M150) || defined(RT_USING_JZ_X1000) 141 int irq = 0, group; 142 rt_uint32_t intc_ipr0 = 0, intc_ipr1 = 0, vpu_pending = 0; 143 144 rt_uint32_t c0_status, c0_cause; 145 rt_uint32_t pending_im; 146 147 /* check os timer */ 148 c0_status = read_c0_status(); 149 c0_cause = read_c0_cause(); 150 151 pending_im = (c0_cause & ST0_IM) & (c0_status & ST0_IM); 152 153 if (pending_im & CAUSEF_IP3) 154 { 155 extern void rt_hw_ost_handler(void); 156 rt_hw_ost_handler(); 157 return; 158 } 159 160 if (pending_im & CAUSEF_IP2) 161 { 162 intc_ipr0 = REG_INTC_IPR(0); 163 intc_ipr1 = REG_INTC_IPR(1); 164 165 if (intc_ipr0) 166 { 167 irq = fls(intc_ipr0) - 1; 168 intc_ipr0 &= ~(1<<irq); 169 } 170 else if(intc_ipr1) 171 { 172 irq = fls(intc_ipr1) - 1; 173 intc_ipr1 &= ~(1<<irq); 174 irq += 32; 175 } 176 #ifndef RT_USING_JZ_X1000 /* X1000 has no VPU */ 177 else 178 { 179 __asm__ __volatile__ ( 180 "mfc0 %0, $13, 0 \n\t" 181 "nop \n\t" 182 :"=r"(vpu_pending) 183 :); 184 185 if(vpu_pending & 0x800) 186 irq = IRQ_VPU; 187 else 188 return; 189 } 190 #endif 191 192 if (irq >= INTERRUPTS_MAX) 193 rt_kprintf("max interrupt, irq=%d\n", irq); 194 195 /* do interrupt */ 196 irq_func = isr_table[irq].handler; 197 param = isr_table[irq].param; 198 (*irq_func)(irq, param); 199 200 #ifdef RT_USING_INTERRUPT_INFO 201 isr_table[i].counter++; 202 #endif /* RT_USING_INTERRUPT_INFO */ 203 204 /* ack interrupt */ 205 __intc_ack_irq(irq); 206 } 207 208 if (pending_im & CAUSEF_IP0) 209 rt_kprintf("CAUSEF_IP0\n"); 210 if (pending_im & CAUSEF_IP1) 211 rt_kprintf("CAUSEF_IP1\n"); 212 if (pending_im & CAUSEF_IP4) 213 rt_kprintf("CAUSEF_IP4\n"); 214 if (pending_im & CAUSEF_IP5) 215 rt_kprintf("CAUSEF_IP5\n"); 216 if (pending_im & CAUSEF_IP6) 217 rt_kprintf("CAUSEF_IP6\n"); 218 if (pending_im & CAUSEF_IP7) 219 rt_kprintf("CAUSEF_IP7\n"); 220 #else 221 static rt_uint32_t pending = 0; 222 223 /* the hardware interrupt */ 224 pending |= REG_INTC_IPR; 225 if (!pending) return; 226 227 for (i = INTERRUPTS_MAX; i > 0; --i) 228 { 229 if ((pending & (1<<i))) 230 { 231 pending &= ~(1<<i); 232 233 /* do interrupt */ 234 irq_func = isr_table[i].handler; 235 param = isr_table[i].param; 236 (*irq_func)(i, param); 237 238 #ifdef RT_USING_INTERRUPT_INFO 239 isr_table[i].counter++; 240 #endif /* RT_USING_INTERRUPT_INFO */ 241 242 /* ack interrupt */ 243 __intc_ack_irq(i); 244 } 245 } 246 #endif 247 } 248 249 /*@}*/ 250