clear SBSS section
[libogc.git] / libogc / irq.c
blob83c979f38d399a168ed26f8a7187ba20aab01427
1 /*-------------------------------------------------------------
3 irq.h -- Interrupt subsystem
5 Copyright (C) 2004
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any
11 damages arising from the use of this software.
13 Permission is granted to anyone to use this software for any
14 purpose, including commercial applications, and to alter it and
15 redistribute it freely, subject to the following restrictions:
17 1. The origin of this software must not be misrepresented; you
18 must not claim that you wrote the original software. If you use
19 this software in a product, an acknowledgment in the product
20 documentation would be appreciated but is not required.
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
25 3. This notice may not be removed or altered from any source
26 distribution.
28 -------------------------------------------------------------*/
31 #include <stdlib.h>
32 #include <string.h>
33 #include "asm.h"
34 #include "cache.h"
35 #include "context.h"
36 #include "processor.h"
37 #include "lwp_threads.h"
38 #include "irq.h"
39 #include "console.h"
41 //#define _IRQ_DEBUG
43 #define CPU_STACK_ALIGNMENT 8
44 #define CPU_MINIMUM_STACK_FRAME_SIZE 16
46 #define _SHIFTL(v, s, w) \
47 ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
48 #define _SHIFTR(v, s, w) \
49 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
51 struct irq_handler_s {
52 raw_irq_handler_t pHndl;
53 void *pCtx;
56 static u64 spuriousIrq = 0;
57 static u32 prevIrqMask = 0;
58 static u32 currIrqMask = 0;
59 static struct irq_handler_s g_IRQHandler[32];
61 static vu32* const _piReg = (u32*)0xCC003000;
62 static vu16* const _memReg = (u16*)0xCC004000;
63 static vu16* const _dspReg = (u16*)0xCC005000;
65 #if defined(HW_DOL)
66 static vu32* const _exiReg = (u32*)0xCC006800;
67 static vu32* const _aiReg = (u32*)0xCC006C00;
68 #elif defined(HW_RVL)
69 static vu32* const _exiReg = (u32*)0xCD006800;
70 static vu32* const _aiReg = (u32*)0xCD006C00;
71 #endif
73 static u32 const _irqPrio[] = {IM_PI_ERROR,IM_PI_DEBUG,IM_MEM,IM_PI_RSW,
74 IM_PI_VI,(IM_PI_PETOKEN|IM_PI_PEFINISH),
75 IM_PI_HSP,
76 (IM_DSP_ARAM|IM_DSP_DSP|IM_AI|IM_EXI|IM_PI_SI|IM_PI_DI),
77 IM_DSP_AI,IM_PI_CP,
78 #if defined(HW_RVL)
79 IM_PI_ACR,
80 #endif
81 0xffffffff};
83 extern void __exception_load(u32,void *,u32,void *);
85 extern s8 irqhandler_start[],irqhandler_end[];
86 extern u8 __intrstack_addr[],__intrstack_end[];
88 #ifdef _IRQ_DEBUG
89 #include <lwp_threads.h>
91 static void __irq_printHex(u32 num,u8 *buf)
93 s32 i;
94 u8 ac,*ptr = buf;
96 for(i=0;i<8;i++) {
97 ac = (u8)((num >> (28 - (i << 2))) & 0xF);
98 if (ac > 9) ac += ('A' - '0' - 10);
99 ac += '0';
100 *ptr++ = ac;
102 *ptr = 0;
105 static void __irq_dump(u32 irqmask,u32 irq_idx)
107 s32 len;
108 u8 cpStr[256];
109 static u32 irqidx = 0;
110 static u32 imask = 0;
112 if((irqmask!=imask || irqidx!=irq_idx)) {
113 strcpy(cpStr,"irqmask = ");
115 len = strlen(cpStr);
116 __irq_printHex(irqmask,&cpStr[len]);
117 strcat(cpStr," irq_idx = ");
119 len = strlen(cpStr);
120 __irq_printHex(irq_idx,&cpStr[len]);
121 strcat(cpStr,"\n");
123 __console_write(NULL,0,cpStr,strlen(cpStr));
124 irqidx = irq_idx;
125 imask = irqmask;
128 #endif
130 void c_irqdispatcher(frame_context *ctx)
132 u32 i,icause,intmask,irq = 0;
133 u32 cause,mask;
135 cause = _piReg[0]&~0x10000;
136 mask = _piReg[1];
138 if(!cause || !(cause&mask)) {
139 spuriousIrq++;
140 return;
143 intmask = 0;
144 if(cause&0x00000080) { //Memory Interface
145 icause = _memReg[15];
146 if(icause&0x00000001) {
147 intmask |= IRQMASK(IRQ_MEM0);
149 if(icause&0x00000002) {
150 intmask |= IRQMASK(IRQ_MEM1);
152 if(icause&0x00000004) {
153 intmask |= IRQMASK(IRQ_MEM2);
155 if(icause&0x00000008) {
156 intmask |= IRQMASK(IRQ_MEM3);
158 if(icause&0x00000010) {
159 intmask |= IRQMASK(IRQ_MEMADDRESS);
162 if(cause&0x00000040) { //DSP
163 icause = _dspReg[5];
164 if(icause&0x00000008){
165 intmask |= IRQMASK(IRQ_DSP_AI);
167 if(icause&0x00000020){
168 intmask |= IRQMASK(IRQ_DSP_ARAM);
170 if(icause&0x00000080){
171 intmask |= IRQMASK(IRQ_DSP_DSP);
174 if(cause&0x00000020) { //Streaming
175 icause = _aiReg[0];
176 if(icause&0x00000008) {
177 intmask |= IRQMASK(IRQ_AI);
180 if(cause&0x00000010) { //EXI
181 //EXI 0
182 icause = _exiReg[0];
183 if(icause&0x00000002) {
184 intmask |= IRQMASK(IRQ_EXI0_EXI);
186 if(icause&0x00000008) {
187 intmask |= IRQMASK(IRQ_EXI0_TC);
189 if(icause&0x00000800) {
190 intmask |= IRQMASK(IRQ_EXI0_EXT);
192 //EXI 1
193 icause = _exiReg[5];
194 if(icause&0x00000002) {
195 intmask |= IRQMASK(IRQ_EXI1_EXI);
197 if(icause&0x00000008) {
198 intmask |= IRQMASK(IRQ_EXI1_TC);
200 if(icause&0x00000800) {
201 intmask |= IRQMASK(IRQ_EXI1_EXT);
203 //EXI 2
204 icause = _exiReg[10];
205 if(icause&0x00000002) {
206 intmask |= IRQMASK(IRQ_EXI2_EXI);
208 if(icause&0x00000008) {
209 intmask |= IRQMASK(IRQ_EXI2_TC);
212 if(cause&0x00002000) { //High Speed Port
213 intmask |= IRQMASK(IRQ_PI_HSP);
215 if(cause&0x00001000) { //External Debugger
216 intmask |= IRQMASK(IRQ_PI_DEBUG);
218 if(cause&0x00000400) { //Frame Ready (PE_FINISH)
219 intmask |= IRQMASK(IRQ_PI_PEFINISH);
221 if(cause&0x00000200) { //Token Assertion (PE_TOKEN)
222 intmask |= IRQMASK(IRQ_PI_PETOKEN);
224 if(cause&0x00000100) { //Video Interface
225 intmask |= IRQMASK(IRQ_PI_VI);
227 if(cause&0x00000008) { //Serial
228 intmask |= IRQMASK(IRQ_PI_SI);
230 if(cause&0x00000004) { //DVD
231 intmask |= IRQMASK(IRQ_PI_DI);
233 if(cause&0x00000002) { //Reset Switch
234 intmask |= IRQMASK(IRQ_PI_RSW);
236 if(cause&0x00000800) { //Command FIFO
237 intmask |= IRQMASK(IRQ_PI_CP);
239 if(cause&0x00000001) { //GP Runtime Error
240 intmask |= IRQMASK(IRQ_PI_ERROR);
242 #if defined(HW_RVL)
243 if(cause&0x00004000) {
244 intmask |= IRQMASK(IRQ_PI_ACR);
246 #endif
247 mask = intmask&~(prevIrqMask|currIrqMask);
248 if(mask) {
249 i=0;
250 irq = 0;
251 while(i<(sizeof(_irqPrio)/sizeof(u32))) {
252 if((irq=(mask&_irqPrio[i]))) {
253 irq = cntlzw(irq);
254 break;
256 i++;
259 if(g_IRQHandler[irq].pHndl) g_IRQHandler[irq].pHndl(irq,g_IRQHandler[irq].pCtx);
261 #ifdef _IRQ_DEBUG
262 __irq_dump(mask,irq);
263 #endif
267 static u32 __SetInterrupts(u32 iMask,u32 nMask)
269 u32 imask;
270 u32 irq;
272 irq = cntlzw(iMask);
273 if(irq<=IRQ_MEMADDRESS) {
274 imask = 0;
275 if(!(nMask&IM_MEM0)) imask |= 0x0001;
276 if(!(nMask&IM_MEM1)) imask |= 0x0002;
277 if(!(nMask&IM_MEM2)) imask |= 0x0004;
278 if(!(nMask&IM_MEM3)) imask |= 0x0008;
279 if(!(nMask&IM_MEMADDRESS)) imask |= 0x0010;
280 _memReg[14] = (u16)imask;
281 return (iMask&~IM_MEM);
284 if(irq>=IRQ_DSP_AI && irq<=IRQ_DSP_DSP) {
285 imask = _dspReg[5]&~0x1f8;
286 if(!(nMask&IM_DSP_AI)) imask |= 0x0010;
287 if(!(nMask&IM_DSP_ARAM)) imask |= 0x0040;
288 if(!(nMask&IM_DSP_DSP)) imask |= 0x0100;
289 _dspReg[5] = (u16)imask;
290 return (iMask&~IM_DSP);
293 if(irq==IRQ_AI) {
294 imask = _aiReg[0]&~0x2c;
295 if(!(nMask&IM_AI)) imask |= 0x0004;
296 _aiReg[0] = imask;
297 return (iMask&~IM_AI);
299 if(irq>=IRQ_EXI0_EXI && irq<=IRQ_EXI0_EXT) {
300 imask = _exiReg[0]&~0x2c0f;
301 if(!(nMask&IM_EXI0_EXI)) imask |= 0x0001;
302 if(!(nMask&IM_EXI0_TC)) imask |= 0x0004;
303 if(!(nMask&IM_EXI0_EXT)) imask |= 0x0400;
304 _exiReg[0] = imask;
305 return (iMask&~IM_EXI0);
308 if(irq>=IRQ_EXI1_EXI && irq<=IRQ_EXI1_EXT) {
309 imask = _exiReg[5]&~0x0c0f;
310 if(!(nMask&IM_EXI1_EXI)) imask |= 0x0001;
311 if(!(nMask&IM_EXI1_TC)) imask |= 0x0004;
312 if(!(nMask&IM_EXI1_EXT)) imask |= 0x0400;
313 _exiReg[5] = imask;
314 return (iMask&~IM_EXI1);
317 if(irq>=IRQ_EXI2_EXI && irq<=IRQ_EXI2_TC) {
318 imask = _exiReg[10]&~0x000f;
319 if(!(nMask&IM_EXI2_EXI)) imask |= 0x0001;
320 if(!(nMask&IM_EXI2_TC)) imask |= 0x0004;
321 _exiReg[10] = imask;
322 return (iMask&~IM_EXI2);
325 #if defined(HW_DOL)
326 if(irq>=IRQ_PI_CP && irq<=IRQ_PI_HSP) {
327 #elif defined(HW_RVL)
328 if(irq>=IRQ_PI_CP && irq<=IRQ_PI_ACR) {
329 #endif
330 imask = 0xf0;
331 if(!(nMask&IM_PI_ERROR)) {
332 imask |= 0x00000001;
334 if(!(nMask&IM_PI_RSW)) {
335 imask |= 0x00000002;
337 if(!(nMask&IM_PI_DI)) {
338 imask |= 0x00000004;
340 if(!(nMask&IM_PI_SI)) {
341 imask |= 0x00000008;
343 if(!(nMask&IM_PI_VI)) {
344 imask |= 0x00000100;
346 if(!(nMask&IM_PI_PETOKEN)) {
347 imask |= 0x00000200;
349 if(!(nMask&IM_PI_PEFINISH)) {
350 imask |= 0x00000400;
352 if(!(nMask&IM_PI_CP)) {
353 imask |= 0x00000800;
355 if(!(nMask&IM_PI_DEBUG)) {
356 imask |= 0x00001000;
358 if(!(nMask&IM_PI_HSP)) {
359 imask |= 0x00002000;
361 #if defined(HW_RVL)
362 if(!(nMask&IM_PI_ACR)) {
363 imask |= 0x00004000;
365 #endif
366 _piReg[1] = imask;
367 return (iMask&~IM_PI);
369 return 0;
372 void __UnmaskIrq(u32 nMask)
374 u32 level;
375 u32 mask;
377 _CPU_ISR_Disable(level);
378 mask = (nMask&(prevIrqMask|currIrqMask));
379 nMask = (prevIrqMask&~nMask);
380 prevIrqMask = nMask;
381 while((mask=__SetInterrupts(mask,(nMask|currIrqMask)))!=0);
382 _CPU_ISR_Restore(level);
385 void __MaskIrq(u32 nMask)
387 u32 level;
388 u32 mask;
390 _CPU_ISR_Disable(level);
391 mask = (nMask&~(prevIrqMask|currIrqMask));
392 nMask = (nMask|prevIrqMask);
393 prevIrqMask = nMask;
394 while((mask=__SetInterrupts(mask,(nMask|currIrqMask)))!=0);
395 _CPU_ISR_Restore(level);
398 void __irq_init()
400 register u32 intrStack = (u32)__intrstack_addr;
401 register u32 intrStack_end = (u32)__intrstack_end;
402 register u32 irqNestingLevel = 0;
404 memset(g_IRQHandler,0,32*sizeof(struct irq_handler_s));
406 *((u32*)intrStack_end) = 0xDEADBEEF;
407 intrStack = intrStack - CPU_MINIMUM_STACK_FRAME_SIZE;
408 intrStack &= ~(CPU_STACK_ALIGNMENT-1);
409 *((u32*)intrStack) = 0;
411 mtspr(272,irqNestingLevel);
412 mtspr(273,intrStack);
414 prevIrqMask = 0;
415 currIrqMask = 0;
416 _piReg[1] = 0xf0;
418 __MaskIrq(-32);
420 _piReg[0] = 0x01;
421 __UnmaskIrq(IM_PI_ERROR);
424 raw_irq_handler_t IRQ_Request(u32 nIrq,raw_irq_handler_t pHndl,void *pCtx)
426 u32 level;
428 _CPU_ISR_Disable(level);
429 raw_irq_handler_t old = g_IRQHandler[nIrq].pHndl;
430 g_IRQHandler[nIrq].pHndl = pHndl;
431 g_IRQHandler[nIrq].pCtx = pCtx;
432 _CPU_ISR_Restore(level);
433 return old;
436 raw_irq_handler_t IRQ_GetHandler(u32 nIrq)
438 u32 level;
439 raw_irq_handler_t ret;
441 _CPU_ISR_Disable(level);
442 ret = g_IRQHandler[nIrq].pHndl;
443 _CPU_ISR_Restore(level);
444 return ret;
447 raw_irq_handler_t IRQ_Free(u32 nIrq)
449 u32 level;
451 _CPU_ISR_Disable(level);
452 raw_irq_handler_t old = g_IRQHandler[nIrq].pHndl;
453 g_IRQHandler[nIrq].pHndl = NULL;
454 g_IRQHandler[nIrq].pCtx = NULL;
455 _CPU_ISR_Restore(level);
456 return old;
459 u32 IRQ_Disable()
461 u32 level;
462 _CPU_ISR_Disable(level);
463 return level;
466 void IRQ_Restore(u32 level)
468 _CPU_ISR_Restore(level);