1 /*-------------------------------------------------------------
2
3 audio.c -- Audio subsystem
4
5 Copyright (C) 2004
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
8
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.
12
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:
16
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.
21
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
24
25 3. This notice may not be removed or altered from any source
26 distribution.
27
28 -------------------------------------------------------------*/
29
30 #include <stdlib.h>
31 #include "asm.h"
32 #include "processor.h"
33 #include "irq.h"
34 #include "audio.h"
35 #include "lwp_watchdog.h"
36
37 #define STACKSIZE 16384
38
39 // DSPCR bits
40 #define DSPCR_DSPRESET 0x0800 // Reset DSP
41 #define DSPCR_DSPDMA 0x0200 // ARAM dma in progress, if set
42 #define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW)
43 #define DSPCR_DSPINT 0x0080 // * interrupt active (RWC)
44 #define DSPCR_ARINTMSK 0x0040
45 #define DSPCR_ARINT 0x0020
46 #define DSPCR_AIINTMSK 0x0010
47 #define DSPCR_AIINT 0x0008
48 #define DSPCR_HALT 0x0004 // halt DSP
49 #define DSPCR_PIINT 0x0002 // assert DSP PI interrupt
50 #define DSPCR_RES 0x0001 // reset DSP
51
52 // Audio Interface Registers
53 #define AI_CONTROL 0
54 #define AI_STREAM_VOL 1
55 #define AI_SAMPLE_COUNT 2
56 #define AI_INT_TIMING 3
57
58 #define AI_PSTAT 0x01
59 #define AI_AISFR 0x02
60 #define AI_AIINTMSK 0x04
61 #define AI_AIINT 0x08
62 #define AI_AIINTVLD 0x10
63 #define AI_SCRESET 0x20
64 #define AI_DMAFR 0x40
65
66 #define _SHIFTL(v, s, w) \
67 ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
68 #define _SHIFTR(v, s, w) \
69 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
70
71 #if defined(HW_DOL)
72 static vu32* const _aiReg = (u32*)0xCC006C00;
73 #elif defined(HW_RVL)
74 static vu32* const _aiReg = (u32*)0xCD006C00;
75 #else
76 #error HW model not supported.
77 #endif
78
79 static vu16* const _dspReg = (u16*)0xCC005000;
80
81 static u32 __AIInitFlag = 0;
82 static u32 __AIActive = 0;
83 static u8 *__CallbackStack __attribute__((used)) = NULL;
84 static u8 *__OldStack __attribute__((used)) = NULL;
85
86 static u64 bound_32KHz,bound_48KHz,min_wait,max_wait,buffer;
87
88 #if defined(HW_DOL)
89 static AISCallback __AIS_Callback;
90 #endif
91 static AIDCallback __AID_Callback;
92
__AICallbackStackSwitch(AIDCallback handler)93 static void __AICallbackStackSwitch(AIDCallback handler)
94 {
95 __asm__ __volatile__("mflr %r0\n\t\
96 stw %r0,4(%r1)\n\t\
97 stwu %r1,-24(%r1)\n\t\
98 stw %r31,20(%r1)\n\t\
99 mr %r31,%r3\n\t\
100 lis %r5,__OldStack@ha\n\t\
101 addi %r5,%r5,__OldStack@l\n\t\
102 stw %r1,0(%r5)\n\t\
103 lis %r5,__CallbackStack@ha\n\t\
104 addi %r5,%r5,__CallbackStack@l\n\t\
105 lwz %r1,0(%r5)\n\t\
106 subi %r1,%r1,8\n\t\
107 mtlr %r31\n\t\
108 blrl\n\t\
109 lis %r5,__OldStack@ha\n\t\
110 addi %r5,%r5,__OldStack@l\n\t\
111 lwz %r1,0(%r5)\n\t\
112 lwz %r0,28(%r1)\n\t\
113 lwz %r31,20(%r1)\n\t\
114 addi %r1,%r1,24\n\t\
115 mtlr %r0\n"
116 );
117 }
118
119 #if defined(HW_DOL)
__AISHandler(u32 nIrq,void * pCtx)120 static void __AISHandler(u32 nIrq,void *pCtx)
121 {
122 if(__AIS_Callback)
123 __AIS_Callback(_aiReg[AI_SAMPLE_COUNT]);
124 _aiReg[AI_CONTROL] |= AI_AIINT;
125 }
126 #endif
127
__AIDHandler(u32 nIrq,void * pCtx)128 static void __AIDHandler(u32 nIrq,void *pCtx)
129 {
130 _dspReg[5] = (_dspReg[5]&~(DSPCR_DSPINT|DSPCR_ARINT))|DSPCR_AIINT;
131 if(__AID_Callback) {
132 if(!__AIActive) {
133 __AIActive = 1;
134 if(__CallbackStack)
135 __AICallbackStackSwitch(__AID_Callback);
136 else
137 __AID_Callback();
138 __AIActive = 0;
139 }
140 }
141 }
142
__AISRCINIT()143 static void __AISRCINIT()
144 {
145 int done = 0;
146 u32 sample_counter;
147 u64 time1, time2, tdiff;
148 u64 wait = 0;
149
150 while (!done) {
151 _aiReg[AI_CONTROL] |= AI_SCRESET;
152 _aiReg[AI_CONTROL] &= ~AI_AISFR;
153 _aiReg[AI_CONTROL] |= AI_PSTAT;
154
155 #ifdef HW_DOL
156 sample_counter = _aiReg[AI_SAMPLE_COUNT];
157 while (sample_counter == _aiReg[AI_SAMPLE_COUNT]) {}
158 #else
159 sample_counter = _aiReg[AI_SAMPLE_COUNT] & 0x7fffffff;
160 while (sample_counter == (_aiReg[AI_SAMPLE_COUNT] & 0x7fffffff)) {}
161 #endif
162
163 time1 = gettime();
164
165 _aiReg[AI_CONTROL] |= AI_AISFR;
166 _aiReg[AI_CONTROL] |= AI_PSTAT;
167
168 #ifdef HW_DOL
169 sample_counter = _aiReg[AI_SAMPLE_COUNT];
170 while (sample_counter == _aiReg[AI_SAMPLE_COUNT]) {}
171 #else
172 sample_counter = _aiReg[AI_SAMPLE_COUNT] & 0x7fffffff;
173 while (sample_counter == (_aiReg[AI_SAMPLE_COUNT] & 0x7fffffff)) {}
174 #endif
175
176 time2 = gettime();
177 tdiff = time2 - time1;
178
179 _aiReg[AI_CONTROL] &= ~AI_AISFR;
180 _aiReg[AI_CONTROL] &= ~AI_PSTAT;
181
182 if ((tdiff > (bound_32KHz - buffer)) &&
183 (tdiff < (bound_32KHz + buffer))) {
184 if (tdiff < (bound_48KHz - buffer)) {
185 wait = max_wait;
186 done = 1;
187 }
188 } else {
189 wait = min_wait;
190 done = 1;
191 }
192 }
193
194 while (diff_ticks(time2, gettime()) < wait) {}
195 }
196
AUDIO_Init(u8 * stack)197 void AUDIO_Init(u8 *stack)
198 {
199 u32 rate,level;
200
201 if(!__AIInitFlag) {
202 bound_32KHz = nanosecs_to_ticks(31524);
203 bound_48KHz = nanosecs_to_ticks(42024);
204 min_wait = nanosecs_to_ticks(42000);
205 max_wait = nanosecs_to_ticks(63000);
206 buffer = nanosecs_to_ticks(3000);
207
208 _aiReg[AI_CONTROL] &= ~(AI_AIINTVLD|AI_AIINTMSK|AI_PSTAT);
209 _aiReg[1] = 0;
210 _aiReg[3] = 0;
211
212 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_SCRESET)|AI_SCRESET;
213
214 rate = (_SHIFTR(_aiReg[AI_CONTROL],6,1))^1;
215 if(rate==AI_SAMPLERATE_48KHZ) {
216 _aiReg[AI_CONTROL] &= ~AI_DMAFR;
217 _CPU_ISR_Disable(level);
218 __AISRCINIT();
219 _aiReg[AI_CONTROL] |= AI_DMAFR;
220 _CPU_ISR_Restore(level);
221 }
222
223 __AID_Callback = NULL;
224
225 __OldStack = NULL; // davem - use it or lose it
226 // looks like 3.4 isn't picking up the use from the asm below
227 __CallbackStack = stack;
228
229 IRQ_Request(IRQ_DSP_AI,__AIDHandler,NULL);
230 __UnmaskIrq(IRQMASK(IRQ_DSP_AI));
231 #if defined(HW_DOL)
232 __AIS_Callback = NULL;
233
234 IRQ_Request(IRQ_AI,__AISHandler,NULL);
235 __UnmaskIrq(IRQMASK(IRQ_AI));
236 #endif
237 __AIInitFlag = 1;
238 }
239 }
240
241 #if defined(HW_DOL)
AUDIO_SetStreamVolLeft(u8 vol)242 void AUDIO_SetStreamVolLeft(u8 vol)
243 {
244 _aiReg[1] = (_aiReg[1]&~0x000000ff)|(vol&0xff);
245 }
246
AUDIO_GetStreamVolLeft()247 u8 AUDIO_GetStreamVolLeft()
248 {
249 return (u8)(_aiReg[1]&0xff);
250 }
251
AUDIO_SetStreamVolRight(u8 vol)252 void AUDIO_SetStreamVolRight(u8 vol)
253 {
254 _aiReg[1] = (_aiReg[1]&~0x0000ff00)|(_SHIFTL(vol,8,8));
255 }
256
AUDIO_GetStreamVolRight()257 u8 AUDIO_GetStreamVolRight()
258 {
259 return (u8)(_SHIFTR(_aiReg[1],8,8));
260 }
261
AUDIO_SetStreamSampleRate(u32 rate)262 void AUDIO_SetStreamSampleRate(u32 rate)
263 {
264 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_AISFR)|(_SHIFTL(rate,1,1));
265 }
266
AUDIO_GetStreamSampleRate()267 u32 AUDIO_GetStreamSampleRate()
268 {
269 return _SHIFTR(_aiReg[AI_CONTROL],1,1);
270 }
271
AUDIO_SetStreamTrigger(u32 cnt)272 void AUDIO_SetStreamTrigger(u32 cnt)
273 {
274 _aiReg[3] = cnt;
275 }
276
AUDIO_ResetStreamSampleCnt()277 void AUDIO_ResetStreamSampleCnt()
278 {
279 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_SCRESET)|AI_SCRESET;
280 }
281
AUDIO_SetStreamPlayState(u32 state)282 void AUDIO_SetStreamPlayState(u32 state)
283 {
284 u32 playstate,streamrate;
285 u32 volright,volleft,level;
286
287 playstate = AUDIO_GetStreamPlayState();
288 streamrate = AUDIO_GetStreamSampleRate();
289 if(playstate!=state && state==AI_STREAM_START && streamrate==AI_SAMPLERATE_32KHZ ) {
290 volright = AUDIO_GetStreamVolRight();
291 AUDIO_SetStreamVolRight(0);
292 volleft = AUDIO_GetStreamVolLeft();
293 AUDIO_SetStreamVolLeft(0);
294
295 _CPU_ISR_Disable(level);
296 __AISRCINIT();
297 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_SCRESET)|AI_SCRESET;
298 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~0x01)|0x01;
299 _CPU_ISR_Restore(level);
300 AUDIO_SetStreamVolRight(volright);
301 AUDIO_SetStreamVolLeft(volleft);
302 } else {
303 _aiReg[AI_CONTROL] = (_aiReg[AI_CONTROL]&~AI_PSTAT)|(state&AI_PSTAT);
304 }
305 }
306
AUDIO_GetStreamPlayState()307 u32 AUDIO_GetStreamPlayState()
308 {
309 return (_aiReg[AI_CONTROL]&AI_PSTAT);
310 }
311 #endif
312
AUDIO_RegisterDMACallback(AIDCallback callback)313 AIDCallback AUDIO_RegisterDMACallback(AIDCallback callback)
314 {
315 u32 level;
316 AIDCallback old;
317
318 _CPU_ISR_Disable(level);
319 old = __AID_Callback;
320 __AID_Callback = callback;
321 _CPU_ISR_Restore(level);
322 return old;
323 }
324
AUDIO_InitDMA(u32 startaddr,u32 len)325 void AUDIO_InitDMA(u32 startaddr,u32 len)
326 {
327 u32 level;
328
329 _CPU_ISR_Disable(level);
330 _dspReg[24] = (_dspReg[24]&~0x1fff)|(_SHIFTR(startaddr,16,13));
331 _dspReg[25] = (_dspReg[25]&~0xffe0)|(startaddr&0xffff);
332 _dspReg[27] = (_dspReg[27]&~0x7fff)|(_SHIFTR(len,5,15));
333 _CPU_ISR_Restore(level);
334 }
335
AUDIO_GetDMAEnableFlag()336 u16 AUDIO_GetDMAEnableFlag()
337 {
338 return (_SHIFTR(_dspReg[27],15,1));
339 }
340
AUDIO_StartDMA()341 void AUDIO_StartDMA()
342 {
343 _dspReg[27] = (_dspReg[27]&~0x8000)|0x8000;
344 }
345
AUDIO_StopDMA()346 void AUDIO_StopDMA()
347 {
348 _dspReg[27] = (_dspReg[27]&~0x8000);
349 }
350
AUDIO_GetDMABytesLeft()351 u32 AUDIO_GetDMABytesLeft()
352 {
353 return (_SHIFTL(_dspReg[29],5,15));
354 }
355
AUDIO_GetDMAStartAddr()356 u32 AUDIO_GetDMAStartAddr()
357 {
358 return (_SHIFTL((_dspReg[24]&0x1fff),16,13)|(_dspReg[25]&0xffe0));
359 }
360
AUDIO_GetDMALength()361 u32 AUDIO_GetDMALength()
362 {
363 return ((_dspReg[27]&0x7fff)<<5);
364 }
365
AUDIO_SetDSPSampleRate(u8 rate)366 void AUDIO_SetDSPSampleRate(u8 rate)
367 {
368 u32 level;
369
370 if(AUDIO_GetDSPSampleRate()!=rate) {
371 _aiReg[AI_CONTROL] &= ~AI_DMAFR;
372 if(rate==AI_SAMPLERATE_32KHZ) {
373 _CPU_ISR_Disable(level);
374 __AISRCINIT();
375 _aiReg[AI_CONTROL] |= AI_DMAFR;
376 _CPU_ISR_Restore(level);
377 }
378 }
379 }
380
AUDIO_GetDSPSampleRate()381 u32 AUDIO_GetDSPSampleRate()
382 {
383 return (_SHIFTR(_aiReg[AI_CONTROL],6,1))^1; //0^1(1) = 48Khz, 1^1(0) = 32Khz
384 }
385