1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - libraries - OS
3   File:     os_interrupt.c
4 
5   Copyright 2003-2008 Nintendo.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-11-06#$
14   $Rev: 9229 $
15   $Author: yada $
16 
17  *---------------------------------------------------------------------------*/
18 #include <nitro/hw/common/armArch.h>
19 
20 #ifdef SDK_NITRO
21 #include        <nitro/os/common/interrupt.h>
22 #else
23 #include        <twl/os/common/interrupt.h>
24 #endif
25 
26 #include <nitro/os/common/system.h>
27 
28 /*---------------------------------------------------------------------------*
29   Name:         OS_InitIrqTable
30 
31   Description:  initialize IRQ handler table
32 
33   Arguments:    None
34 
35   Returns:      None
36  *---------------------------------------------------------------------------*/
37 extern OSThreadQueue OSi_IrqThreadQueue;
38 
OS_InitIrqTable(void)39 void OS_InitIrqTable(void)
40 {
41     //---- initialize thread queue for irq
42     OS_InitThreadQueue(&OSi_IrqThreadQueue);
43 
44 #ifdef SDK_ARM7
45     //---- clear VBlank counter
46     OSi_SetVBlankCount(0);
47 #endif
48 }
49 
50 /*---------------------------------------------------------------------------*
51   Name:         OS_SetIrqFunction
52 
53   Description:  set IRQ handler function
54 
55   Arguments:    intrBit         IRQ mask bit
56                 function        funtion to set
57 
58   Returns:      None
59  *---------------------------------------------------------------------------*/
OS_SetIrqFunction(OSIrqMask intrBit,OSIrqFunction function)60 void OS_SetIrqFunction(OSIrqMask intrBit, OSIrqFunction function)
61 {
62     int     i;
63     OSIrqCallbackInfo *info;
64 
65     for (i = 0; i < OS_IRQ_TABLE_MAX; i++)
66     {
67         if (intrBit & 1)
68         {
69             info = NULL;
70 
71             // ---- if dma(0-3)
72             if (REG_OS_IE_D0_SHIFT <= i && i <= REG_OS_IE_D3_SHIFT)
73             {
74                 info = &OSi_IrqCallbackInfo[i - REG_OS_IE_D0_SHIFT];
75             }
76 #ifdef SDK_TWL
77 			// ---- if new dma(0-3)
78 			else if (REG_OS_IE_ND0_SHIFT <= i && i <= REG_OS_IE_ND3_SHIFT)
79 			{
80 				info = &OSi_IrqCallbackInfo[i - REG_OS_IE_ND0_SHIFT + OSi_IRQCALLBACK_NO_NDMA0];
81 			}
82 #endif
83             // ---- if timer(0-3)
84             else if (REG_OS_IE_T0_SHIFT <= i && i <= REG_OS_IE_T3_SHIFT)
85             {
86                 info = &OSi_IrqCallbackInfo[i - REG_OS_IE_T0_SHIFT + OSi_IRQCALLBACK_NO_TIMER0];
87             }
88 #ifdef SDK_ARM7
89             // ---- if vblank
90             else if (REG_OS_IE_VB_SHIFT == i)
91             {
92                 info = &OSi_IrqCallbackInfo[OSi_IRQCALLBACK_NO_VBLANK];
93             }
94 #endif
95             //---- other interrupt
96             else
97             {
98                 OS_IRQTable[i] = function;
99             }
100 
101             if (info)
102             {
103                 info->func = (void (*)(void *))function;
104                 info->arg = 0;
105                 info->enable = TRUE;
106             }
107 
108         }
109         intrBit >>= 1;
110     }
111 }
112 
113 #if defined(SDK_TWL) && defined(SDK_ARM7)
OS_SetIrqFunctionEx(OSIrqMask intrBit,OSIrqFunction function)114 void OS_SetIrqFunctionEx(OSIrqMask intrBit, OSIrqFunction function)
115 {
116     int     		   i;
117     OSIrqCallbackInfo *info = NULL;
118 
119     for (i = 0; i < OS_IRQ_TABLE2_MAX; i++)
120     {
121         if (intrBit & 1)
122         {
123             info = NULL;
124 			OS_IRQTable2[i] = function;
125 
126             if (info)
127             {
128                 info->func = (void (*)(void *))function;
129                 info->arg = 0;
130                 info->enable = TRUE;
131             }
132 
133         }
134         intrBit >>= 1;
135     }
136 }
137 #endif // defined(SDK_TWL) && defined(SDK_ARM7)
138 
139 /*---------------------------------------------------------------------------*
140   Name:         OS_GetIrqFunction
141 
142   Description:  get IRQ handler function
143 
144   Arguments:    intrBit         IRQ mask bit
145 
146   Returns:      None
147  *---------------------------------------------------------------------------*/
OS_GetIrqFunction(OSIrqMask intrBit)148 OSIrqFunction OS_GetIrqFunction(OSIrqMask intrBit)
149 {
150     int     i;
151     OSIrqFunction *funcPtr = &OS_IRQTable[0];
152 
153     for (i = 0; i < OS_IRQ_TABLE_MAX; i++)
154     {
155         if (intrBit & 1)
156         {
157             //---- if dma(0-3)
158             if (REG_OS_IE_D0_SHIFT <= i && i <= REG_OS_IE_D3_SHIFT)
159             {
160                 return (void (*)(void))OSi_IrqCallbackInfo[i - REG_OS_IE_D0_SHIFT].func;
161             }
162 #ifdef TWL_SDK
163             //---- if ndma(0-3)
164             else if (REG_OS_IE_ND0_SHIFT <= i && i <= REG_OS_IE_ND3_SHIFT)
165             {
166                 return (void (*)(void))OSi_IrqCallbackInfo[i - REG_OS_IE_D0_SHIFT +
167                                                            OSi_IRQCALLBACK_NO_NDMA0].func;
168             }
169 #endif
170             //---- if timer(0-3)
171             else if (REG_OS_IE_T0_SHIFT <= i && i <= REG_OS_IE_T3_SHIFT)
172             {
173                 return (void (*)(void))OSi_IrqCallbackInfo[i - REG_OS_IE_T0_SHIFT +
174                                                            OSi_IRQCALLBACK_NO_TIMER0].func;
175             }
176 #ifdef SDK_ARM7
177             else if (REG_OS_IE_VB_SHIFT == i)
178             {
179                 return (void (*)(void))OSi_IrqCallbackInfo[OSi_IRQCALLBACK_NO_VBLANK].func;
180             }
181 #endif
182 
183             //---- other interrupt
184             return *funcPtr;
185         }
186         intrBit >>= 1;
187         funcPtr++;
188     }
189     return 0;
190 }
191 
192 #if defined(SDK_TWL) && defined(SDK_ARM7)
OS_GetIrqFunctionEx(OSIrqMask intrBit)193 OSIrqFunction OS_GetIrqFunctionEx(OSIrqMask intrBit)
194 {
195     int     i;
196     OSIrqFunction *funcPtr = &OS_IRQTable2[0]; // skip IE part
197 
198     for (i = 0; i < OS_IRQ_TABLE2_MAX; i++)
199     {
200         if (intrBit & 1)
201         {
202             return *funcPtr;
203         }
204         intrBit >>= 1;
205         funcPtr++;
206     }
207     return 0;
208 }
209 #endif // defined(SDK_TWL) && defined(SDK_ARM7)
210 
211 
212 /*---------------------------------------------------------------------------*
213   Name:         OSi_EnterDmaCallback
214 
215   Description:  enter dma callback handler and arg
216 
217   Arguments:    dmaNo       dma number to set callback
218                 callback    callback for dma interrupt
219                 arg         its argument
220 
221   Returns:      None
222  *---------------------------------------------------------------------------*/
OSi_EnterDmaCallback(u32 dmaNo,void (* callback)(void *),void * arg)223 void OSi_EnterDmaCallback(u32 dmaNo, void (*callback) (void *), void *arg)
224 {
225     OSIrqMask imask = (1UL << (REG_OS_IE_D0_SHIFT + dmaNo));
226 
227     //---- enter callback
228     OSi_IrqCallbackInfo[dmaNo].func = callback;
229     OSi_IrqCallbackInfo[dmaNo].arg = arg;
230 
231     //---- remember IRQ mask bit
232     OSi_IrqCallbackInfo[dmaNo].enable = OS_EnableIrqMask(imask) & imask;
233 }
234 
235 /*---------------------------------------------------------------------------*
236   Name:         OSi_EnterNDmaCallback
237 
238   Description:  enter new dma callback handler and arg
239 
240   Arguments:    dmaNo       dma number to set callback
241                 callback    callback for dma interrupt
242                 arg         its argument
243 
244   Returns:      None
245  *---------------------------------------------------------------------------*/
246 #ifdef SDK_TWL
247 #include <twl/ltdmain_begin.h>
248 static void OSi_EnterNDmaCallback_ltdmain(u32 dmaNo, void (*callback) (void *), void *arg);
OSi_EnterNDmaCallback_ltdmain(u32 dmaNo,void (* callback)(void *),void * arg)249 static void OSi_EnterNDmaCallback_ltdmain(u32 dmaNo, void (*callback) (void *), void *arg)
250 {
251     OSIrqMask imask = (1UL << (REG_OS_IE_ND0_SHIFT + dmaNo));
252 
253     //---- enter callback
254     OSi_IrqCallbackInfo[dmaNo + OSi_IRQCALLBACK_NO_NDMA0].func = callback;
255     OSi_IrqCallbackInfo[dmaNo + OSi_IRQCALLBACK_NO_NDMA0].arg = arg;
256 
257     //---- remember IRQ mask bit
258     OSi_IrqCallbackInfo[dmaNo + OSi_IRQCALLBACK_NO_NDMA0].enable = OS_EnableIrqMask(imask) & imask;
259 }
260 #include <twl/ltdmain_end.h>
261 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OSi_EnterNDmaCallback(u32 dmaNo,void (* callback)(void *),void * arg)262 void OSi_EnterNDmaCallback(u32 dmaNo, void (*callback) (void *), void *arg)
263 {
264     OSi_EnterNDmaCallback_ltdmain(dmaNo, callback, arg);
265 }
266 #endif
267 
268 /*---------------------------------------------------------------------------*
269   Name:         OSi_EnterTimerCallback
270 
271   Description:  enter timer callback handler and arg
272 
273   Arguments:    timerNo     timer number to set callback
274                 callback    callback for timer interrupt
275                 arg         its argument
276 
277   Returns:      None
278  *---------------------------------------------------------------------------*/
OSi_EnterTimerCallback(u32 timerNo,void (* callback)(void *),void * arg)279 void OSi_EnterTimerCallback(u32 timerNo, void (*callback) (void *), void *arg)
280 {
281     OSIrqMask imask = (1UL << (REG_OS_IE_T0_SHIFT + timerNo));
282 
283     //---- enter callback
284     OSi_IrqCallbackInfo[timerNo + OSi_IRQCALLBACK_NO_TIMER0].func = callback;
285     OSi_IrqCallbackInfo[timerNo + OSi_IRQCALLBACK_NO_TIMER0].arg = arg;
286 
287     //---- remember IRQ mask bit (force to be ENABLE)
288     (void)OS_EnableIrqMask(imask);
289     OSi_IrqCallbackInfo[timerNo + OSi_IRQCALLBACK_NO_TIMER0].enable = TRUE;
290 }
291 
292 #if defined(SDK_TCM_APPLY) && defined(SDK_ARM9)
293 #include    <nitro/itcm_begin.h>
294 #endif
295 //================================================================================
296 //         IrqMask
297 //================================================================================
298 /*---------------------------------------------------------------------------*
299   Name:         OS_SetIrqMask
300 
301   Description:  set irq factor
302 
303   Arguments:    intr        irq factor
304 
305   Returns:      previous factors
306  *---------------------------------------------------------------------------*/
OS_SetIrqMask(OSIrqMask intr)307 OSIrqMask OS_SetIrqMask(OSIrqMask intr)
308 {
309     BOOL    ime = OS_DisableIrq();     // IME disable
310     OSIrqMask prep = reg_OS_IE;
311     reg_OS_IE = intr;
312     (void)OS_RestoreIrq(ime);
313     return prep;
314 }
315 
316 
317 #if defined(SDK_TWL) && defined(SDK_ARM7)
OS_SetIrqMaskEx(OSIrqMask intr)318 OSIrqMask OS_SetIrqMaskEx(OSIrqMask intr)
319 {
320     BOOL    ime = OS_DisableIrq();     // IME disable
321     OSIrqMask prep = reg_OS_IE2;
322     reg_OS_IE2 = (u16)intr;
323     (void)OS_RestoreIrq(ime);
324     return prep;
325 }
326 #endif
327 
328 /*---------------------------------------------------------------------------*
329   Name:         OS_EnableIrqMask
330 
331   Description:  set specified irq factor
332 
333   Arguments:    intr        irq factor
334 
335   Returns:      previous factors
336  *---------------------------------------------------------------------------*/
OS_EnableIrqMask(OSIrqMask intr)337 OSIrqMask OS_EnableIrqMask(OSIrqMask intr)
338 {
339     BOOL    ime = OS_DisableIrq();     // IME disable
340     OSIrqMask prep = reg_OS_IE;
341     reg_OS_IE = prep | intr;
342     (void)OS_RestoreIrq(ime);
343     return prep;
344 }
345 
346 #if defined(SDK_TWL) && defined(SDK_ARM7)
OS_EnableIrqMaskEx(OSIrqMask intr)347 OSIrqMask OS_EnableIrqMaskEx(OSIrqMask intr)
348 {
349     BOOL    ime = OS_DisableIrq();     // IME disable
350     OSIrqMask prep = reg_OS_IE2;
351     reg_OS_IE2 = (u16)(prep | intr);
352     (void)OS_RestoreIrq(ime);
353     return prep;
354 }
355 #endif
356 
357 /*---------------------------------------------------------------------------*
358   Name:         OS_DisableIrqMask
359 
360   Description:  unset specified irq factor
361 
362   Arguments:    intr        irq factor
363 
364   Returns:      previous factors
365  *---------------------------------------------------------------------------*/
OS_DisableIrqMask(OSIrqMask intr)366 OSIrqMask OS_DisableIrqMask(OSIrqMask intr)
367 {
368     BOOL    ime = OS_DisableIrq();     // IME disable
369     OSIrqMask prep = reg_OS_IE;
370     reg_OS_IE = prep & ~intr;
371     (void)OS_RestoreIrq(ime);
372     return prep;
373 }
374 
375 #if defined(SDK_TWL) & defined(SDK_ARM7)
OS_DisableIrqMaskEx(OSIrqMask intr)376 OSIrqMask OS_DisableIrqMaskEx(OSIrqMask intr)
377 {
378     BOOL    ime = OS_DisableIrq();     // IME disable
379     OSIrqMask prep = reg_OS_IE2;
380     reg_OS_IE2 = (u16)(prep & ~intr);
381     (void)OS_RestoreIrq(ime);
382     return prep;
383 }
384 #endif
385 
386 /*---------------------------------------------------------------------------*
387   Name:         OS_ResetRequestIrqMask
388 
389   Description:  reset IF bit
390                 (setting bit causes to clear bit for interrupt)
391 
392   Arguments:    intr        irq factor
393 
394   Returns:      previous factors
395  *---------------------------------------------------------------------------*/
OS_ResetRequestIrqMask(OSIrqMask intr)396 OSIrqMask OS_ResetRequestIrqMask(OSIrqMask intr)
397 {
398     BOOL    ime = OS_DisableIrq();     // IME disable
399     OSIrqMask prep = reg_OS_IF;
400     reg_OS_IF = intr;
401     (void)OS_RestoreIrq(ime);
402     return prep;
403 }
404 
405 #if defined(SDK_TWL) && defined(SDK_ARM7)
OS_ResetRequestIrqMaskEx(OSIrqMask intr)406 OSIrqMask OS_ResetRequestIrqMaskEx(OSIrqMask intr)
407 {
408     BOOL    ime = OS_DisableIrq();     // IME disable
409     OSIrqMask prep = reg_OS_IF2;
410     reg_OS_IF2 = (u16)intr;
411     (void)OS_RestoreIrq(ime);
412     return prep;
413 }
414 #endif
415 
416 #if defined(SDK_TCM_APPLY) && defined(SDK_ARM9)
417 #include    <nitro/itcm_end.h>
418 #endif
419 
420 
421 
422 //================================================================================
423 //              IRQ STACK CHECKER
424 //================================================================================
425 extern unsigned long SDK_IRQ_STACKSIZE[];
426 #define OSi_IRQ_STACKSIZE               ((int)SDK_IRQ_STACKSIZE)
427 
428 //---- defs for irq stack
429 #ifdef SDK_ARM9
430 #  define  OSi_IRQ_STACK_TOP                (HW_DTCM_SVC_STACK - ((s32)SDK_IRQ_STACKSIZE))
431 #  define  OSi_IRQ_STACK_BOTTOM             HW_DTCM_SVC_STACK
432 #else
433 #  define  OSi_IRQ_STACK_TOP                (HW_PRV_WRAM_IRQ_STACK_END - ((s32)SDK_IRQ_STACKSIZE))
434 #  define  OSi_IRQ_STACK_BOTTOM             HW_PRV_WRAM_IRQ_STACK_END
435 #endif
436 
437 //---- Stack CheckNumber
438 #ifdef SDK_ARM9
439 #  define  OSi_IRQ_STACK_CHECKNUM_BOTTOM     0xfddb597dUL
440 #  define  OSi_IRQ_STACK_CHECKNUM_TOP        0x7bf9dd5bUL
441 #  define  OSi_IRQ_STACK_CHECKNUM_WARN       0x597dfbd9UL
442 #else
443 #  define  OSi_IRQ_STACK_CHECKNUM_BOTTOM     0xd73bfdf7UL
444 #  define  OSi_IRQ_STACK_CHECKNUM_TOP        0xfbdd37bbUL
445 #  define  OSi_IRQ_STACK_CHECKNUM_WARN       0xbdf7db3dUL
446 #endif
447 
448 static u32 OSi_IrqStackWarningOffset = 0;
449 
450 /*---------------------------------------------------------------------------*
451   Name:         OS_SetIrqStackChecker
452 
453   Description:  set irq stack check number to irq stack
454 
455   Arguments:    None
456 
457   Returns:      None
458  *---------------------------------------------------------------------------*/
OS_SetIrqStackChecker(void)459 void OS_SetIrqStackChecker(void)
460 {
461     *(u32 *)(OSi_IRQ_STACK_BOTTOM - sizeof(u32)) = OSi_IRQ_STACK_CHECKNUM_BOTTOM;
462     *(u32 *)(OSi_IRQ_STACK_TOP) = OSi_IRQ_STACK_CHECKNUM_TOP;
463 }
464 
465 /*---------------------------------------------------------------------------*
466   Name:         OS_SetIrqStackWarningOffset
467 
468   Description:  Set warning level for irq stack
469 
470   Arguments:    offset : offset from stack top. must be multiple of 4
471 
472   Returns:      None
473  *---------------------------------------------------------------------------*/
OS_SetIrqStackWarningOffset(u32 offset)474 void OS_SetIrqStackWarningOffset(u32 offset)
475 {
476     SDK_ASSERTMSG((offset & 3) == 0, "Offset must be aligned by 4");
477     SDK_ASSERTMSG(offset > 0, "Cannot set warning level to stack top.");
478     SDK_ASSERTMSG(offset < ((u32)SDK_IRQ_STACKSIZE), "Cannot set warning level over stack bottom.");
479 
480     //---- remember warning offset
481     OSi_IrqStackWarningOffset = offset;
482 
483     //---- set Stack CheckNum
484     if (offset != 0)
485     {
486         *(u32 *)(OSi_IRQ_STACK_TOP + offset) = OSi_IRQ_STACK_CHECKNUM_WARN;
487     }
488 }
489 
490 
491 /*---------------------------------------------------------------------------*
492   Name:         OS_GetIrqStackStatus
493 
494   Description:  check irq stack. check each CheckNUM.
495                 return result.
496 
497   Arguments:    None
498 
499   Returns:      0 (OS_STACK_NO_ERROR)        no error
500                 OS_STACK_OVERFLOW            overflow
501                 OS_STACK_ABOUT_TO_OVERFLOW   about to overflow
502                 OS_STACK_UNDERFLOW           underflow
503  *---------------------------------------------------------------------------*/
OS_GetIrqStackStatus(void)504 OSStackStatus OS_GetIrqStackStatus(void)
505 {
506     //OS_Printf("CHECK OF %x\n", (*(u32 *)(OSi_IRQ_STACK_TOP) ) );
507     //OS_Printf("CHECK AO %x\n", (*(u32 *)(OSi_IRQ_STACK_TOP + OSi_IrqStackWarningOffset) ) );
508     //OS_Printf("CHECK UF %x\n", (*(u32 *)(OSi_IRQ_STACK_BOTTOM - sizeof(u32))) );
509 
510     //OS_Printf(" - OF %x\n", OSi_IRQ_STACK_CHECKNUM_TOP);
511     //OS_Printf(" - AO %x\n", OSi_IRQ_STACK_CHECKNUM_WARN);
512     //OS_Printf(" - UF %x\n", OSi_IRQ_STACK_CHECKNUM_BOTTOM);
513 
514     //---- Check if overflow
515     if (*(u32 *)(OSi_IRQ_STACK_TOP) != OSi_IRQ_STACK_CHECKNUM_TOP)
516     {
517         return OS_STACK_OVERFLOW;
518     }
519     //---- Check if about to overflow
520     else if (OSi_IrqStackWarningOffset
521              && *(u32 *)(OSi_IRQ_STACK_TOP + OSi_IrqStackWarningOffset) !=
522              OSi_IRQ_STACK_CHECKNUM_WARN)
523     {
524         return OS_STACK_ABOUT_TO_OVERFLOW;
525     }
526     //---- Check if underFlow
527     else if (*(u32 *)(OSi_IRQ_STACK_BOTTOM - sizeof(u32)) != OSi_IRQ_STACK_CHECKNUM_BOTTOM)
528     {
529         return OS_STACK_UNDERFLOW;
530     }
531     //---- No Error, return.
532     else
533     {
534         return OS_STACK_NO_ERROR;
535     }
536 }
537 
538 /*---------------------------------------------------------------------------*
539   Name:         OSi_CheckIrqStack
540 
541   Description:  check irq stack. check each CheckNUM.
542                 if changed, display warning and halt.
543 
544   Arguments:    file     file name displayed when stack overflow
545                 line     line number displayed when stack overflow
546 
547   Returns:      None
548                 ( if error occurred, never return )
549  *---------------------------------------------------------------------------*/
550 static char *OSi_CheckIrqStack_mesg[] = {
551     "overflow", "about to overflow", "underflow"
552 };
553 
554 #ifndef SDK_FINALROM
555 #ifndef SDK_NO_MESSAGE
OSi_CheckIrqStack(char * file,int line)556 void OSi_CheckIrqStack(char *file, int line)
557 {
558     OSStackStatus st = OS_GetIrqStackStatus();
559 
560     if (st == OS_STACK_NO_ERROR)
561     {
562         return;
563     }
564 
565     OSi_Panic(file, line, "irq stack %s.\nirq stack area: %08x-%08x, warning offset: %x",
566               OSi_CheckIrqStack_mesg[(int)st - 1],
567               OSi_IRQ_STACK_TOP, OSi_IRQ_STACK_BOTTOM, OSi_IrqStackWarningOffset);
568     // Never return
569 }
570 #endif
571 #endif
572