summaryrefslogtreecommitdiff
path: root/firmware/target/coldfire/pcm-coldfire.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/coldfire/pcm-coldfire.c')
-rw-r--r--firmware/target/coldfire/pcm-coldfire.c134
1 files changed, 106 insertions, 28 deletions
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c
index 2addcb9da8..ef847004ce 100644
--- a/firmware/target/coldfire/pcm-coldfire.c
+++ b/firmware/target/coldfire/pcm-coldfire.c
@@ -55,6 +55,21 @@ static int peaks[4]; /* p-l, p-r, r-l, r-r */
55#define IIS_PLAY IIS2CONFIG 55#define IIS_PLAY IIS2CONFIG
56#endif 56#endif
57 57
58static bool is_playback_monitoring(void)
59{
60 return (IIS_PLAY & (7 << 8)) == (3 << 8);
61}
62
63static void iis_play_reset_if_playback(bool if_playback)
64{
65 bool is_playback = is_playback_monitoring();
66
67 if (is_playback != if_playback)
68 return;
69
70 or_l(IIS_FIFO_RESET, &IIS_PLAY);
71}
72
58#define PLLCR_SET_AUDIO_BITS_DEFPARM \ 73#define PLLCR_SET_AUDIO_BITS_DEFPARM \
59 ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22)) 74 ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
60 75
@@ -113,9 +128,10 @@ void pcm_set_frequency(unsigned int frequency)
113} /* pcm_set_frequency */ 128} /* pcm_set_frequency */
114 129
115/* apply audio settings */ 130/* apply audio settings */
116void _pcm_apply_settings(bool clear_reset) 131bool _pcm_apply_settings(bool clear_reset)
117{ 132{
118 static int last_pcm_freq = 0; 133 static int last_pcm_freq = 0;
134 bool did_reset = false;
119 135
120 if (pcm_freq != last_pcm_freq) 136 if (pcm_freq != last_pcm_freq)
121 { 137 {
@@ -125,6 +141,7 @@ void _pcm_apply_settings(bool clear_reset)
125 or_l(IIS_FIFO_RESET, &IIS_PLAY); 141 or_l(IIS_FIFO_RESET, &IIS_PLAY);
126 audiohw_set_frequency(freq_ent[FPARM_FSEL]); 142 audiohw_set_frequency(freq_ent[FPARM_FSEL]);
127 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM); 143 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
144 did_reset = true;
128 } 145 }
129 146
130 SET_IIS_PLAY(IIS_PLAY_DEFPARM | 147 SET_IIS_PLAY(IIS_PLAY_DEFPARM |
@@ -132,12 +149,25 @@ void _pcm_apply_settings(bool clear_reset)
132#if 0 149#if 0
133 logf("IISPLAY: %08X", IIS_PLAY); 150 logf("IISPLAY: %08X", IIS_PLAY);
134#endif 151#endif
152
153 return did_reset;
135} /* _pcm_apply_settings */ 154} /* _pcm_apply_settings */
136 155
137/* This clears the reset bit to enable monitoring immediately */ 156/* This clears the reset bit to enable monitoring immediately if monitoring
157 recording sources or always if playback is in progress - we might be
158 switching samplerates on the fly */
138void pcm_apply_settings(void) 159void pcm_apply_settings(void)
139{ 160{
140 _pcm_apply_settings(true); 161 int level = set_irq_level(DMA_IRQ_LEVEL);
162 bool pbm = is_playback_monitoring();
163 bool kick = (DCR0 & DMA_EEXT) != 0 && pbm;
164
165 /* Clear reset if not playback monitoring or peripheral request is
166 active and playback monitoring */
167 if (_pcm_apply_settings(!pbm || kick) && kick)
168 PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
169
170 set_irq_level(level);
141} /* pcm_apply_settings */ 171} /* pcm_apply_settings */
142 172
143/** DMA **/ 173/** DMA **/
@@ -149,11 +179,17 @@ void pcm_apply_settings(void)
149/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ 179/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
150void pcm_play_dma_start(const void *addr, size_t size) 180void pcm_play_dma_start(const void *addr, size_t size)
151{ 181{
182 int level;
183
152 logf("pcm_play_dma_start"); 184 logf("pcm_play_dma_start");
153 185
154 addr = (void *)((unsigned long)addr & ~3); /* Align data */ 186 addr = (void *)((unsigned long)addr & ~3); /* Align data */
155 size &= ~3; /* Size must be multiple of 4 */ 187 size &= ~3; /* Size must be multiple of 4 */
156 188
189 /* If a tranfer is going, prevent an interrupt while setting up
190 a new one */
191 level = set_irq_level(DMA_IRQ_LEVEL);
192
157 pcm_playing = true; 193 pcm_playing = true;
158 194
159 /* Set up DMA transfer */ 195 /* Set up DMA transfer */
@@ -162,28 +198,38 @@ void pcm_play_dma_start(const void *addr, size_t size)
162 BCR0 = (unsigned long)size; /* Bytes to transfer */ 198 BCR0 = (unsigned long)size; /* Bytes to transfer */
163 199
164 /* Enable the FIFO and force one write to it */ 200 /* Enable the FIFO and force one write to it */
165 pcm_apply_settings(); 201 _pcm_apply_settings(is_playback_monitoring());
166 202
167 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | 203 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
168 DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START; 204 DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
205
206 set_irq_level(level);
169} /* pcm_play_dma_start */ 207} /* pcm_play_dma_start */
170 208
171/* Stops the DMA transfer and interrupt */ 209/* Stops the DMA transfer and interrupt */
172void pcm_play_dma_stop(void) 210static void pcm_play_dma_stop_irq(void)
173{ 211{
174#if 0
175 logf("pcm_play_dma_stop");
176#endif
177
178 pcm_playing = false; 212 pcm_playing = false;
179 213
180 DSR0 = 1; 214 DSR0 = 1;
181 DCR0 = 0; 215 DCR0 = 0;
182 216
183 /* Place FIFO in reset condition */ 217 /* Place TX FIFO in reset condition if playback monitoring is on.
184 or_l(IIS_FIFO_RESET, &IIS_PLAY); 218 Recording monitoring something else should not be stopped. */
219 iis_play_reset_if_playback(true);
185 220
186 pcm_playing = false; 221 pcm_playing = false;
222} /* pcm_play_dma_stop_irq */
223
224void pcm_play_dma_stop(void)
225{
226 int level = set_irq_level(DMA_IRQ_LEVEL);
227
228 logf("pcm_play_dma_stop");
229
230 pcm_play_dma_stop_irq();
231
232 set_irq_level(level);
187} /* pcm_play_dma_stop */ 233} /* pcm_play_dma_stop */
188 234
189void pcm_init(void) 235void pcm_init(void)
@@ -236,8 +282,8 @@ void pcm_init(void)
236 (DAC should be at zero point now). */ 282 (DAC should be at zero point now). */
237 audiohw_mute(false); 283 audiohw_mute(false);
238 284
239 /* Enable interrupt at level 7, priority 0 */ 285 /* Enable interrupt at level 6, priority 0 */
240 ICR6 = (7 << 2); 286 ICR6 = (6 << 2);
241 and_l(~(1 << 14), &IMR); /* bit 14 is DMA0 */ 287 and_l(~(1 << 14), &IMR); /* bit 14 is DMA0 */
242} /* pcm_init */ 288} /* pcm_init */
243 289
@@ -292,7 +338,7 @@ void DMA0(void)
292#endif 338#endif
293 } 339 }
294 340
295 pcm_play_dma_stop(); 341 pcm_play_dma_stop_irq();
296} /* DMA0 */ 342} /* DMA0 */
297 343
298/**************************************************************************** 344/****************************************************************************
@@ -300,17 +346,21 @@ void DMA0(void)
300 **/ 346 **/
301void pcm_rec_dma_start(void *addr, size_t size) 347void pcm_rec_dma_start(void *addr, size_t size)
302{ 348{
349 int level;
303 logf("pcm_rec_dma_start"); 350 logf("pcm_rec_dma_start");
304 351
305 addr = (void *)((unsigned long)addr & ~3); /* Align data */ 352 addr = (void *)((unsigned long)addr & ~3); /* Align data */
306 size &= ~3; /* Size must be multiple of 4 */ 353 size &= ~3; /* Size must be multiple of 4 */
307 354
355 /* No DMA1 interrupts while setting up a new transfer */
356 level = set_irq_level(DMA_IRQ_LEVEL);
357
308 pcm_recording = true; 358 pcm_recording = true;
309 359
310 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL); 360 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
311 /* Clear reset bit if the source is not set to monitor playback 361 /* Clear TX FIFO reset bit if the source is not set to monitor playback
312 otherwise maintain independence between playback and recording. */ 362 otherwise maintain independence between playback and recording. */
313 _pcm_apply_settings((IIS_PLAY & (7 << 8)) != (3 << 8)); 363 _pcm_apply_settings(!is_playback_monitoring());
314 364
315 /* Start the DMA transfer.. */ 365 /* Start the DMA transfer.. */
316#ifdef HAVE_SPDIF_IN 366#ifdef HAVE_SPDIF_IN
@@ -324,21 +374,35 @@ void pcm_rec_dma_start(void *addr, size_t size)
324 374
325 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC | 375 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
326 DMA_DSIZE(DMA_SIZE_LINE) /* | DMA_START */; 376 DMA_DSIZE(DMA_SIZE_LINE) /* | DMA_START */;
377
378 set_irq_level(level);
327} /* pcm_dma_start */ 379} /* pcm_dma_start */
328 380
329void pcm_rec_dma_stop(void) 381static void pcm_rec_dma_stop_irq(void)
330{ 382{
331 logf("pcm_rec_dma_stop");
332
333 DSR1 = 1; /* Clear interrupt */ 383 DSR1 = 1; /* Clear interrupt */
334 DCR1 = 0; 384 DCR1 = 0;
335
336 pcm_recording = false; 385 pcm_recording = false;
337 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL); 386 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL);
338} /* pcm_dma_stop */ 387
388 iis_play_reset_if_playback(false);
389} /* pcm_rec_dma_stop_irq */
390
391void pcm_rec_dma_stop(void)
392{
393 int level = set_irq_level(DMA_IRQ_LEVEL);
394
395 logf("pcm_rec_dma_stop");
396
397 pcm_rec_dma_stop_irq();
398
399 set_irq_level(level);
400} /* pcm_rec_dma_stop */
339 401
340void pcm_init_recording(void) 402void pcm_init_recording(void)
341{ 403{
404 int level = set_irq_level(DMA_IRQ_LEVEL);
405
342 logf("pcm_init_recording"); 406 logf("pcm_init_recording");
343 407
344 pcm_recording = false; 408 pcm_recording = false;
@@ -349,21 +413,27 @@ void pcm_init_recording(void)
349 and_l(0xffff00ff, &DMAROUTE); 413 and_l(0xffff00ff, &DMAROUTE);
350 or_l(DMA1_REQ_AUDIO_2, &DMAROUTE); 414 or_l(DMA1_REQ_AUDIO_2, &DMAROUTE);
351 415
352 pcm_rec_dma_stop(); 416 pcm_rec_dma_stop_irq();
353 417
354 ICR7 = (7 << 2); /* Enable interrupt at level 7, priority 0 */ 418 ICR7 = (6 << 2) | (1 << 0); /* Enable interrupt at level 6, priority 1 */
355 and_l(~(1 << 15), &IMR); /* bit 15 is DMA1 */ 419 and_l(~(1 << 15), &IMR); /* bit 15 is DMA1 */
420
421 set_irq_level(level);
356} /* pcm_init_recording */ 422} /* pcm_init_recording */
357 423
358void pcm_close_recording(void) 424void pcm_close_recording(void)
359{ 425{
426 int level = set_irq_level(DMA_IRQ_LEVEL);
427
360 logf("pcm_close_recording"); 428 logf("pcm_close_recording");
361 429
362 pcm_rec_dma_stop(); 430 pcm_rec_dma_stop_irq();
363 431
364 and_l(0xffff00ff, &DMAROUTE); 432 and_l(0xffff00ff, &DMAROUTE);
365 ICR7 = 0x00; /* Disable interrupt */ 433 ICR7 = 0x00; /* Disable interrupt */
366 or_l((1 << 15), &IMR); /* bit 15 is DMA1 */ 434 or_l((1 << 15), &IMR); /* bit 15 is DMA1 */
435
436 set_irq_level(level);
367} /* pcm_close_recording */ 437} /* pcm_close_recording */
368 438
369/* DMA1 Interrupt is called when the DMA has finished transfering a chunk 439/* DMA1 Interrupt is called when the DMA has finished transfering a chunk
@@ -409,10 +479,10 @@ void DMA1(void)
409 logf("DMA1 done:%04x %d", res, status); 479 logf("DMA1 done:%04x %d", res, status);
410#endif 480#endif
411 /* Finished recording */ 481 /* Finished recording */
412 pcm_rec_dma_stop(); 482 pcm_rec_dma_stop_irq();
413} /* DMA1 */ 483} /* DMA1 */
414 484
415/* Continue transferring data in */ 485/* Continue transferring data in - call from interrupt callback */
416void pcm_record_more(void *start, size_t size) 486void pcm_record_more(void *start, size_t size)
417{ 487{
418 rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */ 488 rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
@@ -431,15 +501,23 @@ void pcm_mute(bool mute)
431void pcm_play_pause_pause(void) 501void pcm_play_pause_pause(void)
432{ 502{
433 /* Disable DMA peripheral request. */ 503 /* Disable DMA peripheral request. */
504 int level = set_irq_level(DMA_IRQ_LEVEL);
505
434 and_l(~DMA_EEXT, &DCR0); 506 and_l(~DMA_EEXT, &DCR0);
435 or_l(IIS_FIFO_RESET, &IIS_PLAY); 507 iis_play_reset_if_playback(true);
508
509 set_irq_level(level);
436} /* pcm_play_pause_pause */ 510} /* pcm_play_pause_pause */
437 511
438void pcm_play_pause_unpause(void) 512void pcm_play_pause_unpause(void)
439{ 513{
514 int level = set_irq_level(DMA_IRQ_LEVEL);
515
440 /* Enable the FIFO and force one write to it */ 516 /* Enable the FIFO and force one write to it */
441 pcm_apply_settings(); 517 _pcm_apply_settings(is_playback_monitoring());
442 or_l(DMA_EEXT | DMA_START, &DCR0); 518 or_l(DMA_EEXT | DMA_START, &DCR0);
519
520 set_irq_level(level);
443} /* pcm_play_pause_unpause */ 521} /* pcm_play_pause_unpause */
444 522
445/** 523/**