1 /*-------------------------------------------------------------
3 audio.c -- Audio 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
29 -------------------------------------------------------------*/
34 #include "processor.h"
37 #include "lwp_watchdog.h"
39 #define STACKSIZE 16384
42 #define DSPCR_DSPRESET 0x0800 // Reset DSP
43 #define DSPCR_DSPDMA 0x0200 // ARAM dma in progress, if set
44 #define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW)
45 #define DSPCR_DSPINT 0x0080 // * interrupt active (RWC)
46 #define DSPCR_ARINTMSK 0x0040
47 #define DSPCR_ARINT 0x0020
48 #define DSPCR_AIINTMSK 0x0010
49 #define DSPCR_AIINT 0x0008
50 #define DSPCR_HALT 0x0004 // halt DSP
51 #define DSPCR_PIINT 0x0002 // assert DSP PI interrupt
52 #define DSPCR_RES 0x0001 // reset DSP
54 #define _SHIFTL(v, s, w) \
55 ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
56 #define _SHIFTR(v, s, w) \
57 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
60 static vu32
* const _aiReg
= (u32
*)0xCC006C00;
62 static vu32
* const _aiReg
= (u32
*)0xCD006C00;
64 #error HW model not supported.
67 static vu16
* const _dspReg
= (u16
*)0xCC005000;
69 static u32 __AIInitFlag
= 0;
70 static u32 __AIActive
= 0;
71 static u8
*__CallbackStack
= NULL
;
72 static u8
*__OldStack
= NULL
;
74 static u64 bound_32KHz
,bound_48KHz
,min_wait
,max_wait
,buffer
;
77 static AISCallback __AIS_Callback
;
79 static AIDCallback __AID_Callback
;
81 static void __AICallbackStackSwitch(AIDCallback handler
)
83 __asm__
__volatile__("mflr %r0\n\
88 lis %r5,__OldStack@ha\n\
89 addi %r5,%r5,__OldStack@l\n\
91 lis %r5,__CallbackStack@ha\n\
92 addi %r5,%r5,__CallbackStack@l\n\
97 lis %r5,__OldStack@ha\n\
98 addi %r5,%r5,__OldStack@l\n\
108 static void __AISHandler(u32 nIrq
,void *pCtx
)
111 __AIS_Callback(_aiReg
[2]);
116 static void __AIDHandler(u32 nIrq
,void *pCtx
)
118 _dspReg
[5] = (_dspReg
[5]&~(DSPCR_DSPINT
|DSPCR_ARINT
))|DSPCR_AIINT
;
123 __AICallbackStackSwitch(__AID_Callback
);
131 static void __AISRCINIT()
135 u64 time1
,time2
,wait
;
138 _aiReg
[0] = (_aiReg
[0]&~0x20)|0x20;
139 _aiReg
[0] = (_aiReg
[0]&~0x02);
140 _aiReg
[0] = (_aiReg
[0]&~0x01)|0x01;
142 scnt
= _aiReg
[2]&0x7fffffff;
143 while(scnt
!=(_aiReg
[2]&0x7fffffff));
146 _aiReg
[0] = (_aiReg
[0]&~0x02)|0x02;
147 _aiReg
[0] = (_aiReg
[0]&~0x01)|0x01;
149 scnt
= _aiReg
[2]&0x7fffffff;
150 while(scnt
!=(_aiReg
[2]&0x7fffffff));
153 _aiReg
[0] = (_aiReg
[0]&~0x02);
154 _aiReg
[0] = (_aiReg
[0]&~0x01);
156 tdiff
= time2
- time1
;
157 if(tdiff
>(bound_32KHz
- buffer
) && tdiff
<(bound_32KHz
+ buffer
)) {
158 if(tdiff
<(bound_48KHz
- buffer
)) {
168 while(diff_ticks(time2
,gettime()) < wait
);
172 static void __AISetStreamSampleRate(u32 rate
)
175 u32 playstate
,volright
,volleft
,dsprate
;
177 currrate
= AUDIO_GetStreamSampleRate();
179 playstate
= AUDIO_GetStreamPlayState();
180 volleft
= AUDIO_GetStreamVolLeft();
181 volright
= AUDIO_GetStreamVolRight();
182 AUDIO_SetStreamVolLeft(0);
183 AUDIO_SetStreamVolRight(0);
184 dsprate
= _aiReg
[0]&0x40;
185 _aiReg
[0] = _aiReg
[0]&~0x40;
187 _CPU_ISR_Disable(level
);
189 _aiReg
[0] |= dsprate
;
190 _aiReg
[0] = (_aiReg
[0]&~0x20)|0x20;
191 _aiReg
[0] = (_aiReg
[0]&~0x02)|(_SHIFTL(rate
,1,1));
192 _CPU_ISR_Restore(level
);
194 AUDIO_SetStreamPlayState(playstate
);
195 AUDIO_SetStreamVolLeft(volleft
);
196 AUDIO_SetStreamVolRight(volright
);
200 AISCallback
AUDIO_RegisterStreamCallback(AISCallback callback
)
204 AISCallback old
= __AIS_Callback
;
205 _CPU_ISR_Disable(level
);
206 __AIS_Callback
= callback
;
207 _CPU_ISR_Restore(level
);
212 void AUDIO_Init(u8
*stack
)
217 bound_32KHz
= nanosecs_to_ticks(31524);
218 bound_48KHz
= nanosecs_to_ticks(42024);
219 min_wait
= nanosecs_to_ticks(42000);
220 max_wait
= nanosecs_to_ticks(63000);
221 buffer
= nanosecs_to_ticks(3000);
227 _aiReg
[0] = (_aiReg
[0]&~0x20)|0x20;
229 rate
= (_SHIFTR(_aiReg
[0],6,1))^1;
230 if(rate
==AI_SAMPLERATE_48KHZ
) {
232 _CPU_ISR_Disable(level
);
235 _CPU_ISR_Restore(level
);
238 __AID_Callback
= NULL
;
240 __OldStack
= NULL
; // davem - use it or lose it
241 // looks like 3.4 isn't picking up the use from the asm below
242 __CallbackStack
= stack
;
244 IRQ_Request(IRQ_DSP_AI
,__AIDHandler
,NULL
);
245 __UnmaskIrq(IRQMASK(IRQ_DSP_AI
));
247 __AIS_Callback
= NULL
;
249 IRQ_Request(IRQ_AI
,__AISHandler
,NULL
);
250 __UnmaskIrq(IRQMASK(IRQ_AI
));
257 void AUDIO_SetStreamVolLeft(u8 vol
)
259 _aiReg
[1] = (_aiReg
[1]&~0x000000ff)|(vol
&0xff);
262 u8
AUDIO_GetStreamVolLeft()
264 return (u8
)(_aiReg
[1]&0xff);
267 void AUDIO_SetStreamVolRight(u8 vol
)
269 _aiReg
[1] = (_aiReg
[1]&~0x0000ff00)|(_SHIFTL(vol
,8,8));
272 u8
AUDIO_GetStreamVolRight()
274 return (u8
)(_SHIFTR(_aiReg
[1],8,8));
277 void AUDIO_SetStreamSampleRate(u32 rate
)
279 _aiReg
[0] = (_aiReg
[0]&~0x0002)|(_SHIFTL(rate
,1,1));
282 u32
AUDIO_GetStreamSampleRate()
284 return _SHIFTR(_aiReg
[0],1,1);
287 void AUDIO_SetStreamTrigger(u32 cnt
)
292 void AUDIO_ResetStreamSampleCnt()
294 _aiReg
[0] = (_aiReg
[0]&~0x20)|0x20;
297 void AUDIO_SetStreamPlayState(u32 state
)
299 u32 playstate
,streamrate
;
300 u32 volright
,volleft
,level
;
302 playstate
= AUDIO_GetStreamPlayState();
303 streamrate
= AUDIO_GetStreamSampleRate();
304 if(playstate
!=state
&& state
==AI_STREAM_START
&& streamrate
==AI_SAMPLERATE_32KHZ
) {
305 volright
= AUDIO_GetStreamVolRight();
306 AUDIO_SetStreamVolRight(0);
307 volleft
= AUDIO_GetStreamVolLeft();
308 AUDIO_SetStreamVolLeft(0);
310 _CPU_ISR_Disable(level
);
312 _aiReg
[0] = (_aiReg
[0]&~0x20)|0x20;
313 _aiReg
[0] = (_aiReg
[0]&~0x01)|0x01;
314 _CPU_ISR_Restore(level
);
315 AUDIO_SetStreamVolRight(volright
);
316 AUDIO_SetStreamVolLeft(volleft
);
318 _aiReg
[0] = (_aiReg
[0]&~0x01)|(state
&0x01);
322 u32
AUDIO_GetStreamPlayState()
324 return (_aiReg
[0]&0x01);
328 AIDCallback
AUDIO_RegisterDMACallback(AIDCallback callback
)
333 _CPU_ISR_Disable(level
);
334 old
= __AID_Callback
;
335 __AID_Callback
= callback
;
336 _CPU_ISR_Restore(level
);
340 void AUDIO_InitDMA(u32 startaddr
,u32 len
)
344 _CPU_ISR_Disable(level
);
345 _dspReg
[24] = (_dspReg
[24]&~0x1fff)|(_SHIFTR(startaddr
,16,13));
346 _dspReg
[25] = (_dspReg
[25]&~0xffe0)|(startaddr
&0xffff);
347 _dspReg
[27] = (_dspReg
[27]&~0x7fff)|(_SHIFTR(len
,5,15));
348 _CPU_ISR_Restore(level
);
351 u16
AUDIO_GetDMAEnableFlag()
353 return (_SHIFTR(_dspReg
[27],15,1));
356 void AUDIO_StartDMA()
358 _dspReg
[27] = (_dspReg
[27]&~0x8000)|0x8000;
363 _dspReg
[27] = (_dspReg
[27]&~0x8000);
366 u32
AUDIO_GetDMABytesLeft()
368 return (_SHIFTL(_dspReg
[29],5,15));
371 u32
AUDIO_GetDMAStartAddr()
373 return (_SHIFTL((_dspReg
[24]&0x1fff),16,13)|(_dspReg
[25]&0xffe0));
376 u32
AUDIO_GetDMALength()
378 return ((_dspReg
[27]&0x7fff)<<5);
381 void AUDIO_SetDSPSampleRate(u8 rate
)
385 if(AUDIO_GetDSPSampleRate()!=rate
) {
387 if(rate
==AI_SAMPLERATE_32KHZ
) {
388 _CPU_ISR_Disable(level
);
391 _CPU_ISR_Restore(level
);
396 u32
AUDIO_GetDSPSampleRate()
398 return (_SHIFTR(_aiReg
[0],6,1))^1; //0^1(1) = 48Khz, 1^1(0) = 32Khz