More catching up on old work. Refine audio interface setup on Coldfire. Stop the...
[Rockbox.git] / firmware / target / coldfire / pcm-coldfire.c
blob2addcb9da831f37f92366b4391152c1f14f713fd
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Michael Sevakis
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include <stdlib.h>
20 #include "system.h"
21 #include "kernel.h"
22 #include "logf.h"
23 #include "audio.h"
24 #if defined(HAVE_UDA1380)
25 #include "uda1380.h"
26 #elif defined(HAVE_TLV320)
27 #include "tlv320.h"
28 #endif
29 #if defined(HAVE_SPDIF_IN) || defined(HAVE_SPDIF_OUT)
30 #include "spdif.h"
31 #endif
33 /* peaks */
34 static unsigned long *rec_peak_addr;
35 enum
37 PLAY_PEAK_LEFT = 0,
38 PLAY_PEAK_RIGHT,
39 REC_PEAK_LEFT,
40 REC_PEAK_RIGHT
42 static int peaks[4]; /* p-l, p-r, r-l, r-r */
44 #define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
45 (IIS_PLAY & (7 << 8)) | \
46 (4 << 2) ) /* 64 bit clocks / word clock */
47 #define IIS_FIFO_RESET (1 << 11)
48 #define PDIR2_FIFO_RESET (1 << 9)
50 #if defined(IAUDIO_X5) || defined(IAUDIO_M5)
51 #define SET_IIS_PLAY(x) IIS1CONFIG = (x)
52 #define IIS_PLAY IIS1CONFIG
53 #else
54 #define SET_IIS_PLAY(x) IIS2CONFIG = (x)
55 #define IIS_PLAY IIS2CONFIG
56 #endif
58 #define PLLCR_SET_AUDIO_BITS_DEFPARM \
59 ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
61 /** Sample rates **/
62 #define FPARM_CLOCKSEL 0
63 #define FPARM_CLSEL 1
64 #define FPARM_FSEL 2
65 #if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380)
66 static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
68 [HW_FREQ_88] = { 0x0c, 0x01, 0x03 },
69 [HW_FREQ_44] = { 0x06, 0x01, 0x02 },
70 [HW_FREQ_22] = { 0x04, 0x02, 0x01 },
71 [HW_FREQ_11] = { 0x02, 0x02, 0x00 },
73 #endif
75 #if CONFIG_CPU == MCF5250 && defined(HAVE_TLV320)
76 static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
78 [HW_FREQ_88] = { 0x0c, 0x01, 0x02 },
79 [HW_FREQ_44] = { 0x06, 0x01, 0x01 },
80 [HW_FREQ_22] = { 0x04, 0x01, 0x00 },
81 [HW_FREQ_11] = { 0x02, 0x02, 0x00 },
83 #endif
85 static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */
86 static const unsigned char *freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT];
88 /* set frequency used by the audio hardware */
89 void pcm_set_frequency(unsigned int frequency)
91 int index;
93 switch(frequency)
95 case SAMPR_11:
96 index = HW_FREQ_11;
97 break;
98 case SAMPR_22:
99 index = HW_FREQ_22;
100 break;
101 default:
102 case SAMPR_44:
103 index = HW_FREQ_44;
104 break;
105 case SAMPR_88:
106 index = HW_FREQ_88;
107 break;
110 /* remember table entry and rate */
111 freq_ent = pcm_freq_parms[index];
112 pcm_freq = hw_freq_sampr[index];
113 } /* pcm_set_frequency */
115 /* apply audio settings */
116 void _pcm_apply_settings(bool clear_reset)
118 static int last_pcm_freq = 0;
120 if (pcm_freq != last_pcm_freq)
122 last_pcm_freq = pcm_freq;
123 /* Reprogramming bits 15-12 requires FIFO to be in a reset
124 condition - Users Manual 17-8, Note 11 */
125 or_l(IIS_FIFO_RESET, &IIS_PLAY);
126 audiohw_set_frequency(freq_ent[FPARM_FSEL]);
127 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
130 SET_IIS_PLAY(IIS_PLAY_DEFPARM |
131 (clear_reset ? 0 : (IIS_PLAY & IIS_FIFO_RESET)));
132 #if 0
133 logf("IISPLAY: %08X", IIS_PLAY);
134 #endif
135 } /* _pcm_apply_settings */
137 /* This clears the reset bit to enable monitoring immediately */
138 void pcm_apply_settings(void)
140 _pcm_apply_settings(true);
141 } /* pcm_apply_settings */
143 /** DMA **/
145 /****************************************************************************
146 ** Playback DMA transfer
149 /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
150 void pcm_play_dma_start(const void *addr, size_t size)
152 logf("pcm_play_dma_start");
154 addr = (void *)((unsigned long)addr & ~3); /* Align data */
155 size &= ~3; /* Size must be multiple of 4 */
157 pcm_playing = true;
159 /* Set up DMA transfer */
160 SAR0 = (unsigned long)addr; /* Source address */
161 DAR0 = (unsigned long)&PDOR3; /* Destination address */
162 BCR0 = (unsigned long)size; /* Bytes to transfer */
164 /* Enable the FIFO and force one write to it */
165 pcm_apply_settings();
167 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
168 DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
169 } /* pcm_play_dma_start */
171 /* Stops the DMA transfer and interrupt */
172 void pcm_play_dma_stop(void)
174 #if 0
175 logf("pcm_play_dma_stop");
176 #endif
178 pcm_playing = false;
180 DSR0 = 1;
181 DCR0 = 0;
183 /* Place FIFO in reset condition */
184 or_l(IIS_FIFO_RESET, &IIS_PLAY);
186 pcm_playing = false;
187 } /* pcm_play_dma_stop */
189 void pcm_init(void)
191 logf("pcm_init");
193 pcm_playing = false;
194 pcm_paused = false;
195 pcm_callback_for_more = NULL;
197 AUDIOGLOB = (1 << 8) /* IIS1 fifo auto sync */
198 | (1 << 7) /* PDIR2 fifo auto sync */
199 #ifdef HAVE_SPDIF_OUT
200 | (1 << 10) /* EBU TX auto sync */
201 #endif
203 DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
204 and_l(0xffffff00, &DMAROUTE);
205 or_l(DMA0_REQ_AUDIO_1, &DMAROUTE);
206 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
208 /* Call pcm_play_dma_stop to initialize everything. */
209 pcm_play_dma_stop();
210 /* Call pcm_close_recording to put in closed state */
211 pcm_close_recording();
212 audio_set_output_source(AUDIO_SRC_PLAYBACK);
213 audio_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
214 pcm_set_frequency(HW_FREQ_DEFAULT);
216 _pcm_apply_settings(false);
218 #if defined(HAVE_SPDIF_IN) || defined(HAVE_SPDIF_OUT)
219 spdif_init();
220 #endif
222 /* Initialize default register values. */
223 audiohw_init();
225 #if defined(HAVE_UDA1380)
226 /* Sleep a while so the power can stabilize (especially a long
227 delay is needed for the line out connector). */
228 sleep(HZ);
229 /* Power on FSDAC and HP amp. */
230 audiohw_enable_output(true);
231 #elif defined(HAVE_TLV320)
232 sleep(HZ/4);
233 #endif
235 /* UDA1380: Unmute the master channel
236 (DAC should be at zero point now). */
237 audiohw_mute(false);
239 /* Enable interrupt at level 7, priority 0 */
240 ICR6 = (7 << 2);
241 and_l(~(1 << 14), &IMR); /* bit 14 is DMA0 */
242 } /* pcm_init */
244 size_t pcm_get_bytes_waiting(void)
246 return BCR0 & 0xffffff;
247 } /* pcm_get_bytes_waiting */
249 /* DMA0 Interrupt is called when the DMA has finished transfering a chunk
250 from the caller's buffer */
251 void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
252 void DMA0(void)
254 int res = DSR0;
256 DSR0 = 1; /* Clear interrupt */
257 and_l(~DMA_EEXT, &DCR0); /* Disable peripheral request */
258 /* Stop on error */
259 if ((res & 0x70) == 0)
261 pcm_more_callback_type get_more = pcm_callback_for_more;
262 unsigned char *next_start;
263 size_t next_size = 0;
265 if (get_more)
266 get_more(&next_start, &next_size);
268 if (next_size > 0)
270 SAR0 = (unsigned long)next_start; /* Source address */
271 BCR0 = next_size; /* Bytes to transfer */
272 or_l(DMA_EEXT, &DCR0); /* Enable peripheral request */
273 return;
275 else
277 /* Finished playing */
278 #if 0
279 /* int. logfs can trash the display */
280 logf("DMA0 No Data:0x%04x", res);
281 #endif
284 else
286 logf("DMA0 err: %02x", res);
287 #if 0
288 logf(" SAR0: %08x", SAR0);
289 logf(" DAR0: %08x", DAR0);
290 logf(" BCR0: %08x", BCR0);
291 logf(" DCR0: %08x", DCR0);
292 #endif
295 pcm_play_dma_stop();
296 } /* DMA0 */
298 /****************************************************************************
299 ** Recording DMA transfer
301 void pcm_rec_dma_start(void *addr, size_t size)
303 logf("pcm_rec_dma_start");
305 addr = (void *)((unsigned long)addr & ~3); /* Align data */
306 size &= ~3; /* Size must be multiple of 4 */
308 pcm_recording = true;
310 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
311 /* Clear reset bit if the source is not set to monitor playback
312 otherwise maintain independence between playback and recording. */
313 _pcm_apply_settings((IIS_PLAY & (7 << 8)) != (3 << 8));
315 /* Start the DMA transfer.. */
316 #ifdef HAVE_SPDIF_IN
317 INTERRUPTCLEAR = 0x03c00000;
318 #endif
320 SAR1 = (unsigned long)&PDIR2; /* Source address */
321 rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */
322 DAR1 = (unsigned long)addr; /* Destination address */
323 BCR1 = (unsigned long)size; /* Bytes to transfer */
325 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
326 DMA_DSIZE(DMA_SIZE_LINE) /* | DMA_START */;
327 } /* pcm_dma_start */
329 void pcm_rec_dma_stop(void)
331 logf("pcm_rec_dma_stop");
333 DSR1 = 1; /* Clear interrupt */
334 DCR1 = 0;
336 pcm_recording = false;
337 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL);
338 } /* pcm_dma_stop */
340 void pcm_init_recording(void)
342 logf("pcm_init_recording");
344 pcm_recording = false;
345 pcm_callback_more_ready = NULL;
347 DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
348 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
349 and_l(0xffff00ff, &DMAROUTE);
350 or_l(DMA1_REQ_AUDIO_2, &DMAROUTE);
352 pcm_rec_dma_stop();
354 ICR7 = (7 << 2); /* Enable interrupt at level 7, priority 0 */
355 and_l(~(1 << 15), &IMR); /* bit 15 is DMA1 */
356 } /* pcm_init_recording */
358 void pcm_close_recording(void)
360 logf("pcm_close_recording");
362 pcm_rec_dma_stop();
364 and_l(0xffff00ff, &DMAROUTE);
365 ICR7 = 0x00; /* Disable interrupt */
366 or_l((1 << 15), &IMR); /* bit 15 is DMA1 */
367 } /* pcm_close_recording */
369 /* DMA1 Interrupt is called when the DMA has finished transfering a chunk
370 into the caller's buffer */
371 void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
372 void DMA1(void)
374 int res = DSR1;
375 int status = 0;
376 pcm_more_callback_type2 more_ready;
378 DSR1 = 1; /* Clear interrupt */
379 and_l(~DMA_EEXT, &DCR1); /* Disable peripheral request */
381 if (res & 0x70)
383 status = DMA_REC_ERROR_DMA;
384 logf("DMA1 err: %02x", res);
385 #if 0
386 logf(" SAR1: %08x", SAR1);
387 logf(" DAR1: %08x", DAR1);
388 logf(" BCR1: %08x", BCR1);
389 logf(" DCR1: %08x", DCR1);
390 #endif
392 #ifdef HAVE_SPDIF_IN
393 else if (DATAINCONTROL == 0xc038 &&
394 (INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */
396 INTERRUPTCLEAR = 0x03c00000;
397 status = DMA_REC_ERROR_SPDIF;
398 logf("spdif err");
400 #endif
402 more_ready = pcm_callback_more_ready;
404 if (more_ready != NULL && more_ready(status) >= 0)
405 return;
407 #if 0
408 /* int. logfs can trash the display */
409 logf("DMA1 done:%04x %d", res, status);
410 #endif
411 /* Finished recording */
412 pcm_rec_dma_stop();
413 } /* DMA1 */
415 /* Continue transferring data in */
416 void pcm_record_more(void *start, size_t size)
418 rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
419 DAR1 = (unsigned long)start; /* Destination address */
420 BCR1 = (unsigned long)size; /* Bytes to transfer */
421 or_l(DMA_EEXT, &DCR1); /* Enable peripheral request */
424 void pcm_mute(bool mute)
426 audiohw_mute(mute);
427 if (mute)
428 sleep(HZ/16);
429 } /* pcm_mute */
431 void pcm_play_pause_pause(void)
433 /* Disable DMA peripheral request. */
434 and_l(~DMA_EEXT, &DCR0);
435 or_l(IIS_FIFO_RESET, &IIS_PLAY);
436 } /* pcm_play_pause_pause */
438 void pcm_play_pause_unpause(void)
440 /* Enable the FIFO and force one write to it */
441 pcm_apply_settings();
442 or_l(DMA_EEXT | DMA_START, &DCR0);
443 } /* pcm_play_pause_unpause */
446 * Do peak calculation using distance squared from axis and save a lot
447 * of jumps and negation. Don't bother with the calculations of left or
448 * right only as it's never really used and won't save much time.
450 static void pcm_peak_peeker(unsigned long *addr, unsigned long *end,
451 int peaks[2])
453 long peak_l = 0, peak_r = 0;
454 long peaksq_l = 0, peaksq_r = 0;
458 long value = *addr;
459 long ch, chsq;
461 ch = value >> 16;
462 chsq = ch*ch;
463 if (chsq > peaksq_l)
464 peak_l = ch, peaksq_l = chsq;
466 ch = (short)value;
467 chsq = ch*ch;
468 if (chsq > peaksq_r)
469 peak_r = ch, peaksq_r = chsq;
471 addr += 4;
473 while (addr < end);
475 peaks[0] = abs(peak_l);
476 peaks[1] = abs(peak_r);
477 } /* pcm_peak_peeker */
480 * Return playback peaks - Peaks ahead in the DMA buffer based upon the
481 * calling period to attempt to compensate for
482 * delay.
484 void pcm_calculate_peaks(int *left, int *right)
486 static unsigned long last_peak_tick = 0;
487 static unsigned long frame_period = 0;
489 long samples, samp_frames;
490 unsigned long *addr;
492 /* Throttled peak ahead based on calling period */
493 unsigned long period = current_tick - last_peak_tick;
495 /* Keep reasonable limits on period */
496 if (period < 1)
497 period = 1;
498 else if (period > HZ/5)
499 period = HZ/5;
501 frame_period = (3*frame_period + period) >> 2;
503 last_peak_tick = current_tick;
505 if (pcm_playing && !pcm_paused)
507 /* Snapshot as quickly as possible */
508 asm volatile (
509 "move.l %c[sar0], %[start] \n"
510 "move.l %c[bcr0], %[count] \n"
511 : [start]"=r"(addr), [count]"=r"(samples)
512 : [sar0]"p"(&SAR0), [bcr0]"p"(&BCR0)
515 samples &= 0xfffffc;
516 samp_frames = frame_period*pcm_freq/(HZ/4);
517 samples = MIN(samp_frames, samples) >> 2;
519 if (samples > 0)
521 addr = (long *)((long)addr & ~3);
522 pcm_peak_peeker(addr, addr + samples, &peaks[PLAY_PEAK_LEFT]);
525 else
527 peaks[PLAY_PEAK_LEFT] = peaks[PLAY_PEAK_RIGHT] = 0;
530 if (left)
531 *left = peaks[PLAY_PEAK_LEFT];
533 if (right)
534 *right = peaks[PLAY_PEAK_RIGHT];
535 } /* pcm_calculate_peaks */
538 * Return recording peaks - From the end of the last peak up to
539 * current write position.
541 void pcm_calculate_rec_peaks(int *left, int *right)
543 if (pcm_recording)
545 unsigned long *addr, *end;
547 /* Snapshot as quickly as possible */
548 asm volatile (
549 "move.l %c[start], %[addr] \n"
550 "move.l %c[dar1], %[end] \n"
551 "and.l %[mask], %[addr] \n"
552 "and.l %[mask], %[end] \n"
553 : [addr]"=r"(addr), [end]"=r"(end)
554 : [start]"p"(&rec_peak_addr), [dar1]"p"(&DAR1), [mask]"r"(~3)
557 if (addr < end)
559 pcm_peak_peeker(addr, end, &peaks[REC_PEAK_LEFT]);
561 if (addr == rec_peak_addr)
562 rec_peak_addr = end;
565 else
567 peaks[REC_PEAK_LEFT] = peaks[REC_PEAK_RIGHT] = 0;
570 if (left)
571 *left = peaks[REC_PEAK_LEFT];
573 if (right)
574 *right = peaks[REC_PEAK_RIGHT];
575 } /* pcm_calculate_rec_peaks */