1 /*
2 * File : cpu_intc.c
3 * This file is part of RT-Thread RTOS
4 * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Change Logs:
21 * Date Author Notes
22 * 2016/09/07 Urey the first version
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include <rtthread.h>
29 #include <rthw.h>
30 #include <board.h>
31
32 #include "../common/mips.h"
33
34 #define INTERRUPTS_MAX 64
35
36 extern rt_uint32_t rt_interrupt_nest;
37 rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
38 rt_uint32_t rt_thread_switch_interrupt_flag;
39
40 static struct rt_irq_desc isr_table[INTERRUPTS_MAX];
41
rt_hw_interrupt_handler(int vector,void * param)42 static void rt_hw_interrupt_handler(int vector, void *param)
43 {
44 rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
45 }
46
rt_hw_interrupt_init(void)47 void rt_hw_interrupt_init(void)
48 {
49 rt_int32_t idx;
50
51 clear_c0_status(0xff04); /* clear ERL */
52 set_c0_status(0x0400); /* set IP2 */
53
54
55 rt_memset(isr_table, 0x00, sizeof(isr_table));
56 for (idx = 0; idx < INTERRUPTS_MAX; idx ++)
57 {
58 isr_table[idx].handler = rt_hw_interrupt_handler;
59 }
60
61 /* init interrupt nest, and context in thread sp */
62 rt_interrupt_nest = 0;
63 rt_interrupt_from_thread = 0;
64 rt_interrupt_to_thread = 0;
65 rt_thread_switch_interrupt_flag = 0;
66
67 /* enable cpu interrupt mask */
68 set_c0_status(IE_IRQ0 | IE_IRQ1);
69 }
70
rt_hw_interrupt_mask(int vector)71 void rt_hw_interrupt_mask(int vector)
72 {
73 /* mask interrupt */
74 __intc_mask_irq(vector);
75 }
76
rt_hw_interrupt_umask(int vector)77 void rt_hw_interrupt_umask(int vector)
78 {
79 __intc_unmask_irq(vector);
80 }
81
rt_hw_interrupt_install(int vector,rt_isr_handler_t handler,void * param,const char * name)82 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
83 void *param, const char *name)
84 {
85 rt_isr_handler_t old_handler = RT_NULL;
86
87 if(vector < INTERRUPTS_MAX)
88 {
89 old_handler = isr_table[vector].handler;
90
91 #ifdef RT_USING_INTERRUPT_INFO
92 rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX);
93 #endif /* RT_USING_INTERRUPT_INFO */
94 isr_table[vector].handler = handler;
95 isr_table[vector].param = param;
96 }
97
98 return old_handler;
99 }
100
fls(int x)101 rt_inline int fls(int x)
102 {
103 __asm__("clz %0, %1" : "=r" (x) : "r" (x));
104
105 return 32 - x;
106 }
107
rt_interrupt_dispatch(void * ptreg)108 void rt_interrupt_dispatch(void *ptreg)
109 {
110 void *param;
111 rt_isr_handler_t irq_func;
112
113 int irq = 0, group;
114 rt_uint32_t intc_ipr0 = 0, intc_ipr1 = 0, vpu_pending = 0;
115
116 rt_uint32_t c0_status, c0_cause;
117 rt_uint32_t pending_im;
118
119 /* check os timer */
120 c0_status = read_c0_status();
121 c0_cause = read_c0_cause();
122
123 pending_im = (c0_cause & ST0_IM) & (c0_status & ST0_IM);
124
125 if (pending_im & CAUSEF_IP3)
126 {
127 extern void rt_hw_ost_handler(void);
128 rt_hw_ost_handler();
129 return;
130 }
131 if (pending_im & CAUSEF_IP2)
132 {
133 intc_ipr0 = REG_INTC_IPR(0);
134 intc_ipr1 = REG_INTC_IPR(1);
135
136 if (intc_ipr0)
137 {
138 irq = fls(intc_ipr0) - 1;
139 intc_ipr0 &= ~(1<<irq);
140 }
141 else if(intc_ipr1)
142 {
143 irq = fls(intc_ipr1) - 1;
144 intc_ipr1 &= ~(1<<irq);
145 irq += 32;
146 }
147 else
148 {
149 //VPU
150 }
151
152 if (irq >= INTERRUPTS_MAX)
153 rt_kprintf("max interrupt, irq=%d\n", irq);
154
155 /* do interrupt */
156 irq_func = isr_table[irq].handler;
157 param = isr_table[irq].param;
158 (*irq_func)(irq, param);
159
160 #ifdef RT_USING_INTERRUPT_INFO
161 isr_table[irq].counter++;
162 #endif /* RT_USING_INTERRUPT_INFO */
163
164 /* ack interrupt */
165 __intc_ack_irq(irq);
166 }
167
168 if (pending_im & CAUSEF_IP0)
169 rt_kprintf("CAUSEF_IP0\n");
170 if (pending_im & CAUSEF_IP1)
171 rt_kprintf("CAUSEF_IP1\n");
172 if (pending_im & CAUSEF_IP4)
173 rt_kprintf("CAUSEF_IP4\n");
174 if (pending_im & CAUSEF_IP5)
175 rt_kprintf("CAUSEF_IP5\n");
176 if (pending_im & CAUSEF_IP6)
177 rt_kprintf("CAUSEF_IP6\n");
178 if (pending_im & CAUSEF_IP7)
179 rt_kprintf("CAUSEF_IP7\n");
180 }
181
182 #ifdef RT_USING_INTERRUPT_INFO
183 #include <finsh.h>
list_irqs(void)184 int list_irqs(void)
185 {
186 int index;
187
188 rt_kprintf("interrupt list:\n");
189 rt_kprintf("----------------\n");
190 rt_kprintf("name counter\n");
191 for (index = 0; index < INTERRUPTS_MAX; index ++)
192 {
193 if (isr_table[index].handler != rt_hw_interrupt_handler)
194 {
195 rt_kprintf("%-*.*s %d\n", RT_NAME_MAX, RT_NAME_MAX, isr_table[index].name, isr_table[index].counter);
196 }
197 }
198
199 return 0;
200 }
201 MSH_CMD_EXPORT(list_irqs, list interrupt counter);
202 #endif
203
spin_lock_irqsave(void)204 unsigned int spin_lock_irqsave(void)
205 {
206 register unsigned int t;
207 t = read_c0_status();
208 write_c0_status((t & (~1)));
209 return (t);
210 }
211
spin_unlock_irqrestore(unsigned int val)212 void spin_unlock_irqrestore(unsigned int val)
213 {
214 write_c0_status(val);
215 }
216