1 /*-------------------------------------------------------------
3 irq.h -- Interrupt subsystem
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
28 -------------------------------------------------------------*/
36 #include "processor.h"
37 #include "lwp_threads.h"
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
;
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;
66 static vu32
* const _exiReg
= (u32
*)0xCC006800;
67 static vu32
* const _aiReg
= (u32
*)0xCC006C00;
69 static vu32
* const _exiReg
= (u32
*)0xCD006800;
70 static vu32
* const _aiReg
= (u32
*)0xCD006C00;
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
),
76 (IM_DSP_ARAM
|IM_DSP_DSP
|IM_AI
|IM_EXI
|IM_PI_SI
|IM_PI_DI
),
83 extern void __exception_load(u32
,void *,u32
,void *);
85 extern s8 irqhandler_start
[],irqhandler_end
[];
86 extern u8 __intrstack_addr
[],__intrstack_end
[];
89 #include <lwp_threads.h>
91 static void __irq_printHex(u32 num
,u8
*buf
)
97 ac
= (u8
)((num
>> (28 - (i
<< 2))) & 0xF);
98 if (ac
> 9) ac
+= ('A' - '0' - 10);
105 static void __irq_dump(u32 irqmask
,u32 irq_idx
)
109 static u32 irqidx
= 0;
110 static u32 imask
= 0;
112 if((irqmask
!=imask
|| irqidx
!=irq_idx
)) {
113 strcpy(cpStr
,"irqmask = ");
116 __irq_printHex(irqmask
,&cpStr
[len
]);
117 strcat(cpStr
," irq_idx = ");
120 __irq_printHex(irq_idx
,&cpStr
[len
]);
123 __console_write(NULL
,0,cpStr
,strlen(cpStr
));
130 void c_irqdispatcher(frame_context
*ctx
)
132 u32 i
,icause
,intmask
,irq
= 0;
135 cause
= _piReg
[0]&~0x10000;
138 if(!cause
|| !(cause
&mask
)) {
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
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
176 if(icause
&0x00000008) {
177 intmask
|= IRQMASK(IRQ_AI
);
180 if(cause
&0x00000010) { //EXI
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
);
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
);
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
);
243 if(cause
&0x00004000) {
244 intmask
|= IRQMASK(IRQ_PI_ACR
);
247 mask
= intmask
&~(prevIrqMask
|currIrqMask
);
251 while(i
<(sizeof(_irqPrio
)/sizeof(u32
))) {
252 if((irq
=(mask
&_irqPrio
[i
]))) {
259 if(g_IRQHandler
[irq
].pHndl
) g_IRQHandler
[irq
].pHndl(irq
,g_IRQHandler
[irq
].pCtx
);
262 __irq_dump(mask
,irq
);
267 static u32
__SetInterrupts(u32 iMask
,u32 nMask
)
273 if(irq
<=IRQ_MEMADDRESS
) {
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
);
294 imask
= _aiReg
[0]&~0x2c;
295 if(!(nMask
&IM_AI
)) imask
|= 0x0004;
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;
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;
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;
322 return (iMask
&~IM_EXI2
);
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
) {
331 if(!(nMask
&IM_PI_ERROR
)) {
334 if(!(nMask
&IM_PI_RSW
)) {
337 if(!(nMask
&IM_PI_DI
)) {
340 if(!(nMask
&IM_PI_SI
)) {
343 if(!(nMask
&IM_PI_VI
)) {
346 if(!(nMask
&IM_PI_PETOKEN
)) {
349 if(!(nMask
&IM_PI_PEFINISH
)) {
352 if(!(nMask
&IM_PI_CP
)) {
355 if(!(nMask
&IM_PI_DEBUG
)) {
358 if(!(nMask
&IM_PI_HSP
)) {
362 if(!(nMask
&IM_PI_ACR
)) {
367 return (iMask
&~IM_PI
);
372 void __UnmaskIrq(u32 nMask
)
377 _CPU_ISR_Disable(level
);
378 mask
= (nMask
&(prevIrqMask
|currIrqMask
));
379 nMask
= (prevIrqMask
&~nMask
);
381 while((mask
=__SetInterrupts(mask
,(nMask
|currIrqMask
)))!=0);
382 _CPU_ISR_Restore(level
);
385 void __MaskIrq(u32 nMask
)
390 _CPU_ISR_Disable(level
);
391 mask
= (nMask
&~(prevIrqMask
|currIrqMask
));
392 nMask
= (nMask
|prevIrqMask
);
394 while((mask
=__SetInterrupts(mask
,(nMask
|currIrqMask
)))!=0);
395 _CPU_ISR_Restore(level
);
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
);
421 __UnmaskIrq(IM_PI_ERROR
);
424 raw_irq_handler_t
IRQ_Request(u32 nIrq
,raw_irq_handler_t pHndl
,void *pCtx
)
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
);
436 raw_irq_handler_t
IRQ_GetHandler(u32 nIrq
)
439 raw_irq_handler_t ret
;
441 _CPU_ISR_Disable(level
);
442 ret
= g_IRQHandler
[nIrq
].pHndl
;
443 _CPU_ISR_Restore(level
);
447 raw_irq_handler_t
IRQ_Free(u32 nIrq
)
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
);
462 _CPU_ISR_Disable(level
);
466 void IRQ_Restore(u32 level
)
468 _CPU_ISR_Restore(level
);