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