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
rt_hw_interrupt_handler(int vector,void * param)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 */
rt_hw_interrupt_init(void)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 */
rt_hw_interrupt_mask(int vector)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 */
rt_hw_interrupt_umask(int vector)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 */
rt_hw_interrupt_install(int vector,rt_isr_handler_t handler,void * param,const char * name)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 */
ls1c_do_IRQ(int IRQn)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
ls1c_irq_dispatch(int n)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
rt_interrupt_dispatch(void * ptreg)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