1 /* 2 * File : interrupt.c 3 * This file is part of RT-Thread RTOS 4 * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team 5 * 6 * The license and distribution terms for this file may be 7 * found in the file LICENSE in this distribution or at 8 * http://www.rt-thread.org/license/LICENSE 9 * 10 * Change Logs: 11 * Date Author Notes 12 * 2010-10-15 Bernard first version 13 * 2010-10-15 lgnq modified for LS1B 14 * 2013-03-29 aozima Modify the interrupt interface implementations. 15 * 2015-07-06 chinesebear modified for loongson 1c 16 */ 17 18 #include <rtthread.h> 19 #include <rthw.h> 20 #include "ls1c.h" 21 #include "ls1c_public.h" 22 23 24 #define MAX_INTR (LS1C_NR_IRQS) 25 26 extern rt_uint32_t rt_interrupt_nest; 27 rt_uint32_t rt_interrupt_from_thread; 28 rt_uint32_t rt_interrupt_to_thread; 29 rt_uint32_t rt_thread_switch_interrupt_flag; 30 31 static struct rt_irq_desc irq_handle_table[MAX_INTR]; 32 void rt_interrupt_dispatch(void *ptreg); 33 void rt_hw_timer_handler(); 34 35 static struct ls1c_intc_regs volatile *ls1c_hw0_icregs 36 = (struct ls1c_intc_regs volatile *)(LS1C_INTREG_BASE); 37 38 /** 39 * @addtogroup Loongson LS1B 40 */ 41 42 /*@{*/ 43 44 static void rt_hw_interrupt_handler(int vector, void *param) 45 { 46 rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); 47 } 48 49 /** 50 * This function will initialize hardware interrupt 51 */ 52 void rt_hw_interrupt_init(void) 53 { 54 rt_int32_t idx; 55 rt_int32_t i; 56 rt_uint32_t c0_status = 0; 57 58 // ����Э������0��״̬�Ĵ���SR��IM7-2�������ж� 59 c0_status = read_c0_status(); 60 c0_status |= 0xFC00; 61 write_c0_status(c0_status); 62 63 // ��о1c���жϷ�Ϊ���� 64 for (i=0; i<5; i++) 65 { 66 /* disable */ 67 (ls1c_hw0_icregs+i)->int_en = 0x0; 68 /* pci active low */ 69 (ls1c_hw0_icregs+i)->int_pol = -1; //must be done here 20110802 lgnq 70 /* make all interrupts level triggered */ 71 (ls1c_hw0_icregs+i)->int_edge = 0x00000000; 72 /* mask all interrupts */ 73 (ls1c_hw0_icregs+i)->int_clr = 0xffffffff; 74 } 75 76 rt_memset(irq_handle_table, 0x00, sizeof(irq_handle_table)); 77 for (idx = 0; idx < MAX_INTR; idx ++) 78 { 79 irq_handle_table[idx].handler = rt_hw_interrupt_handler; 80 } 81 82 /* init interrupt nest, and context in thread sp */ 83 rt_interrupt_nest = 0; 84 rt_interrupt_from_thread = 0; 85 rt_interrupt_to_thread = 0; 86 rt_thread_switch_interrupt_flag = 0; 87 } 88 89 /** 90 * This function will mask a interrupt. 91 * @param vector the interrupt number 92 */ 93 void rt_hw_interrupt_mask(int vector) 94 { 95 /* mask interrupt */ 96 (ls1c_hw0_icregs+(vector>>5))->int_en &= ~(1 << (vector&0x1f)); 97 } 98 99 /** 100 * This function will un-mask a interrupt. 101 * @param vector the interrupt number 102 */ 103 void rt_hw_interrupt_umask(int vector) 104 { 105 (ls1c_hw0_icregs+(vector>>5))->int_en |= (1 << (vector&0x1f)); 106 } 107 108 /** 109 * This function will install a interrupt service routine to a interrupt. 110 * @param vector the interrupt number 111 * @param new_handler the interrupt service routine to be installed 112 * @param old_handler the old interrupt service routine 113 */ 114 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, 115 void *param, const char *name) 116 { 117 rt_isr_handler_t old_handler = RT_NULL; 118 119 if (vector >= 0 && vector < MAX_INTR) 120 { 121 old_handler = irq_handle_table[vector].handler; 122 123 #ifdef RT_USING_INTERRUPT_INFO 124 rt_strncpy(irq_handle_table[vector].name, name, RT_NAME_MAX); 125 #endif /* RT_USING_INTERRUPT_INFO */ 126 irq_handle_table[vector].handler = handler; 127 irq_handle_table[vector].param = param; 128 } 129 130 return old_handler; 131 } 132 133 134 /** 135 * ִ���жϴ����� 136 * @IRQn �жϺ� 137 */ 138 void ls1c_do_IRQ(int IRQn) 139 { 140 rt_isr_handler_t irq_func; 141 void *param; 142 143 // �ҵ��жϴ����� 144 irq_func = irq_handle_table[IRQn].handler; 145 param = irq_handle_table[IRQn].param; 146 147 // ִ���жϴ����� 148 irq_func(IRQn, param); 149 150 #ifdef RT_USING_INTERRUPT_INFO 151 irq_handle_table[IRQn].counter++; 152 #endif 153 154 return ; 155 } 156 157 158 void ls1c_irq_dispatch(int n) 159 { 160 rt_uint32_t intstatus, irq; 161 162 /* Receive interrupt signal, compute the irq */ 163 intstatus = (ls1c_hw0_icregs+n)->int_isr & (ls1c_hw0_icregs+n)->int_en; 164 if (0 == intstatus) 165 return ; 166 167 // ִ���жϴ����� 168 irq = ls1c_ffs(intstatus) - 1; 169 ls1c_do_IRQ((n<<5) + irq); 170 171 /* ack interrupt */ 172 (ls1c_hw0_icregs+n)->int_clr |= (1 << irq); 173 174 return ; 175 } 176 177 178 void rt_interrupt_dispatch(void *ptreg) 179 { 180 int irq; 181 void *param; 182 rt_isr_handler_t irq_func; 183 static rt_uint32_t status = 0; 184 rt_uint32_t c0_status; 185 rt_uint32_t c0_cause; 186 volatile rt_uint32_t cause_im; 187 volatile rt_uint32_t status_im; 188 rt_uint32_t pending_im; 189 190 /* check os timer */ 191 c0_status = read_c0_status(); 192 c0_cause = read_c0_cause(); 193 194 cause_im = c0_cause & ST0_IM; 195 status_im = c0_status & ST0_IM; 196 pending_im = cause_im & status_im; 197 198 if (pending_im & CAUSEF_IP7) 199 { 200 rt_hw_timer_handler(); 201 } 202 else if (pending_im & CAUSEF_IP2) 203 { 204 ls1c_irq_dispatch(0); 205 } 206 else if (pending_im & CAUSEF_IP3) 207 { 208 ls1c_irq_dispatch(1); 209 } 210 else if (pending_im & CAUSEF_IP4) 211 { 212 ls1c_irq_dispatch(2); 213 } 214 else if (pending_im & CAUSEF_IP5) 215 { 216 ls1c_irq_dispatch(3); 217 } 218 else if (pending_im & CAUSEF_IP6) 219 { 220 ls1c_irq_dispatch(4); 221 } 222 } 223 224 /*@}*/ 225 226 227