diff options
Diffstat (limited to 'firmware/target/coldfire')
-rw-r--r-- | firmware/target/coldfire/pcm-coldfire.c | 478 |
1 files changed, 170 insertions, 308 deletions
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c index 315479f115..6d79ed08f1 100644 --- a/firmware/target/coldfire/pcm-coldfire.c +++ b/firmware/target/coldfire/pcm-coldfire.c | |||
@@ -26,17 +26,6 @@ | |||
26 | #include "spdif.h" | 26 | #include "spdif.h" |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | /* peaks */ | ||
30 | static unsigned long *rec_peak_addr; | ||
31 | enum | ||
32 | { | ||
33 | PLAY_PEAK_LEFT = 0, | ||
34 | PLAY_PEAK_RIGHT, | ||
35 | REC_PEAK_LEFT, | ||
36 | REC_PEAK_RIGHT | ||
37 | }; | ||
38 | static int peaks[4]; /* p-l, p-r, r-l, r-r */ | ||
39 | |||
40 | #define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \ | 29 | #define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \ |
41 | (IIS_PLAY & (7 << 8)) | \ | 30 | (IIS_PLAY & (7 << 8)) | \ |
42 | (4 << 2) ) /* 64 bit clocks / word clock */ | 31 | (4 << 2) ) /* 64 bit clocks / word clock */ |
@@ -51,6 +40,12 @@ static int peaks[4]; /* p-l, p-r, r-l, r-r */ | |||
51 | #define IIS_PLAY IIS2CONFIG | 40 | #define IIS_PLAY IIS2CONFIG |
52 | #endif | 41 | #endif |
53 | 42 | ||
43 | struct dma_lock | ||
44 | { | ||
45 | int locked; | ||
46 | unsigned long state; | ||
47 | }; | ||
48 | |||
54 | static bool is_playback_monitoring(void) | 49 | static bool is_playback_monitoring(void) |
55 | { | 50 | { |
56 | return (IIS_PLAY & (7 << 8)) == (3 << 8); | 51 | return (IIS_PLAY & (7 << 8)) == (3 << 8); |
@@ -93,7 +88,7 @@ static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] = | |||
93 | }; | 88 | }; |
94 | #endif | 89 | #endif |
95 | 90 | ||
96 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ | 91 | static unsigned long pcm_freq = 0; /* 44.1 is default */ |
97 | static const unsigned char *freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT]; | 92 | static const unsigned char *freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT]; |
98 | 93 | ||
99 | /* set frequency used by the audio hardware */ | 94 | /* set frequency used by the audio hardware */ |
@@ -126,13 +121,12 @@ void pcm_set_frequency(unsigned int frequency) | |||
126 | /* apply audio settings */ | 121 | /* apply audio settings */ |
127 | bool _pcm_apply_settings(bool clear_reset) | 122 | bool _pcm_apply_settings(bool clear_reset) |
128 | { | 123 | { |
129 | static int last_pcm_freq = 0; | ||
130 | bool did_reset = false; | 124 | bool did_reset = false; |
131 | unsigned long iis_play_defparm = IIS_PLAY_DEFPARM; | 125 | unsigned long iis_play_defparm = IIS_PLAY_DEFPARM; |
132 | 126 | ||
133 | if (pcm_freq != last_pcm_freq) | 127 | if (pcm_freq != pcm_curr_sampr) |
134 | { | 128 | { |
135 | last_pcm_freq = pcm_freq; | 129 | pcm_curr_sampr = pcm_freq; |
136 | /* Reprogramming bits 15-12 requires FIFO to be in a reset | 130 | /* Reprogramming bits 15-12 requires FIFO to be in a reset |
137 | condition - Users Manual 17-8, Note 11 */ | 131 | condition - Users Manual 17-8, Note 11 */ |
138 | or_l(IIS_FIFO_RESET, &IIS_PLAY); | 132 | or_l(IIS_FIFO_RESET, &IIS_PLAY); |
@@ -159,6 +153,14 @@ bool _pcm_apply_settings(bool clear_reset) | |||
159 | return did_reset; | 153 | return did_reset; |
160 | } /* _pcm_apply_settings */ | 154 | } /* _pcm_apply_settings */ |
161 | 155 | ||
156 | /* apply audio setting with all DMA interrupts disabled */ | ||
157 | void _pcm_apply_settings_irq_lock(bool clear_reset) | ||
158 | { | ||
159 | int level = set_irq_level(DMA_IRQ_LEVEL); | ||
160 | _pcm_apply_settings(clear_reset); | ||
161 | set_irq_level(level); | ||
162 | } | ||
163 | |||
162 | /* This clears the reset bit to enable monitoring immediately if monitoring | 164 | /* This clears the reset bit to enable monitoring immediately if monitoring |
163 | recording sources or always if playback is in progress - we might be | 165 | recording sources or always if playback is in progress - we might be |
164 | switching samplerates on the fly */ | 166 | switching samplerates on the fly */ |
@@ -176,76 +178,8 @@ void pcm_apply_settings(void) | |||
176 | set_irq_level(level); | 178 | set_irq_level(level); |
177 | } /* pcm_apply_settings */ | 179 | } /* pcm_apply_settings */ |
178 | 180 | ||
179 | /** DMA **/ | 181 | void pcm_play_dma_init(void) |
180 | |||
181 | /**************************************************************************** | ||
182 | ** Playback DMA transfer | ||
183 | **/ | ||
184 | |||
185 | /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ | ||
186 | void pcm_play_dma_start(const void *addr, size_t size) | ||
187 | { | ||
188 | int level; | ||
189 | |||
190 | logf("pcm_play_dma_start"); | ||
191 | |||
192 | addr = (void *)((unsigned long)addr & ~3); /* Align data */ | ||
193 | size &= ~3; /* Size must be multiple of 4 */ | ||
194 | |||
195 | /* If a tranfer is going, prevent an interrupt while setting up | ||
196 | a new one */ | ||
197 | level = set_irq_level(DMA_IRQ_LEVEL); | ||
198 | |||
199 | pcm_playing = true; | ||
200 | |||
201 | /* Set up DMA transfer */ | ||
202 | SAR0 = (unsigned long)addr; /* Source address */ | ||
203 | DAR0 = (unsigned long)&PDOR3; /* Destination address */ | ||
204 | BCR0 = (unsigned long)size; /* Bytes to transfer */ | ||
205 | |||
206 | /* Enable the FIFO and force one write to it */ | ||
207 | _pcm_apply_settings(is_playback_monitoring()); | ||
208 | |||
209 | DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | | ||
210 | DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START; | ||
211 | |||
212 | set_irq_level(level); | ||
213 | } /* pcm_play_dma_start */ | ||
214 | |||
215 | /* Stops the DMA transfer and interrupt */ | ||
216 | static void pcm_play_dma_stop_irq(void) | ||
217 | { | ||
218 | pcm_playing = false; | ||
219 | if (!audio_status()) | ||
220 | pcm_paused = false; | ||
221 | |||
222 | DSR0 = 1; | ||
223 | DCR0 = 0; | ||
224 | |||
225 | /* Place TX FIFO in reset condition if playback monitoring is on. | ||
226 | Recording monitoring something else should not be stopped. */ | ||
227 | iis_play_reset_if_playback(true); | ||
228 | } /* pcm_play_dma_stop_irq */ | ||
229 | |||
230 | void pcm_play_dma_stop(void) | ||
231 | { | 182 | { |
232 | int level = set_irq_level(DMA_IRQ_LEVEL); | ||
233 | |||
234 | logf("pcm_play_dma_stop"); | ||
235 | |||
236 | pcm_play_dma_stop_irq(); | ||
237 | |||
238 | set_irq_level(level); | ||
239 | } /* pcm_play_dma_stop */ | ||
240 | |||
241 | void pcm_init(void) | ||
242 | { | ||
243 | logf("pcm_init"); | ||
244 | |||
245 | pcm_playing = false; | ||
246 | pcm_paused = false; | ||
247 | pcm_callback_for_more = NULL; | ||
248 | |||
249 | AUDIOGLOB = (1 << 8) /* IIS1 fifo auto sync */ | 183 | AUDIOGLOB = (1 << 8) /* IIS1 fifo auto sync */ |
250 | | (1 << 7) /* PDIR2 fifo auto sync */ | 184 | | (1 << 7) /* PDIR2 fifo auto sync */ |
251 | #ifdef HAVE_SPDIF_OUT | 185 | #ifdef HAVE_SPDIF_OUT |
@@ -259,8 +193,6 @@ void pcm_init(void) | |||
259 | 193 | ||
260 | /* Call pcm_play_dma_stop to initialize everything. */ | 194 | /* Call pcm_play_dma_stop to initialize everything. */ |
261 | pcm_play_dma_stop(); | 195 | pcm_play_dma_stop(); |
262 | /* Call pcm_close_recording to put in closed state */ | ||
263 | pcm_close_recording(); | ||
264 | 196 | ||
265 | /* Setup Coldfire I2S before initializing hardware or changing | 197 | /* Setup Coldfire I2S before initializing hardware or changing |
266 | other settings. */ | 198 | other settings. */ |
@@ -282,14 +214,95 @@ void pcm_init(void) | |||
282 | #endif | 214 | #endif |
283 | /* Enable interrupt at level 6, priority 0 */ | 215 | /* Enable interrupt at level 6, priority 0 */ |
284 | ICR6 = (6 << 2); | 216 | ICR6 = (6 << 2); |
285 | and_l(~(1 << 14), &IMR); /* bit 14 is DMA0 */ | 217 | } /* pcm_play_dma_init */ |
286 | } /* pcm_init */ | ||
287 | 218 | ||
288 | void pcm_postinit(void) | 219 | void pcm_postinit(void) |
289 | { | 220 | { |
290 | audiohw_postinit(); | 221 | audiohw_postinit(); |
291 | } | 222 | } |
292 | 223 | ||
224 | /** DMA **/ | ||
225 | |||
226 | /**************************************************************************** | ||
227 | ** Playback DMA transfer | ||
228 | **/ | ||
229 | /* For the locks, DMA interrupt must be disabled when manipulating the lock | ||
230 | if the handler ever calls these - right now things are arranged so it | ||
231 | doesn't */ | ||
232 | static struct dma_lock dma_play_lock = | ||
233 | { | ||
234 | .locked = 0, | ||
235 | .state = (0 << 14) /* bit 14 is DMA0 */ | ||
236 | }; | ||
237 | |||
238 | void pcm_play_lock(void) | ||
239 | { | ||
240 | if (++dma_play_lock.locked == 1) | ||
241 | or_l((1 << 14), &IMR); | ||
242 | } | ||
243 | |||
244 | void pcm_play_unlock(void) | ||
245 | { | ||
246 | if (--dma_play_lock.locked == 0) | ||
247 | and_l(~dma_play_lock.state, &IMR); | ||
248 | } | ||
249 | |||
250 | /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ | ||
251 | void pcm_play_dma_start(const void *addr, size_t size) | ||
252 | { | ||
253 | logf("pcm_play_dma_start"); | ||
254 | |||
255 | /* stop any DMA in progress */ | ||
256 | DSR0 = 1; | ||
257 | DCR0 = 0; | ||
258 | |||
259 | /* Set up DMA transfer */ | ||
260 | SAR0 = (unsigned long)addr; /* Source address */ | ||
261 | DAR0 = (unsigned long)&PDOR3; /* Destination address */ | ||
262 | BCR0 = (unsigned long)size; /* Bytes to transfer */ | ||
263 | |||
264 | /* Enable the FIFO and force one write to it */ | ||
265 | _pcm_apply_settings_irq_lock(is_playback_monitoring()); | ||
266 | |||
267 | DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | | ||
268 | DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START; | ||
269 | |||
270 | dma_play_lock.state = (1 << 14); | ||
271 | } /* pcm_play_dma_start */ | ||
272 | |||
273 | /* Stops the DMA transfer and interrupt */ | ||
274 | void pcm_play_dma_stop(void) | ||
275 | { | ||
276 | DSR0 = 1; | ||
277 | DCR0 = 0; | ||
278 | BCR0 = 0; | ||
279 | |||
280 | /* Place TX FIFO in reset condition if playback monitoring is on. | ||
281 | Recording monitoring something else should not be stopped. */ | ||
282 | iis_play_reset_if_playback(true); | ||
283 | |||
284 | dma_play_lock.state = (0 << 14); | ||
285 | } /* pcm_play_dma_stop */ | ||
286 | |||
287 | void pcm_play_dma_pause(bool pause) | ||
288 | { | ||
289 | if (pause) | ||
290 | { | ||
291 | /* pause playback on current buffer */ | ||
292 | and_l(~DMA_EEXT, &DCR0); | ||
293 | iis_play_reset_if_playback(true); | ||
294 | dma_play_lock.state = (0 << 14); | ||
295 | } | ||
296 | else | ||
297 | { | ||
298 | /* restart playback on current buffer */ | ||
299 | /* Enable the FIFO and force one write to it */ | ||
300 | _pcm_apply_settings_irq_lock(is_playback_monitoring()); | ||
301 | or_l(DMA_EEXT | DMA_START, &DCR0); | ||
302 | dma_play_lock.state = (1 << 14); | ||
303 | } | ||
304 | } /* pcm_play_dma_pause */ | ||
305 | |||
293 | size_t pcm_get_bytes_waiting(void) | 306 | size_t pcm_get_bytes_waiting(void) |
294 | { | 307 | { |
295 | return BCR0 & 0xffffff; | 308 | return BCR0 & 0xffffff; |
@@ -341,29 +354,54 @@ void DMA0(void) | |||
341 | #endif | 354 | #endif |
342 | } | 355 | } |
343 | 356 | ||
344 | pcm_play_dma_stop_irq(); | 357 | /* Stop interrupt and futher transfers */ |
358 | pcm_play_dma_stop(); | ||
359 | /* Inform PCM that we're done */ | ||
360 | pcm_play_dma_stopped_callback(); | ||
345 | } /* DMA0 */ | 361 | } /* DMA0 */ |
346 | 362 | ||
363 | const void * pcm_play_dma_get_peak_buffer(int *count) | ||
364 | { | ||
365 | unsigned long addr = SAR0; | ||
366 | int cnt = BCR0; | ||
367 | *count = (cnt & 0xffffff) >> 2; | ||
368 | return (void *)((addr + 2) & ~3); | ||
369 | } /* pcm_play_dma_get_peak_buffer */ | ||
370 | |||
347 | /**************************************************************************** | 371 | /**************************************************************************** |
348 | ** Recording DMA transfer | 372 | ** Recording DMA transfer |
349 | **/ | 373 | **/ |
350 | void pcm_rec_dma_start(void *addr, size_t size) | 374 | static struct dma_lock dma_rec_lock = |
351 | { | 375 | { |
352 | int level; | 376 | .locked = 0, |
353 | logf("pcm_rec_dma_start"); | 377 | .state = (0 << 15) /* bit 15 is DMA1 */ |
378 | }; | ||
354 | 379 | ||
355 | addr = (void *)((unsigned long)addr & ~3); /* Align data */ | 380 | /* For the locks, DMA interrupt must be disabled when manipulating the lock |
356 | size &= ~3; /* Size must be multiple of 4 */ | 381 | if the handler ever calls these - right now things are arranged so it |
382 | doesn't */ | ||
383 | void pcm_rec_lock(void) | ||
384 | { | ||
385 | if (++dma_rec_lock.locked == 1) | ||
386 | or_l((1 << 15), &IMR); | ||
387 | } | ||
357 | 388 | ||
358 | /* No DMA1 interrupts while setting up a new transfer */ | 389 | void pcm_rec_unlock(void) |
359 | level = set_irq_level(DMA_IRQ_LEVEL); | 390 | { |
391 | if (--dma_rec_lock.locked == 0) | ||
392 | and_l(~dma_rec_lock.state, &IMR); | ||
393 | } | ||
360 | 394 | ||
361 | pcm_recording = true; | 395 | void pcm_rec_dma_start(void *addr, size_t size) |
396 | { | ||
397 | /* stop any DMA in progress */ | ||
398 | and_l(~DMA_EEXT, &DCR1); | ||
399 | DSR1 = 1; | ||
362 | 400 | ||
363 | and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL); | 401 | and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL); |
364 | /* Clear TX FIFO reset bit if the source is not set to monitor playback | 402 | /* Clear TX FIFO reset bit if the source is not set to monitor playback |
365 | otherwise maintain independence between playback and recording. */ | 403 | otherwise maintain independence between playback and recording. */ |
366 | _pcm_apply_settings(!is_playback_monitoring()); | 404 | _pcm_apply_settings_irq_lock(!is_playback_monitoring()); |
367 | 405 | ||
368 | /* Start the DMA transfer.. */ | 406 | /* Start the DMA transfer.. */ |
369 | #ifdef HAVE_SPDIF_REC | 407 | #ifdef HAVE_SPDIF_REC |
@@ -371,74 +409,48 @@ void pcm_rec_dma_start(void *addr, size_t size) | |||
371 | INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22); | 409 | INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22); |
372 | #endif | 410 | #endif |
373 | 411 | ||
374 | SAR1 = (unsigned long)&PDIR2; /* Source address */ | 412 | SAR1 = (unsigned long)&PDIR2; /* Source address */ |
375 | rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */ | 413 | pcm_rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */ |
376 | DAR1 = (unsigned long)addr; /* Destination address */ | 414 | DAR1 = (unsigned long)addr; /* Destination address */ |
377 | BCR1 = (unsigned long)size; /* Bytes to transfer */ | 415 | BCR1 = (unsigned long)size; /* Bytes to transfer */ |
378 | 416 | ||
379 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC | | 417 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC | |
380 | DMA_DSIZE(DMA_SIZE_LINE) /* | DMA_START */; | 418 | DMA_DSIZE(DMA_SIZE_LINE) | DMA_START; |
381 | 419 | ||
382 | set_irq_level(level); | 420 | dma_rec_lock.state = (1 << 15); |
383 | } /* pcm_dma_start */ | 421 | } /* pcm_rec_dma_start */ |
384 | 422 | ||
385 | static void pcm_rec_dma_stop_irq(void) | 423 | void pcm_rec_dma_stop(void) |
386 | { | 424 | { |
387 | DSR1 = 1; /* Clear interrupt */ | 425 | DSR1 = 1; /* Clear interrupt */ |
388 | DCR1 = 0; | 426 | DCR1 = 0; |
389 | pcm_recording = false; | 427 | BCR1 = 0; |
390 | or_l(PDIR2_FIFO_RESET, &DATAINCONTROL); | 428 | or_l(PDIR2_FIFO_RESET, &DATAINCONTROL); |
391 | 429 | ||
392 | iis_play_reset_if_playback(false); | 430 | iis_play_reset_if_playback(false); |
393 | } /* pcm_rec_dma_stop_irq */ | ||
394 | |||
395 | void pcm_rec_dma_stop(void) | ||
396 | { | ||
397 | int level = set_irq_level(DMA_IRQ_LEVEL); | ||
398 | |||
399 | logf("pcm_rec_dma_stop"); | ||
400 | |||
401 | pcm_rec_dma_stop_irq(); | ||
402 | 431 | ||
403 | set_irq_level(level); | 432 | dma_rec_lock.state = (0 << 15); |
404 | } /* pcm_rec_dma_stop */ | 433 | } /* pcm_rec_dma_stop */ |
405 | 434 | ||
406 | void pcm_init_recording(void) | 435 | void pcm_rec_dma_init(void) |
407 | { | 436 | { |
408 | int level = set_irq_level(DMA_IRQ_LEVEL); | 437 | DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */ |
409 | 438 | DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ | |
410 | logf("pcm_init_recording"); | ||
411 | |||
412 | pcm_recording = false; | ||
413 | pcm_callback_more_ready = NULL; | ||
414 | |||
415 | DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */ | ||
416 | DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ | ||
417 | and_l(0xffff00ff, &DMAROUTE); | 439 | and_l(0xffff00ff, &DMAROUTE); |
418 | or_l(DMA1_REQ_AUDIO_2, &DMAROUTE); | 440 | or_l(DMA1_REQ_AUDIO_2, &DMAROUTE); |
419 | 441 | ||
420 | pcm_rec_dma_stop_irq(); | 442 | pcm_rec_dma_stop(); |
421 | |||
422 | ICR7 = (6 << 2) | (1 << 0); /* Enable interrupt at level 6, priority 1 */ | ||
423 | and_l(~(1 << 15), &IMR); /* bit 15 is DMA1 */ | ||
424 | 443 | ||
425 | set_irq_level(level); | 444 | /* Enable interrupt at level 6, priority 1 */ |
445 | ICR7 = (6 << 2) | (1 << 0); | ||
426 | } /* pcm_init_recording */ | 446 | } /* pcm_init_recording */ |
427 | 447 | ||
428 | void pcm_close_recording(void) | 448 | void pcm_rec_dma_close(void) |
429 | { | 449 | { |
430 | int level = set_irq_level(DMA_IRQ_LEVEL); | ||
431 | |||
432 | logf("pcm_close_recording"); | ||
433 | |||
434 | pcm_rec_dma_stop_irq(); | ||
435 | |||
436 | and_l(0xffff00ff, &DMAROUTE); | 450 | and_l(0xffff00ff, &DMAROUTE); |
437 | ICR7 = 0x00; /* Disable interrupt */ | 451 | ICR7 = 0x00; /* Disable interrupt */ |
438 | or_l((1 << 15), &IMR); /* bit 15 is DMA1 */ | 452 | dma_rec_lock.state = (0 << 15); |
439 | 453 | } /* pcm_rec_dma_close */ | |
440 | set_irq_level(level); | ||
441 | } /* pcm_close_recording */ | ||
442 | 454 | ||
443 | /* DMA1 Interrupt is called when the DMA has finished transfering a chunk | 455 | /* DMA1 Interrupt is called when the DMA has finished transfering a chunk |
444 | into the caller's buffer */ | 456 | into the caller's buffer */ |
@@ -485,175 +497,25 @@ void DMA1(void) | |||
485 | logf("DMA1 done:%04x %d", res, status); | 497 | logf("DMA1 done:%04x %d", res, status); |
486 | #endif | 498 | #endif |
487 | /* Finished recording */ | 499 | /* Finished recording */ |
488 | pcm_rec_dma_stop_irq(); | 500 | pcm_rec_dma_stop(); |
501 | /* Inform PCM that we're done */ | ||
502 | pcm_rec_dma_stopped_callback(); | ||
489 | } /* DMA1 */ | 503 | } /* DMA1 */ |
490 | 504 | ||
491 | /* Continue transferring data in - call from interrupt callback */ | 505 | /* Continue transferring data in - call from interrupt callback */ |
492 | void pcm_record_more(void *start, size_t size) | 506 | void pcm_record_more(void *start, size_t size) |
493 | { | 507 | { |
494 | rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */ | 508 | pcm_rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */ |
495 | DAR1 = (unsigned long)start; /* Destination address */ | 509 | DAR1 = (unsigned long)start; /* Destination address */ |
496 | BCR1 = (unsigned long)size; /* Bytes to transfer */ | 510 | BCR1 = (unsigned long)size; /* Bytes to transfer */ |
497 | or_l(DMA_EEXT, &DCR1); /* Enable peripheral request */ | 511 | or_l(DMA_EEXT, &DCR1); /* Enable peripheral request */ |
498 | } | 512 | } /* pcm_record_more */ |
499 | 513 | ||
500 | void pcm_mute(bool mute) | 514 | const void * pcm_rec_dma_get_peak_buffer(int *count) |
501 | { | 515 | { |
502 | audiohw_mute(mute); | 516 | unsigned long addr = (unsigned long)pcm_rec_peak_addr; |
503 | if (mute) | 517 | unsigned long end = DAR1; |
504 | sleep(HZ/16); | 518 | addr >>= 2; |
505 | } /* pcm_mute */ | 519 | *count = (end >> 2) - addr; |
506 | 520 | return (void *)(addr << 2); | |
507 | void pcm_play_pause_pause(void) | 521 | } /* pcm_rec_dma_get_peak_buffer */ |
508 | { | ||
509 | /* Disable DMA peripheral request. */ | ||
510 | int level = set_irq_level(DMA_IRQ_LEVEL); | ||
511 | |||
512 | and_l(~DMA_EEXT, &DCR0); | ||
513 | iis_play_reset_if_playback(true); | ||
514 | |||
515 | set_irq_level(level); | ||
516 | } /* pcm_play_pause_pause */ | ||
517 | |||
518 | void pcm_play_pause_unpause(void) | ||
519 | { | ||
520 | int level = set_irq_level(DMA_IRQ_LEVEL); | ||
521 | |||
522 | /* Enable the FIFO and force one write to it */ | ||
523 | _pcm_apply_settings(is_playback_monitoring()); | ||
524 | or_l(DMA_EEXT | DMA_START, &DCR0); | ||
525 | |||
526 | set_irq_level(level); | ||
527 | } /* pcm_play_pause_unpause */ | ||
528 | |||
529 | /** | ||
530 | * Do peak calculation using distance squared from axis and save a lot | ||
531 | * of jumps and negation. Don't bother with the calculations of left or | ||
532 | * right only as it's never really used and won't save much time. | ||
533 | */ | ||
534 | static void pcm_peak_peeker(unsigned long *addr, unsigned long *end, | ||
535 | int peaks[2]) | ||
536 | { | ||
537 | long peak_l = 0, peak_r = 0; | ||
538 | long peaksq_l = 0, peaksq_r = 0; | ||
539 | |||
540 | do | ||
541 | { | ||
542 | long value = *addr; | ||
543 | long ch, chsq; | ||
544 | |||
545 | ch = value >> 16; | ||
546 | chsq = ch*ch; | ||
547 | if (chsq > peaksq_l) | ||
548 | peak_l = ch, peaksq_l = chsq; | ||
549 | |||
550 | ch = (short)value; | ||
551 | chsq = ch*ch; | ||
552 | if (chsq > peaksq_r) | ||
553 | peak_r = ch, peaksq_r = chsq; | ||
554 | |||
555 | addr += 4; | ||
556 | } | ||
557 | while (addr < end); | ||
558 | |||
559 | peaks[0] = abs(peak_l); | ||
560 | peaks[1] = abs(peak_r); | ||
561 | } /* pcm_peak_peeker */ | ||
562 | |||
563 | /** | ||
564 | * Return playback peaks - Peaks ahead in the DMA buffer based upon the | ||
565 | * calling period to attempt to compensate for | ||
566 | * delay. | ||
567 | */ | ||
568 | void pcm_calculate_peaks(int *left, int *right) | ||
569 | { | ||
570 | static unsigned long last_peak_tick = 0; | ||
571 | static unsigned long frame_period = 0; | ||
572 | |||
573 | long samples, samp_frames; | ||
574 | unsigned long *addr; | ||
575 | |||
576 | /* Throttled peak ahead based on calling period */ | ||
577 | unsigned long period = current_tick - last_peak_tick; | ||
578 | |||
579 | /* Keep reasonable limits on period */ | ||
580 | if (period < 1) | ||
581 | period = 1; | ||
582 | else if (period > HZ/5) | ||
583 | period = HZ/5; | ||
584 | |||
585 | frame_period = (3*frame_period + period) >> 2; | ||
586 | |||
587 | last_peak_tick = current_tick; | ||
588 | |||
589 | if (pcm_playing && !pcm_paused) | ||
590 | { | ||
591 | /* Snapshot as quickly as possible */ | ||
592 | asm volatile ( | ||
593 | "move.l %c[sar0], %[start] \n" | ||
594 | "move.l %c[bcr0], %[count] \n" | ||
595 | : [start]"=r"(addr), [count]"=r"(samples) | ||
596 | : [sar0]"p"(&SAR0), [bcr0]"p"(&BCR0) | ||
597 | ); | ||
598 | |||
599 | samples &= 0xfffffc; | ||
600 | samp_frames = frame_period*pcm_freq/(HZ/4); | ||
601 | samples = MIN(samp_frames, samples) >> 2; | ||
602 | |||
603 | if (samples > 0) | ||
604 | { | ||
605 | addr = (long *)((long)addr & ~3); | ||
606 | pcm_peak_peeker(addr, addr + samples, &peaks[PLAY_PEAK_LEFT]); | ||
607 | } | ||
608 | } | ||
609 | else | ||
610 | { | ||
611 | peaks[PLAY_PEAK_LEFT] = peaks[PLAY_PEAK_RIGHT] = 0; | ||
612 | } | ||
613 | |||
614 | if (left) | ||
615 | *left = peaks[PLAY_PEAK_LEFT]; | ||
616 | |||
617 | if (right) | ||
618 | *right = peaks[PLAY_PEAK_RIGHT]; | ||
619 | } /* pcm_calculate_peaks */ | ||
620 | |||
621 | /** | ||
622 | * Return recording peaks - From the end of the last peak up to | ||
623 | * current write position. | ||
624 | */ | ||
625 | void pcm_calculate_rec_peaks(int *left, int *right) | ||
626 | { | ||
627 | if (pcm_recording) | ||
628 | { | ||
629 | unsigned long *addr, *end; | ||
630 | |||
631 | /* Snapshot as quickly as possible */ | ||
632 | asm volatile ( | ||
633 | "move.l %c[start], %[addr] \n" | ||
634 | "move.l %c[dar1], %[end] \n" | ||
635 | "and.l %[mask], %[addr] \n" | ||
636 | "and.l %[mask], %[end] \n" | ||
637 | : [addr]"=r"(addr), [end]"=r"(end) | ||
638 | : [start]"p"(&rec_peak_addr), [dar1]"p"(&DAR1), [mask]"r"(~3) | ||
639 | ); | ||
640 | |||
641 | if (addr < end) | ||
642 | { | ||
643 | pcm_peak_peeker(addr, end, &peaks[REC_PEAK_LEFT]); | ||
644 | |||
645 | if (addr == rec_peak_addr) | ||
646 | rec_peak_addr = end; | ||
647 | } | ||
648 | } | ||
649 | else | ||
650 | { | ||
651 | peaks[REC_PEAK_LEFT] = peaks[REC_PEAK_RIGHT] = 0; | ||
652 | } | ||
653 | |||
654 | if (left) | ||
655 | *left = peaks[REC_PEAK_LEFT]; | ||
656 | |||
657 | if (right) | ||
658 | *right = peaks[REC_PEAK_RIGHT]; | ||
659 | } /* pcm_calculate_rec_peaks */ | ||