H100 S/PDIF recording: Check and clear the correct interrupt bits when recording...
[kugel-rb.git] / firmware / target / coldfire / pcm-coldfire.c
blobfaddf7047027661923d4688054a7e73cd16a3c89
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 #include "sound.h"
25 #if defined(HAVE_SPDIF_IN) || defined(HAVE_SPDIF_OUT)
26 #include "spdif.h"
27 #endif
29 /* peaks */
30 static unsigned long *rec_peak_addr;
31 enum
33 PLAY_PEAK_LEFT = 0,
34 PLAY_PEAK_RIGHT,
35 REC_PEAK_LEFT,
36 REC_PEAK_RIGHT
38 static int peaks[4]; /* p-l, p-r, r-l, r-r */
40 #define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
41 (IIS_PLAY & (7 << 8)) | \
42 (4 << 2) ) /* 64 bit clocks / word clock */
43 #define IIS_FIFO_RESET (1 << 11)
44 #define PDIR2_FIFO_RESET (1 << 9)
46 #if defined(IAUDIO_X5) || defined(IAUDIO_M5)
47 #define SET_IIS_PLAY(x) IIS1CONFIG = (x)
48 #define IIS_PLAY IIS1CONFIG
49 #else
50 #define SET_IIS_PLAY(x) IIS2CONFIG = (x)
51 #define IIS_PLAY IIS2CONFIG
52 #endif
54 static bool is_playback_monitoring(void)
56 return (IIS_PLAY & (7 << 8)) == (3 << 8);
59 static void iis_play_reset_if_playback(bool if_playback)
61 bool is_playback = is_playback_monitoring();
63 if (is_playback != if_playback)
64 return;
66 or_l(IIS_FIFO_RESET, &IIS_PLAY);
69 #define PLLCR_SET_AUDIO_BITS_DEFPARM \
70 ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
72 /** Sample rates **/
73 #define FPARM_CLOCKSEL 0
74 #define FPARM_CLSEL 1
75 #define FPARM_FSEL 2
76 #if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380)
77 static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
79 [HW_FREQ_88] = { 0x0c, 0x01, 0x03 },
80 [HW_FREQ_44] = { 0x06, 0x01, 0x02 },
81 [HW_FREQ_22] = { 0x04, 0x02, 0x01 },
82 [HW_FREQ_11] = { 0x02, 0x02, 0x00 },
84 #endif
86 #if CONFIG_CPU == MCF5250 && defined(HAVE_TLV320)
87 static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
89 [HW_FREQ_88] = { 0x0c, 0x01, 0x02 },
90 [HW_FREQ_44] = { 0x06, 0x01, 0x01 },
91 [HW_FREQ_22] = { 0x04, 0x01, 0x00 },
92 [HW_FREQ_11] = { 0x02, 0x02, 0x00 },
94 #endif
96 static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */
97 static const unsigned char *freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT];
99 /* set frequency used by the audio hardware */
100 void pcm_set_frequency(unsigned int frequency)
102 int index;
104 switch(frequency)
106 case SAMPR_11:
107 index = HW_FREQ_11;
108 break;
109 case SAMPR_22:
110 index = HW_FREQ_22;
111 break;
112 default:
113 case SAMPR_44:
114 index = HW_FREQ_44;
115 break;
116 case SAMPR_88:
117 index = HW_FREQ_88;
118 break;
121 /* remember table entry and rate */
122 freq_ent = pcm_freq_parms[index];
123 pcm_freq = hw_freq_sampr[index];
124 } /* pcm_set_frequency */
126 /* apply audio settings */
127 bool _pcm_apply_settings(bool clear_reset)
129 static int last_pcm_freq = 0;
130 bool did_reset = false;
131 unsigned long iis_play_defparm = IIS_PLAY_DEFPARM;
133 if (pcm_freq != last_pcm_freq)
135 last_pcm_freq = pcm_freq;
136 /* Reprogramming bits 15-12 requires FIFO to be in a reset
137 condition - Users Manual 17-8, Note 11 */
138 or_l(IIS_FIFO_RESET, &IIS_PLAY);
139 /* Important for TLV320 - this must happen in the correct order
140 or starting recording will sound absolutely awful once in
141 awhile - audiohw_set_frequency then coldfire_set_pllcr_audio_bits
143 SET_IIS_PLAY(iis_play_defparm | IIS_FIFO_RESET);
144 audiohw_set_frequency(freq_ent[FPARM_FSEL]);
145 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
146 did_reset = true;
149 /* If a reset was done because of a sample rate change, IIS_PLAY will have
150 been set already, so only needs to be set again if the reset flag must
151 be cleared. If the frequency didn't change, it was never altered and
152 the reset flag can just be removed or no action taken. */
153 if (clear_reset)
154 SET_IIS_PLAY(iis_play_defparm & ~IIS_FIFO_RESET);
155 #if 0
156 logf("IISPLAY: %08X", IIS_PLAY);
157 #endif
159 return did_reset;
160 } /* _pcm_apply_settings */
162 /* This clears the reset bit to enable monitoring immediately if monitoring
163 recording sources or always if playback is in progress - we might be
164 switching samplerates on the fly */
165 void pcm_apply_settings(void)
167 int level = set_irq_level(DMA_IRQ_LEVEL);
168 bool pbm = is_playback_monitoring();
169 bool kick = (DCR0 & DMA_EEXT) != 0 && pbm;
171 /* Clear reset if not playback monitoring or peripheral request is
172 active and playback monitoring */
173 if (_pcm_apply_settings(!pbm || kick) && kick)
174 PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
176 set_irq_level(level);
177 } /* pcm_apply_settings */
179 /** DMA **/
181 /****************************************************************************
182 ** Playback DMA transfer
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)
188 int level;
190 logf("pcm_play_dma_start");
192 addr = (void *)((unsigned long)addr & ~3); /* Align data */
193 size &= ~3; /* Size must be multiple of 4 */
195 /* If a tranfer is going, prevent an interrupt while setting up
196 a new one */
197 level = set_irq_level(DMA_IRQ_LEVEL);
199 pcm_playing = true;
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 */
206 /* Enable the FIFO and force one write to it */
207 _pcm_apply_settings(is_playback_monitoring());
209 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
210 DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
212 set_irq_level(level);
213 } /* pcm_play_dma_start */
215 /* Stops the DMA transfer and interrupt */
216 static void pcm_play_dma_stop_irq(void)
218 pcm_playing = false;
220 DSR0 = 1;
221 DCR0 = 0;
223 /* Place TX FIFO in reset condition if playback monitoring is on.
224 Recording monitoring something else should not be stopped. */
225 iis_play_reset_if_playback(true);
227 pcm_playing = false;
228 } /* pcm_play_dma_stop_irq */
230 void pcm_play_dma_stop(void)
232 int level = set_irq_level(DMA_IRQ_LEVEL);
234 logf("pcm_play_dma_stop");
236 pcm_play_dma_stop_irq();
238 set_irq_level(level);
239 } /* pcm_play_dma_stop */
241 void pcm_init(void)
243 logf("pcm_init");
245 pcm_playing = false;
246 pcm_paused = false;
247 pcm_callback_for_more = NULL;
249 AUDIOGLOB = (1 << 8) /* IIS1 fifo auto sync */
250 | (1 << 7) /* PDIR2 fifo auto sync */
251 #ifdef HAVE_SPDIF_OUT
252 | (1 << 10) /* EBU TX auto sync */
253 #endif
255 DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
256 and_l(0xffffff00, &DMAROUTE);
257 or_l(DMA0_REQ_AUDIO_1, &DMAROUTE);
258 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
260 /* Call pcm_play_dma_stop to initialize everything. */
261 pcm_play_dma_stop();
262 /* Call pcm_close_recording to put in closed state */
263 pcm_close_recording();
265 /* Setup Coldfire I2S before initializing hardware or changing
266 other settings. */
267 or_l(IIS_FIFO_RESET, &IIS_PLAY);
268 SET_IIS_PLAY(IIS_PLAY_DEFPARM | IIS_FIFO_RESET);
269 pcm_set_frequency(HW_FREQ_DEFAULT);
270 audio_set_output_source(AUDIO_SRC_PLAYBACK);
272 /* Initialize default register values. */
273 audiohw_init();
275 audio_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
277 audiohw_set_frequency(freq_ent[FPARM_FSEL]);
278 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
280 #if defined(HAVE_SPDIF_IN) || defined(HAVE_SPDIF_OUT)
281 spdif_init();
282 #endif
283 /* Enable interrupt at level 6, priority 0 */
284 ICR6 = (6 << 2);
285 and_l(~(1 << 14), &IMR); /* bit 14 is DMA0 */
286 } /* pcm_init */
288 void pcm_postinit(void)
290 audiohw_postinit();
293 size_t pcm_get_bytes_waiting(void)
295 return BCR0 & 0xffffff;
296 } /* pcm_get_bytes_waiting */
298 /* DMA0 Interrupt is called when the DMA has finished transfering a chunk
299 from the caller's buffer */
300 void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
301 void DMA0(void)
303 int res = DSR0;
305 DSR0 = 1; /* Clear interrupt */
306 and_l(~DMA_EEXT, &DCR0); /* Disable peripheral request */
307 /* Stop on error */
308 if ((res & 0x70) == 0)
310 pcm_more_callback_type get_more = pcm_callback_for_more;
311 unsigned char *next_start;
312 size_t next_size = 0;
314 if (get_more)
315 get_more(&next_start, &next_size);
317 if (next_size > 0)
319 SAR0 = (unsigned long)next_start; /* Source address */
320 BCR0 = next_size; /* Bytes to transfer */
321 or_l(DMA_EEXT, &DCR0); /* Enable peripheral request */
322 return;
324 else
326 /* Finished playing */
327 #if 0
328 /* int. logfs can trash the display */
329 logf("DMA0 No Data:0x%04x", res);
330 #endif
333 else
335 logf("DMA0 err: %02x", res);
336 #if 0
337 logf(" SAR0: %08x", SAR0);
338 logf(" DAR0: %08x", DAR0);
339 logf(" BCR0: %08x", BCR0);
340 logf(" DCR0: %08x", DCR0);
341 #endif
344 pcm_play_dma_stop_irq();
345 } /* DMA0 */
347 /****************************************************************************
348 ** Recording DMA transfer
350 void pcm_rec_dma_start(void *addr, size_t size)
352 int level;
353 logf("pcm_rec_dma_start");
355 addr = (void *)((unsigned long)addr & ~3); /* Align data */
356 size &= ~3; /* Size must be multiple of 4 */
358 /* No DMA1 interrupts while setting up a new transfer */
359 level = set_irq_level(DMA_IRQ_LEVEL);
361 pcm_recording = true;
363 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
364 /* Clear TX FIFO reset bit if the source is not set to monitor playback
365 otherwise maintain independence between playback and recording. */
366 _pcm_apply_settings(!is_playback_monitoring());
368 /* Start the DMA transfer.. */
369 #ifdef HAVE_SPDIF_IN
370 /* clear: ebu1cnew, valnogood, symbolerr, parityerr */
371 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
372 #endif
374 SAR1 = (unsigned long)&PDIR2; /* Source address */
375 rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */
376 DAR1 = (unsigned long)addr; /* Destination address */
377 BCR1 = (unsigned long)size; /* Bytes to transfer */
379 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
380 DMA_DSIZE(DMA_SIZE_LINE) /* | DMA_START */;
382 set_irq_level(level);
383 } /* pcm_dma_start */
385 static void pcm_rec_dma_stop_irq(void)
387 DSR1 = 1; /* Clear interrupt */
388 DCR1 = 0;
389 pcm_recording = false;
390 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL);
392 iis_play_reset_if_playback(false);
393 } /* pcm_rec_dma_stop_irq */
395 void pcm_rec_dma_stop(void)
397 int level = set_irq_level(DMA_IRQ_LEVEL);
399 logf("pcm_rec_dma_stop");
401 pcm_rec_dma_stop_irq();
403 set_irq_level(level);
404 } /* pcm_rec_dma_stop */
406 void pcm_init_recording(void)
408 int level = set_irq_level(DMA_IRQ_LEVEL);
410 logf("pcm_init_recording");
412 pcm_recording = false;
413 pcm_callback_more_ready = NULL;
415 DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
416 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
417 and_l(0xffff00ff, &DMAROUTE);
418 or_l(DMA1_REQ_AUDIO_2, &DMAROUTE);
420 pcm_rec_dma_stop_irq();
422 ICR7 = (6 << 2) | (1 << 0); /* Enable interrupt at level 6, priority 1 */
423 and_l(~(1 << 15), &IMR); /* bit 15 is DMA1 */
425 set_irq_level(level);
426 } /* pcm_init_recording */
428 void pcm_close_recording(void)
430 int level = set_irq_level(DMA_IRQ_LEVEL);
432 logf("pcm_close_recording");
434 pcm_rec_dma_stop_irq();
436 and_l(0xffff00ff, &DMAROUTE);
437 ICR7 = 0x00; /* Disable interrupt */
438 or_l((1 << 15), &IMR); /* bit 15 is DMA1 */
440 set_irq_level(level);
441 } /* pcm_close_recording */
443 /* DMA1 Interrupt is called when the DMA has finished transfering a chunk
444 into the caller's buffer */
445 void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
446 void DMA1(void)
448 int res = DSR1;
449 int status = 0;
450 pcm_more_callback_type2 more_ready;
452 DSR1 = 1; /* Clear interrupt */
453 and_l(~DMA_EEXT, &DCR1); /* Disable peripheral request */
455 if (res & 0x70)
457 status = DMA_REC_ERROR_DMA;
458 logf("DMA1 err: %02x", res);
459 #if 0
460 logf(" SAR1: %08x", SAR1);
461 logf(" DAR1: %08x", DAR1);
462 logf(" BCR1: %08x", BCR1);
463 logf(" DCR1: %08x", DCR1);
464 #endif
466 #ifdef HAVE_SPDIF_IN
467 else if (DATAINCONTROL == 0xc038 &&
468 (INTERRUPTSTAT & ((1 << 24) | (1 << 23) | (1 << 22))))
470 /* reason: valnogood, symbolerr, parityerr */
471 /* clear: ebu1cnew, valnogood, symbolerr, parityerr */
472 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
473 status = DMA_REC_ERROR_SPDIF;
474 logf("spdif err");
476 #endif
478 more_ready = pcm_callback_more_ready;
480 if (more_ready != NULL && more_ready(status) >= 0)
481 return;
483 #if 0
484 /* int. logfs can trash the display */
485 logf("DMA1 done:%04x %d", res, status);
486 #endif
487 /* Finished recording */
488 pcm_rec_dma_stop_irq();
489 } /* DMA1 */
491 /* Continue transferring data in - call from interrupt callback */
492 void pcm_record_more(void *start, size_t size)
494 rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
495 DAR1 = (unsigned long)start; /* Destination address */
496 BCR1 = (unsigned long)size; /* Bytes to transfer */
497 or_l(DMA_EEXT, &DCR1); /* Enable peripheral request */
500 void pcm_mute(bool mute)
502 audiohw_mute(mute);
503 if (mute)
504 sleep(HZ/16);
505 } /* pcm_mute */
507 void pcm_play_pause_pause(void)
509 /* Disable DMA peripheral request. */
510 int level = set_irq_level(DMA_IRQ_LEVEL);
512 and_l(~DMA_EEXT, &DCR0);
513 iis_play_reset_if_playback(true);
515 set_irq_level(level);
516 } /* pcm_play_pause_pause */
518 void pcm_play_pause_unpause(void)
520 int level = set_irq_level(DMA_IRQ_LEVEL);
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);
526 set_irq_level(level);
527 } /* pcm_play_pause_unpause */
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.
534 static void pcm_peak_peeker(unsigned long *addr, unsigned long *end,
535 int peaks[2])
537 long peak_l = 0, peak_r = 0;
538 long peaksq_l = 0, peaksq_r = 0;
542 long value = *addr;
543 long ch, chsq;
545 ch = value >> 16;
546 chsq = ch*ch;
547 if (chsq > peaksq_l)
548 peak_l = ch, peaksq_l = chsq;
550 ch = (short)value;
551 chsq = ch*ch;
552 if (chsq > peaksq_r)
553 peak_r = ch, peaksq_r = chsq;
555 addr += 4;
557 while (addr < end);
559 peaks[0] = abs(peak_l);
560 peaks[1] = abs(peak_r);
561 } /* pcm_peak_peeker */
564 * Return playback peaks - Peaks ahead in the DMA buffer based upon the
565 * calling period to attempt to compensate for
566 * delay.
568 void pcm_calculate_peaks(int *left, int *right)
570 static unsigned long last_peak_tick = 0;
571 static unsigned long frame_period = 0;
573 long samples, samp_frames;
574 unsigned long *addr;
576 /* Throttled peak ahead based on calling period */
577 unsigned long period = current_tick - last_peak_tick;
579 /* Keep reasonable limits on period */
580 if (period < 1)
581 period = 1;
582 else if (period > HZ/5)
583 period = HZ/5;
585 frame_period = (3*frame_period + period) >> 2;
587 last_peak_tick = current_tick;
589 if (pcm_playing && !pcm_paused)
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)
599 samples &= 0xfffffc;
600 samp_frames = frame_period*pcm_freq/(HZ/4);
601 samples = MIN(samp_frames, samples) >> 2;
603 if (samples > 0)
605 addr = (long *)((long)addr & ~3);
606 pcm_peak_peeker(addr, addr + samples, &peaks[PLAY_PEAK_LEFT]);
609 else
611 peaks[PLAY_PEAK_LEFT] = peaks[PLAY_PEAK_RIGHT] = 0;
614 if (left)
615 *left = peaks[PLAY_PEAK_LEFT];
617 if (right)
618 *right = peaks[PLAY_PEAK_RIGHT];
619 } /* pcm_calculate_peaks */
622 * Return recording peaks - From the end of the last peak up to
623 * current write position.
625 void pcm_calculate_rec_peaks(int *left, int *right)
627 if (pcm_recording)
629 unsigned long *addr, *end;
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)
641 if (addr < end)
643 pcm_peak_peeker(addr, end, &peaks[REC_PEAK_LEFT]);
645 if (addr == rec_peak_addr)
646 rec_peak_addr = end;
649 else
651 peaks[REC_PEAK_LEFT] = peaks[REC_PEAK_RIGHT] = 0;
654 if (left)
655 *left = peaks[REC_PEAK_LEFT];
657 if (right)
658 *right = peaks[REC_PEAK_RIGHT];
659 } /* pcm_calculate_rec_peaks */