fix issue with HBC stub + 64B L2 cache (tueidj)
[libogc.git] / libogc / audio.c
blob934454f51650e3fe8c5629fb9ff95363a50cf53c
1 /*-------------------------------------------------------------
3 audio.c -- Audio 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.
29 -------------------------------------------------------------*/
32 #include <stdlib.h>
33 #include "asm.h"
34 #include "processor.h"
35 #include "irq.h"
36 #include "audio.h"
37 #include "lwp_watchdog.h"
39 #define STACKSIZE 16384
41 // DSPCR bits
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 // Audio Interface Registers
55 #define AI_CONTROL 0
56 #define AI_STREAM_VOL 1
57 #define AI_SAMPLE_COUNT 2
58 #define AI_INT_TIMING 3
60 #define AI_PSTAT 0x01
61 #define AI_AISFR 0x02
62 #define AI_AIINTMSK 0x04
63 #define AI_AIINT 0x08
64 #define AI_AIINTVLD 0x10
65 #define AI_SCRESET 0x20
66 #define AI_DMAFR 0x40
68 #define _SHIFTL(v, s, w) \
69 ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
70 #define _SHIFTR(v, s, w) \
71 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
73 #if defined(HW_DOL)
74 static vu32* const _aiReg = (u32*)0xCC006C00;
75 #elif defined(HW_RVL)
76 static vu32* const _aiReg = (u32*)0xCD006C00;
77 #else
78 #error HW model not supported.
79 #endif
81 static vu16* const _dspReg = (u16*)0xCC005000;
83 static u32 __AIInitFlag = 0;
84 static u32 __AIActive = 0;
85 static u8 *__CallbackStack = NULL;
86 static u8 *__OldStack = NULL;
88 static u64 bound_32KHz,bound_48KHz,min_wait,max_wait,buffer;
90 #if defined(HW_DOL)
91 static AISCallback __AIS_Callback;
92 #endif
93 static AIDCallback __AID_Callback;
95 static void __AICallbackStackSwitch(AIDCallback handler)
97 __asm__ __volatile__("mflr %r0\n\
98 stw %r0,4(%r1)\n\
99 stwu %r1,-24(%r1)\n\
100 stw %r31,20(%r1)\n\
101 mr %r31,%r3\n\
102 lis %r5,__OldStack@ha\n\
103 addi %r5,%r5,__OldStack@l\n\
104 stw %r1,0(%r5)\n\
105 lis %r5,__CallbackStack@ha\n\
106 addi %r5,%r5,__CallbackStack@l\n\
107 lwz %r1,0(%r5)\n\
108 subi %r1,%r1,8\n\
109 mtlr %r31\n\
110 blrl\n\
111 lis %r5,__OldStack@ha\n\
112 addi %r5,%r5,__OldStack@l\n\
113 lwz %r1,0(%r5)\n\
114 lwz %r0,28(%r1)\n\
115 lwz %r31,20(%r1)\n\
116 addi %r1,%r1,24\n\
117 mtlr %r0\n"
121 #if defined(HW_DOL)
122 static void __AISHandler(u32 nIrq,void *pCtx)
124 if(__AIS_Callback)
125 __AIS_Callback(_aiReg[AI_SAMPLE_COUNT]);
126 _aiReg[AI_CONTROL] |= AI_AIINT;
128 #endif
130 static void __AIDHandler(u32 nIrq,void *pCtx)
132 _dspReg[5] = (_dspReg[5]&~(DSPCR_DSPINT|DSPCR_ARINT))|DSPCR_AIINT;
133 if(__AID_Callback) {
134 if(!__AIActive) {
135 __AIActive = 1;
136 if(__CallbackStack)
137 __AICallbackStackSwitch(__AID_Callback);
138 else
139 __AID_Callback();
140 __AIActive = 0;
145 static void __AISRCINIT()
147 int done = 0;
148 u32 sample_counter;
149 u64 time1, time2, tdiff;
150 u64 wait = 0;
152 while (!done) {
153 _aiReg[AI_CONTROL] |= AI_SCRESET;
154 _aiReg[AI_CONTROL] &= ~AI_AISFR;
155 _aiReg[AI_CONTROL] |= AI_PSTAT;
157 #ifdef HW_DOL
158 sample_counter = _aiReg[AI_SAMPLE_COUNT];
159 while (sample_counter == _aiReg[AI_SAMPLE_COUNT]) {}
160 #else
161 sample_counter = _aiReg[AI_SAMPLE_COUNT] & 0x7fffffff;
162 while (sample_counter == (_aiReg[AI_SAMPLE_COUNT] & 0x7fffffff)) {}
163 #endif
165 time1 = gettime();
167 _aiReg[AI_CONTROL] |= AI_AISFR;
168 _aiReg[AI_CONTROL] |= AI_PSTAT;
170 #ifdef HW_DOL
171 sample_counter = _aiReg[AI_SAMPLE_COUNT];
172 while (sample_counter == _aiReg[AI_SAMPLE_COUNT]) {}
173 #else
174 sample_counter = _aiReg[AI_SAMPLE_COUNT] & 0x7fffffff;
175 while (sample_counter == (_aiReg[AI_SAMPLE_COUNT] & 0x7fffffff)) {}
176 #endif
178 time2 = gettime();
179 tdiff = time2 - time1;
181 _aiReg[AI_CONTROL] &= ~AI_AISFR;
182 _aiReg[AI_CONTROL] &= ~AI_PSTAT;
184 if ((tdiff > (bound_32KHz - buffer)) &&
185 (tdiff < (bound_32KHz + buffer))) {
186 if (tdiff < (bound_48KHz - buffer)) {
187 wait = max_wait;
188 done = 1;
190 } else {
191 wait = min_wait;
192 done = 1;
196 while (diff_ticks(time2, gettime()) < wait) {}
199 #if defined(HW_DOL)
200 static void __AISetStreamSampleRate(u32 rate)
202 u32 currrate,level;
203 u32 playstate,volright,volleft,dsprate;
205 currrate = AUDIO_GetStreamSampleRate();
206 if(currrate!=rate) {
207 playstate = AUDIO_GetStreamPlayState();
208 volleft = AUDIO_GetStreamVolLeft();
209 volright = AUDIO_GetStreamVolRight();
210 AUDIO_SetStreamVolLeft(0);
211 AUDIO_SetStreamVolRight(0);
212 dsprate = _aiReg[AI_CONTROL]&0x40;
213 _aiReg[AI_CONTROL] = _aiReg[AI_CONTROL]&~0x40;
215 _CPU_ISR_Disable(level);
216 __AISRCINIT();
217 _aiReg[AI_CONTROL] |= dsprate;
218 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~0x20)|0x20;
219 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~0x02)|(_SHIFTL(rate,1,1));
220 _CPU_ISR_Restore(level);
222 AUDIO_SetStreamPlayState(playstate);
223 AUDIO_SetStreamVolLeft(volleft);
224 AUDIO_SetStreamVolRight(volright);
228 AISCallback AUDIO_RegisterStreamCallback(AISCallback callback)
230 u32 level;
232 AISCallback old = __AIS_Callback;
233 _CPU_ISR_Disable(level);
234 __AIS_Callback = callback;
235 _CPU_ISR_Restore(level);
236 return old;
238 #endif
240 void AUDIO_Init(u8 *stack)
242 u32 rate,level;
244 if(!__AIInitFlag) {
245 bound_32KHz = nanosecs_to_ticks(31524);
246 bound_48KHz = nanosecs_to_ticks(42024);
247 min_wait = nanosecs_to_ticks(42000);
248 max_wait = nanosecs_to_ticks(63000);
249 buffer = nanosecs_to_ticks(3000);
251 _aiReg[AI_CONTROL] &= ~(AI_AIINTVLD|AI_AIINTMSK|AI_PSTAT);
252 _aiReg[1] = 0;
253 _aiReg[3] = 0;
255 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_SCRESET)|AI_SCRESET;
257 rate = (_SHIFTR(_aiReg[AI_CONTROL],6,1))^1;
258 if(rate==AI_SAMPLERATE_48KHZ) {
259 _aiReg[AI_CONTROL] &= ~AI_DMAFR;
260 _CPU_ISR_Disable(level);
261 __AISRCINIT();
262 _aiReg[AI_CONTROL] |= AI_DMAFR;
263 _CPU_ISR_Restore(level);
266 __AID_Callback = NULL;
268 __OldStack = NULL; // davem - use it or lose it
269 // looks like 3.4 isn't picking up the use from the asm below
270 __CallbackStack = stack;
272 IRQ_Request(IRQ_DSP_AI,__AIDHandler,NULL);
273 __UnmaskIrq(IRQMASK(IRQ_DSP_AI));
274 #if defined(HW_DOL)
275 __AIS_Callback = NULL;
277 IRQ_Request(IRQ_AI,__AISHandler,NULL);
278 __UnmaskIrq(IRQMASK(IRQ_AI));
279 #endif
280 __AIInitFlag = 1;
284 #if defined(HW_DOL)
285 void AUDIO_SetStreamVolLeft(u8 vol)
287 _aiReg[1] = (_aiReg[1]&~0x000000ff)|(vol&0xff);
290 u8 AUDIO_GetStreamVolLeft()
292 return (u8)(_aiReg[1]&0xff);
295 void AUDIO_SetStreamVolRight(u8 vol)
297 _aiReg[1] = (_aiReg[1]&~0x0000ff00)|(_SHIFTL(vol,8,8));
300 u8 AUDIO_GetStreamVolRight()
302 return (u8)(_SHIFTR(_aiReg[1],8,8));
305 void AUDIO_SetStreamSampleRate(u32 rate)
307 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_AISFR)|(_SHIFTL(rate,1,1));
310 u32 AUDIO_GetStreamSampleRate()
312 return _SHIFTR(_aiReg[AI_CONTROL],1,1);
315 void AUDIO_SetStreamTrigger(u32 cnt)
317 _aiReg[3] = cnt;
320 void AUDIO_ResetStreamSampleCnt()
322 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_SCRESET)|AI_SCRESET;
325 void AUDIO_SetStreamPlayState(u32 state)
327 u32 playstate,streamrate;
328 u32 volright,volleft,level;
330 playstate = AUDIO_GetStreamPlayState();
331 streamrate = AUDIO_GetStreamSampleRate();
332 if(playstate!=state && state==AI_STREAM_START && streamrate==AI_SAMPLERATE_32KHZ ) {
333 volright = AUDIO_GetStreamVolRight();
334 AUDIO_SetStreamVolRight(0);
335 volleft = AUDIO_GetStreamVolLeft();
336 AUDIO_SetStreamVolLeft(0);
338 _CPU_ISR_Disable(level);
339 __AISRCINIT();
340 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_SCRESET)|AI_SCRESET;
341 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~0x01)|0x01;
342 _CPU_ISR_Restore(level);
343 AUDIO_SetStreamVolRight(volright);
344 AUDIO_SetStreamVolLeft(volleft);
345 } else {
346 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_PSTAT)|(state&AI_PSTAT);
350 u32 AUDIO_GetStreamPlayState()
352 return (_aiReg[AI_CONTROL]&AI_PSTAT);
354 #endif
356 AIDCallback AUDIO_RegisterDMACallback(AIDCallback callback)
358 u32 level;
359 AIDCallback old;
361 _CPU_ISR_Disable(level);
362 old = __AID_Callback;
363 __AID_Callback = callback;
364 _CPU_ISR_Restore(level);
365 return old;
368 void AUDIO_InitDMA(u32 startaddr,u32 len)
370 u32 level;
372 _CPU_ISR_Disable(level);
373 _dspReg[24] = (_dspReg[24]&~0x1fff)|(_SHIFTR(startaddr,16,13));
374 _dspReg[25] = (_dspReg[25]&~0xffe0)|(startaddr&0xffff);
375 _dspReg[27] = (_dspReg[27]&~0x7fff)|(_SHIFTR(len,5,15));
376 _CPU_ISR_Restore(level);
379 u16 AUDIO_GetDMAEnableFlag()
381 return (_SHIFTR(_dspReg[27],15,1));
384 void AUDIO_StartDMA()
386 _dspReg[27] = (_dspReg[27]&~0x8000)|0x8000;
389 void AUDIO_StopDMA()
391 _dspReg[27] = (_dspReg[27]&~0x8000);
394 u32 AUDIO_GetDMABytesLeft()
396 return (_SHIFTL(_dspReg[29],5,15));
399 u32 AUDIO_GetDMAStartAddr()
401 return (_SHIFTL((_dspReg[24]&0x1fff),16,13)|(_dspReg[25]&0xffe0));
404 u32 AUDIO_GetDMALength()
406 return ((_dspReg[27]&0x7fff)<<5);
409 void AUDIO_SetDSPSampleRate(u8 rate)
411 u32 level;
413 if(AUDIO_GetDSPSampleRate()!=rate) {
414 _aiReg[AI_CONTROL] &= ~AI_DMAFR;
415 if(rate==AI_SAMPLERATE_32KHZ) {
416 _CPU_ISR_Disable(level);
417 __AISRCINIT();
418 _aiReg[AI_CONTROL] |= AI_DMAFR;
419 _CPU_ISR_Restore(level);
424 u32 AUDIO_GetDSPSampleRate()
426 return (_SHIFTR(_aiReg[AI_CONTROL],6,1))^1; //0^1(1) = 48Khz, 1^1(0) = 32Khz