12 #include "lwp_watchdog.h"
16 #define _SHIFTL(v, s, w) \
17 ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
18 #define _SHIFTR(v, s, w) \
19 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
21 #define SISR_ERRORMASK(chn) (0x0f000000>>((chn)<<3))
22 #define SIPOLL_ENABLE(chn) (0x80000000>>((chn)+24))
24 #define SICOMCSR_TCINT (1<<31)
25 #define SICOMCSR_TCINT_ENABLE (1<<30)
26 #define SICOMCSR_COMERR (1<<29)
27 #define SICOMCSR_RDSTINT (1<<28)
28 #define SICOMCSR_RDSTINT_ENABLE (1<<27)
29 #define SICOMCSR_TSTART (1<<0)
31 #define SISR_UNDERRUN 0x0001
32 #define SISR_OVERRUN 0x0002
33 #define SISR_COLLISION 0x0004
34 #define SISR_NORESPONSE 0x0008
35 #define SISR_WRST 0x0010
36 #define SISR_RDST 0x0020
38 typedef union _sicomcsr
{
56 static struct _sipacket
{
66 static struct _sicntrl
{
85 {0x00F6,0x02},{0x000F,0x12},{0x001E,0x09},{0x002C,0x06},
86 {0x0034,0x05},{0x0041,0x04},{0x0057,0x03},{0x0057,0x03},
87 {0x0057,0x03},{0x0083,0x02},{0x0083,0x02},{0x0083,0x02}
91 {0x0128,0x02},{0x000F,0x15},{0x001D,0x0B},{0x002D,0x07},
92 {0x0034,0x06},{0x003F,0x05},{0x004E,0x04},{0x0068,0x03},
93 {0x0068,0x03},{0x0068,0x03},{0x0068,0x03},{0x009C,0x02}
99 static u32 sampling_rate
= 0;
100 static u32 cmdtypeandstatus$
47 = 0;
101 static u32 cmdtypeandstatus$
223 = 0;
102 static u32 cmdfixdevice
[4] = {0,0,0,0};
103 static u32 si_type
[4] = {8,8,8,8};
104 static u32 inputBufferVCount
[4] = {0,0,0,0};
105 static u32 inputBufferValid
[4] = {0,0,0,0};
106 static u32 inputBuffer
[4][2] = {{0,0},{0,0},{0,0},{0,0}};
107 static RDSTHandler rdstHandlers
[4] = {NULL
,NULL
,NULL
,NULL
};
108 static u64 typeTime
[4] = {0,0,0,0};
109 static u64 xferTime
[4] = {0,0,0,0};
110 static SICallback typeCallback
[4][4] = {{NULL
,NULL
,NULL
,NULL
},
111 {NULL
,NULL
,NULL
,NULL
},
112 {NULL
,NULL
,NULL
,NULL
},
113 {NULL
,NULL
,NULL
,NULL
}};
114 static syswd_t si_alarm
[4];
117 static vu32
* const _siReg
= (u32
*)0xCC006400;
118 #elif defined(HW_RVL)
119 static vu32
* const _siReg
= (u32
*)0xCD006400;
121 #error HW model unknown.
124 static vu16
* const _viReg
= (u16
*)0xCC002000;
126 static u32
__si_transfer(s32 chan
,void *out
,u32 out_len
,void *in
,u32 in_len
,SICallback cb
);
128 static __inline__
struct _xy
* __si_getxy()
130 switch(VIDEO_GetCurrentTvMode()) {
143 static __inline__
void __si_cleartcinterrupt()
145 _siReg
[13] = (_siReg
[13]|SICOMCSR_TCINT
)&SICOMCSR_TCINT
;
148 static void __si_alarmhandler(syswd_t thealarm
,void *cbarg
)
152 printf("__si_alarmhandler(%08x)\n",thealarm
);
156 if(si_alarm
[chn
]==thealarm
) break;
161 if(sipacket
[chn
].chan
!=-1) {
162 if(__si_transfer(sipacket
[chn
].chan
,sipacket
[chn
].out
,sipacket
[chn
].out_bytes
,sipacket
[chn
].in
,sipacket
[chn
].in_bytes
,sipacket
[chn
].callback
)) sipacket
[chn
].chan
= -1;
166 static u32
__si_completetransfer()
172 printf("__si_completetransfer(csr = %08x,sr = %08x,chan = %d)\n",_siReg
[13],_siReg
[14],sicntrl
.chan
);
175 __si_cleartcinterrupt();
177 if(sicntrl
.chan
==-1) return sisr
;
179 xferTime
[sicntrl
.chan
] = gettime();
181 in
= (u32
*)sicntrl
.in
;
182 cnt
= (sicntrl
.in_bytes
/4);
183 for(i
=0;i
<cnt
;i
++) in
[i
] = _siReg
[32+i
];
184 if(sicntrl
.in_bytes
&0x03) {
185 val
= _siReg
[32+cnt
];
186 for(i
=0;i
<(sicntrl
.in_bytes
&0x03);i
++) ((u8
*)in
)[(cnt
*4)+i
] = (val
>>((3-i
)*8))&0xff;
189 printf("__si_completetransfer(csr = %08x)\n",_siReg
[13]);
191 if(_siReg
[13]&SICOMCSR_COMERR
) {
192 sisr
= (sisr
>>((3-sicntrl
.chan
)*8))&0x0f;
193 if(sisr
&SISR_NORESPONSE
&& !(si_type
[sicntrl
.chan
]&SI_ERR_BUSY
)) si_type
[sicntrl
.chan
] = SI_ERROR_NO_RESPONSE
;
194 if(!sisr
) sisr
= SISR_COLLISION
;
196 typeTime
[sicntrl
.chan
] = gettime();
204 static u32
__si_transfer(s32 chan
,void *out
,u32 out_len
,void *in
,u32 in_len
,SICallback cb
)
209 printf("__si_transfer(%d,%p,%d,%p,%d,%p)\n",chan
,out
,out_len
,in
,in_len
,cb
);
211 _CPU_ISR_Disable(level
);
212 if(sicntrl
.chan
!=-1) {
213 _CPU_ISR_Restore(level
);
217 printf("__si_transfer(out = %08x,csr = %08x,sr = %08x)\n",*(u32
*)out
,_siReg
[13],_siReg
[14]);
219 _siReg
[14] &= SISR_ERRORMASK(chan
);
222 sicntrl
.callback
= cb
;
223 sicntrl
.in_bytes
= in_len
;
226 printf("__si_transfer(csr = %08x,sr = %08x)\n",_siReg
[13],_siReg
[14]);
228 cnt
= ((out_len
+3)/4);
229 for(i
=0;i
<cnt
;i
++) _siReg
[32+i
] = ((u32
*)out
)[i
];
231 csr
.val
= _siReg
[13];
232 csr
.csrmap
.tcint
= 1;
233 csr
.csrmap
.tcintmsk
= 0;
234 if(cb
) csr
.csrmap
.tcintmsk
= 1;
236 if(out_len
==128) out_len
= 0;
237 csr
.csrmap
.outlen
= out_len
&0x7f;
239 if(in_len
==128) in_len
= 0;
240 csr
.csrmap
.inlen
= in_len
&0x7f;
242 csr
.csrmap
.channel
= chan
&0x03;
243 csr
.csrmap
.tstart
= 1;
245 printf("__si_transfer(csr = %08x)\n",csr
.val
);
247 _siReg
[13] = csr
.val
;
248 _CPU_ISR_Restore(level
);
253 static void __si_calltypandstatuscallback(s32 chan
,u32 type
)
256 SICallback cb
= NULL
;
258 printf("__si_calltypandstatuscallback(%d,%08x)\n",chan
,type
);
262 cb
= typeCallback
[chan
][typ
];
264 typeCallback
[chan
][typ
] = NULL
;
271 static void __si_gettypecallback(s32 chan
,u32 type
)
275 si_type
[chan
] = (si_type
[chan
]&~SI_ERR_BUSY
)|type
;
276 typeTime
[chan
] = gettime();
278 printf("__si_gettypecallback(%d,%08x,%08x)\n",chan
,type
,si_type
[chan
]);
280 sipad_en
= __PADFixBits
&SI_CHAN_BIT(chan
);
281 __PADFixBits
&= ~SI_CHAN_BIT(chan
);
283 if(type
&0x0f || ((si_type
[chan
]&SI_TYPE_MASK
)-SI_TYPE_GC
)
284 || !(si_type
[chan
]&SI_GC_WIRELESS
) || si_type
[chan
]&SI_WIRELESS_IR
) {
285 SYS_SetWirelessID(chan
,0);
286 __si_calltypandstatuscallback(chan
,si_type
[chan
]);
290 id
= _SHIFTL(SYS_GetWirelessID(chan
),8,16);
292 printf("__si_gettypecallback(id = %08x)\n",id
);
294 if(sipad_en
&& id
&SI_WIRELESS_FIX_ID
) {
295 cmdfixdevice
[chan
] = 0x4e100000|(id
&0x00CFFF00);
296 si_type
[chan
] = SI_ERR_BUSY
;
297 SI_Transfer(chan
,&cmdfixdevice
[chan
],3,&si_type
[chan
],3,__si_gettypecallback
,0);
301 if(si_type
[chan
]&SI_WIRELESS_FIX_ID
) {
302 if((id
&0x00CFFF00)==(si_type
[chan
]&0x00CFFF00)) goto exit
;
303 if(!(id
&SI_WIRELESS_FIX_ID
)) {
304 id
= SI_WIRELESS_FIX_ID
|(si_type
[chan
]&0x00CFFF00);
305 SYS_SetWirelessID(chan
,_SHIFTR(id
,8,16));
307 cmdfixdevice
[chan
] = 0x4e000000|id
;
308 si_type
[chan
] = SI_ERR_BUSY
;
309 SI_Transfer(chan
,&cmdfixdevice
[chan
],3,&si_type
[chan
],3,__si_gettypecallback
,0);
313 if(si_type
[chan
]&SI_WIRELESS_RECEIVED
) {
314 id
= SI_WIRELESS_FIX_ID
|(si_type
[chan
]&0x00CFFF00);
315 SYS_SetWirelessID(chan
,_SHIFTR(id
,8,16));
317 cmdfixdevice
[chan
] = 0x4e000000|id
;
318 si_type
[chan
] = SI_ERR_BUSY
;
319 SI_Transfer(chan
,&cmdfixdevice
[chan
],3,&si_type
[chan
],3,__si_gettypecallback
,0);
322 SYS_SetWirelessID(chan
,0);
325 __si_calltypandstatuscallback(chan
,si_type
[chan
]);
328 static void __si_transfernext(u32 chan
)
334 printf("__si_transfernext(%d)\n",chan
);
341 printf("__si_transfernext(chan = %d,sipacket.chan = %d)\n",chan
,sipacket
[chan
].chan
);
343 if(sipacket
[chan
].chan
!=-1) {
345 diff
= (now
- sipacket
[chan
].fire
);
347 if(!__si_transfer(sipacket
[chan
].chan
,sipacket
[chan
].out
,sipacket
[chan
].out_bytes
,sipacket
[chan
].in
,sipacket
[chan
].in_bytes
,sipacket
[chan
].callback
)) break;
348 SYS_CancelAlarm(si_alarm
[chan
]);
349 sipacket
[chan
].chan
= -1;
356 static void __si_interrupthandler(u32 irq
,void *ctx
)
359 u32 chn
,curr_line
,line
,ret
;
362 csr
.val
= _siReg
[13];
364 printf("__si_interrupthandler(csr = %08x)\n",csr
.val
);
366 if(csr
.csrmap
.tcintmsk
&& csr
.csrmap
.tcint
) {
368 cb
= sicntrl
.callback
;
369 sicntrl
.callback
= NULL
;
371 ret
= __si_completetransfer();
372 __si_transfernext(chn
);
376 _siReg
[14] &= SISR_ERRORMASK(chn
);
378 if(si_type
[chn
]==SI_ERR_BUSY
&& !SI_IsChanBusy(chn
)) SI_Transfer(chn
,&cmdtypeandstatus$
47,1,&si_type
[chn
],3,__si_gettypecallback
,65);
381 if(csr
.csrmap
.rdstintmsk
&& csr
.csrmap
.rdstint
) {
382 curr_line
= VIDEO_GetCurrentLine();
384 line
= _SHIFTR(sicntrl
.poll
,16,10);
388 if(SI_GetResponseRaw(chn
)) inputBufferVCount
[chn
] = curr_line
;
394 if(sicntrl
.poll
&SIPOLL_ENABLE(chn
)) {
395 if(!inputBufferVCount
[chn
] || ((line
>>1)+inputBufferVCount
[chn
])<curr_line
) return;
401 while(chn
<4) inputBufferVCount
[chn
++] = 0;
405 if(rdstHandlers
[chn
]) rdstHandlers
[chn
](irq
,ctx
);
415 while(_siReg
[13]&SICOMCSR_TSTART
);
417 _CPU_ISR_Disable(level
);
418 ret
= __si_completetransfer();
419 __si_transfernext(4);
420 _CPU_ISR_Restore(level
);
427 return (sicntrl
.chan
==-1)?0:1;
430 u32
SI_IsChanBusy(s32 chan
)
434 if(sipacket
[chan
].chan
!=-1 || sicntrl
.chan
==chan
) ret
= 1;
439 void SI_SetXY(u16 line
,u8 cnt
)
443 printf("SI_SetXY(%d,%d)\n",line
,cnt
);
445 _CPU_ISR_Disable(level
);
446 sicntrl
.poll
= (sicntrl
.poll
&~0x3ffff00)|_SHIFTL(line
,16,10)|_SHIFTL(cnt
,8,8);
447 _siReg
[12] = sicntrl
.poll
;
448 _CPU_ISR_Restore(level
);
451 void SI_EnablePolling(u32 poll
)
455 printf("SI_EnablePolling(%08x)\n",poll
);
457 _CPU_ISR_Disable(level
);
459 mask
= (poll
>>4)&0x0f;
460 sicntrl
.poll
&= ~mask
;
462 poll
&= (0x03fffff0|mask
);
464 sicntrl
.poll
|= (poll
&~0x03ffff00);
465 SI_TransferCommands();
467 printf("SI_EnablePolling(%08x)\n",sicntrl
.poll
);
469 _siReg
[12] = sicntrl
.poll
;
470 _CPU_ISR_Restore(level
);
473 void SI_DisablePolling(u32 poll
)
477 printf("SI_DisablePolling(%08x)\n",poll
);
479 _CPU_ISR_Disable(level
);
480 mask
= (poll
>>24)&0xf0;
481 sicntrl
.poll
&= ~mask
;
482 _siReg
[12] = sicntrl
.poll
;
483 _CPU_ISR_Restore(level
);
486 void SI_SetSamplingRate(u32 samplingrate
)
489 struct _xy
*xy
= NULL
;
491 if(samplingrate
>11) samplingrate
= 11;
493 _CPU_ISR_Disable(level
);
494 sampling_rate
= samplingrate
;
498 if(_viReg
[54]&0x0001) div
= 2;
500 SI_SetXY(div
*xy
[samplingrate
].line
,xy
[samplingrate
].cnt
);
501 _CPU_ISR_Restore(level
);
504 void SI_RefreshSamplingRate()
506 SI_SetSamplingRate(sampling_rate
);
509 u32
SI_GetStatus(s32 chan
)
513 _CPU_ISR_Disable(level
);
514 sisr
= (_siReg
[14]>>((3-chan
)<<3));
515 if(sisr
&SISR_NORESPONSE
&& !(si_type
[chan
]&SI_ERR_BUSY
)) si_type
[chan
] = SI_ERROR_NO_RESPONSE
;
516 _CPU_ISR_Restore(level
);
520 u32
SI_GetResponseRaw(s32 chan
)
524 printf("SI_GetResponseRaw(%d)\n",chan
);
527 status
= SI_GetStatus(chan
);
528 if(status
&SISR_RDST
) {
529 inputBuffer
[chan
][0] = _siReg
[(chan
*3)+1];
530 inputBuffer
[chan
][1] = _siReg
[(chan
*3)+2];
531 inputBufferValid
[chan
] = 1;
537 u32
SI_GetResponse(s32 chan
,void *buf
)
540 _CPU_ISR_Disable(level
);
541 SI_GetResponseRaw(chan
);
542 valid
= inputBufferValid
[chan
];
543 inputBufferValid
[chan
] = 0;
545 printf("SI_GetResponse(%d,%p,%d)\n",chan
,buf
,valid
);
548 ((u32
*)buf
)[0] = inputBuffer
[chan
][0];
549 ((u32
*)buf
)[1] = inputBuffer
[chan
][1];
551 _CPU_ISR_Restore(level
);
555 void SI_SetCommand(s32 chan
,u32 cmd
)
557 _siReg
[chan
*3] = cmd
;
560 u32
SI_GetCommand(s32 chan
)
562 return (_siReg
[chan
*3]);
565 u32
SI_Transfer(s32 chan
,void *out
,u32 out_len
,void *in
,u32 in_len
,SICallback cb
,u32 us_delay
)
573 printf("SI_Transfer(%d,%p,%d,%p,%d,%p,%d)\n",chan
,out
,out_len
,in
,in_len
,cb
,us_delay
);
575 _CPU_ISR_Disable(level
);
576 if(sipacket
[chan
].chan
==-1 && sicntrl
.chan
!=chan
) {
578 fire
= now
= gettime();
579 if(us_delay
) fire
= xferTime
[chan
]+microsecs_to_ticks(us_delay
);
583 tb
.tv_nsec
= ticks_to_nanosecs((fire
- now
));
584 SYS_SetAlarm(si_alarm
[chan
],&tb
,__si_alarmhandler
,NULL
);
585 } else if(__si_transfer(chan
,out
,out_len
,in
,in_len
,cb
)) {
586 _CPU_ISR_Restore(level
);
589 sipacket
[chan
].chan
= chan
;
590 sipacket
[chan
].out
= out
;
591 sipacket
[chan
].out_bytes
= out_len
;
592 sipacket
[chan
].in
= in
;
593 sipacket
[chan
].in_bytes
= in_len
;
594 sipacket
[chan
].callback
= cb
;
595 sipacket
[chan
].fire
= fire
;
597 printf("SI_Transfer(%d,%p,%d,%p,%d,%p,%08x%08x)\n",sipacket
[chan
].chan
,sipacket
[chan
].out
,sipacket
[chan
].out_bytes
,sipacket
[chan
].in
,sipacket
[chan
].in_bytes
,sipacket
[chan
].callback
,(u32
)(sipacket
[chan
].fire
>>32),(u32
)sipacket
[chan
].fire
);
600 _CPU_ISR_Restore(level
);
604 u32
SI_GetType(s32 chan
)
610 printf("SI_GetType(%d)\n",chan
);
612 _CPU_ISR_Disable(level
);
614 type
= si_type
[chan
];
615 diff
= (now
- typeTime
[chan
]);
616 if(sicntrl
.poll
&(0x80>>chan
)) {
617 if(type
!=SI_ERROR_NO_RESPONSE
) {
618 typeTime
[chan
] = gettime();
619 _CPU_ISR_Restore(level
);
622 si_type
[chan
] = type
= SI_ERR_BUSY
;
623 } else if(diff
==millisecs_to_ticks(50) && type
!=SI_ERROR_NO_RESPONSE
) {
624 _CPU_ISR_Restore(level
);
626 } else if(diff
==millisecs_to_ticks(75)) si_type
[chan
] = SI_ERR_BUSY
;
627 else si_type
[chan
] = type
= SI_ERR_BUSY
;
629 typeTime
[chan
] = gettime();
631 SI_Transfer(chan
,&cmdtypeandstatus$
223,1,&si_type
[chan
],3,__si_gettypecallback
,65);
632 _CPU_ISR_Restore(level
);
637 u32
SI_GetTypeAsync(s32 chan
,SICallback cb
)
642 printf("SI_GetTypeAsync(%d)\n",chan
);
644 _CPU_ISR_Disable(level
);
645 type
= SI_GetType(chan
);
646 if(si_type
[chan
]&SI_ERR_BUSY
) {
649 if(!typeCallback
[chan
][i
] && typeCallback
[chan
][i
]!=cb
) {
650 typeCallback
[chan
][i
] = cb
;
654 _CPU_ISR_Restore(level
);
659 _CPU_ISR_Restore(level
);
663 void SI_TransferCommands()
665 _siReg
[14] = 0x80000000;
668 u32
SI_RegisterPollingHandler(RDSTHandler handler
)
672 _CPU_ISR_Disable(level
);
676 if(rdstHandlers
[i
]==handler
) {
677 _CPU_ISR_Restore(level
);
683 if(rdstHandlers
[i
]==NULL
) {
684 rdstHandlers
[i
] = handler
;
685 SI_EnablePollingInterrupt(TRUE
);
686 _CPU_ISR_Restore(level
);
691 _CPU_ISR_Restore(level
);
695 u32
SI_UnregisterPollingHandler(RDSTHandler handler
)
699 _CPU_ISR_Disable(level
);
701 if(rdstHandlers
[i
]==handler
) {
702 rdstHandlers
[i
] = NULL
;
704 if(rdstHandlers
[i
]!=NULL
) break;
706 if(i
>=4) SI_EnablePollingInterrupt(FALSE
);
708 _CPU_ISR_Restore(level
);
712 _CPU_ISR_Restore(level
);
716 u32
SI_EnablePollingInterrupt(s32 enable
)
721 _CPU_ISR_Disable(level
);
724 csr
.val
= _siReg
[13];
725 if(csr
.csrmap
.rdstintmsk
) ret
= 1;
728 csr
.csrmap
.rdstintmsk
= 1;
729 for(i
=0;i
<4;i
++) inputBufferVCount
[i
] = 0;
731 csr
.csrmap
.rdstintmsk
= 0;
733 csr
.val
&= 0x7ffffffe;
734 _siReg
[13] = csr
.val
;
736 _CPU_ISR_Restore(level
);
744 printf("__si_init()\n");
747 sipacket
[i
].chan
= -1;
748 SYS_CreateAlarm(&si_alarm
[i
]);
752 SI_SetSamplingRate(0);
753 while(_siReg
[13]&0x0001);
754 _siReg
[13] = 0x80000000;
756 _siReg
[15] &= ~0x80000000; // permit exi clock to be set to 32MHz
758 IRQ_Request(IRQ_PI_SI
,__si_interrupthandler
,NULL
);
759 __UnmaskIrq(IRQMASK(IRQ_PI_SI
));