summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2009-02-12 21:32:14 +0000
committerMichael Sevakis <jethead71@rockbox.org>2009-02-12 21:32:14 +0000
commitca5ca5b6efd635a10f1ab8f27e8a1632a759a191 (patch)
treee06483e54a3d05c6a722d391a23e114f1c9e27b5
parentb411f5eee54e09c3baeb0a6b089bf6e29dd9b790 (diff)
downloadrockbox-ca5ca5b6efd635a10f1ab8f27e8a1632a759a191.tar.gz
rockbox-ca5ca5b6efd635a10f1ab8f27e8a1632a759a191.zip
Give pcm-coldfire.c a much needed shakedown. Fixes FS#9378 - metronome freezes (works for me now on X5 and H120 after running it at 400bpm for an hour or so). The reason seems to have been DMA_INT in DCR should also be cleared when forcing a channel stop. Also fixes a dodgey keyclick without music playing that I was getting on H120.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19991 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/target/coldfire/pcm-coldfire.c316
1 files changed, 157 insertions, 159 deletions
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c
index 914947a98e..97e4de7e4c 100644
--- a/firmware/target/coldfire/pcm-coldfire.c
+++ b/firmware/target/coldfire/pcm-coldfire.c
@@ -8,6 +8,7 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2006 by Michael Sevakis 10 * Copyright (C) 2006 by Michael Sevakis
11 * Copyright (C) 2005 by Linus Nielsen Feltzing
11 * 12 *
12 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 14 * modify it under the terms of the GNU General Public License
@@ -28,45 +29,30 @@
28#include "spdif.h" 29#include "spdif.h"
29#endif 30#endif
30 31
31#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \ 32#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
32 (IIS_PLAY & (7 << 8)) | \ 33 (IIS_PLAY & (7 << 8)) | \
33 (4 << 2) ) /* 64 bit clocks / word clock */ 34 (4 << 2) ) /* 64 bit clocks / word clock */
34#define IIS_FIFO_RESET (1 << 11) 35#define IIS_FIFO_RESET (1 << 11)
35#define PDIR2_FIFO_RESET (1 << 9) 36#define PDIR2_FIFO_RESET (1 << 9)
36 37
37#if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(IAUDIO_M3) 38#if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(IAUDIO_M3)
38#define SET_IIS_PLAY(x) IIS1CONFIG = (x) 39#define IIS_PLAY IIS1CONFIG
39#define IIS_PLAY IIS1CONFIG
40#else 40#else
41#define SET_IIS_PLAY(x) IIS2CONFIG = (x) 41#define IIS_PLAY IIS2CONFIG
42#define IIS_PLAY IIS2CONFIG
43#endif 42#endif
44 43
45struct dma_lock 44#ifdef HAVE_SPDIF_OUT
46{ 45/* EBU TX auto sync, PDIR2 fifo auto sync, IIS1 fifo auto sync */
47 int locked; 46#define AUDIOGLOB_DEFPARM ((1 << 10) | (1 << 8) | (1 << 7))
48 unsigned long state; 47#else
49}; 48/* PDIR2 fifo auto sync, IIS1 fifo auto sync */
50 49#define AUDIOGLOB_DEFPARM ((1 << 8) | (1 << 7))
51static bool is_playback_monitoring(void) 50#endif
52{
53 return (IIS_PLAY & (7 << 8)) == (3 << 8);
54}
55
56static void iis_play_reset_if_playback(bool if_playback)
57{
58 bool is_playback = is_playback_monitoring();
59
60 if (is_playback != if_playback)
61 return;
62
63 or_l(IIS_FIFO_RESET, &IIS_PLAY);
64}
65 51
52/** Sample rates **/
66#define PLLCR_SET_AUDIO_BITS_DEFPARM \ 53#define PLLCR_SET_AUDIO_BITS_DEFPARM \
67 ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22)) 54 ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
68 55
69/** Sample rates **/
70#define FPARM_CLOCKSEL 0 56#define FPARM_CLOCKSEL 0
71#define FPARM_CLSEL 1 57#define FPARM_CLSEL 1
72#if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380) 58#if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380)
@@ -91,62 +77,62 @@ static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] =
91 77
92static const unsigned char *freq_ent; 78static const unsigned char *freq_ent;
93 79
94/* apply audio settings */ 80/* Lock status struct for playback and recording */
95static bool _pcm_dma_apply_settings(bool clear_reset) 81struct dma_lock
96{ 82{
97 bool did_reset = false; 83 int locked;
98 unsigned long iis_play_defparm; 84 unsigned long state;
99 85};
100 int level = set_irq_level(DMA_IRQ_LEVEL);
101
102 /* remember table entry */
103 freq_ent = pcm_freq_parms[pcm_fsel];
104
105 iis_play_defparm = IIS_PLAY_DEFPARM;
106 86
107 if (pcm_sampr != pcm_curr_sampr) 87static void iis_play_reset(void)
108 { 88{
109 /* Reprogramming bits 15-12 requires FIFO to be in a reset 89 or_l(IIS_FIFO_RESET, &IIS_PLAY);
110 condition - Users Manual 17-8, Note 11 */ 90 and_l(~IIS_FIFO_RESET, &IIS_PLAY);
111 or_l(IIS_FIFO_RESET, &IIS_PLAY); 91 PDOR3 = 0;
112 /* Important for TLV320 - this must happen in the correct order 92}
113 or starting recording will sound absolutely awful once in
114 awhile - audiohw_set_frequency then coldfire_set_pllcr_audio_bits
115 */
116 SET_IIS_PLAY(IIS_PLAY_DEFPARM | IIS_FIFO_RESET);
117 audiohw_set_frequency(pcm_fsel);
118 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
119 did_reset = true;
120 }
121 93
122 /* If a reset was done because of a sample rate change, IIS_PLAY will have 94static bool is_playback_monitoring(void)
123 been set already, so only needs to be set again if the reset flag must 95{
124 be cleared. If the frequency didn't change, it was never altered and 96 return (IIS_PLAY & (7 << 8)) == (3 << 8);
125 the reset flag can just be removed or no action taken. */ 97}
126 if (clear_reset)
127 SET_IIS_PLAY(IIS_PLAY_DEFPARM & ~IIS_FIFO_RESET);
128 98
99static void iis_play_reset_if_playback(bool if_playback)
100{
101 int level = set_irq_level(DMA_IRQ_LEVEL);
102 if (is_playback_monitoring() == if_playback)
103 iis_play_reset();
129 restore_irq(level); 104 restore_irq(level);
105}
130 106
131#if 0 107/* apply audio settings */
132 logf("IISPLAY: %08X", IIS_PLAY);
133#endif
134
135 return did_reset;
136} /* _pcm_dma_apply_settings */
137
138/* This clears the reset bit to enable monitoring immediately if monitoring 108/* This clears the reset bit to enable monitoring immediately if monitoring
139 recording sources or always if playback is in progress - we might be 109 recording sources or always if playback is in progress - we might be
140 switching samplerates on the fly */ 110 switching samplerates on the fly */
141void pcm_dma_apply_settings(void) 111void pcm_dma_apply_settings(void)
142{ 112{
143 int level = set_irq_level(DMA_IRQ_LEVEL); 113 int level = set_irq_level(DMA_IRQ_LEVEL);
144 bool pbm = is_playback_monitoring();
145 bool kick = (DCR0 & DMA_EEXT) != 0 && pbm;
146 114
147 /* Clear reset if not playback monitoring or peripheral request is 115 /* remember table entry */
148 active and playback monitoring */ 116 freq_ent = pcm_freq_parms[pcm_fsel];
149 if (_pcm_dma_apply_settings(!pbm || kick) && kick) 117
118 /* Reprogramming bits 15-12 requires FIFO to be in a reset
119 condition - Users Manual 17-8, Note 11 */
120 or_l(IIS_FIFO_RESET, &IIS_PLAY);
121 /* Important for TLV320 - this must happen in the correct order
122 or starting recording will sound absolutely awful once in
123 awhile - audiohw_set_frequency then coldfire_set_pllcr_audio_bits
124 */
125 IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET;
126 restore_irq(level);
127
128 audiohw_set_frequency(pcm_fsel);
129 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
130
131 level = set_irq_level(DMA_IRQ_LEVEL);
132
133 IIS_PLAY = IIS_PLAY_DEFPARM;
134
135 if ((DCR0 & DMA_EEXT) != 0 && is_playback_monitoring())
150 PDOR3 = 0; /* Kick FIFO out of reset by writing to it */ 136 PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
151 137
152 restore_irq(level); 138 restore_irq(level);
@@ -156,24 +142,18 @@ void pcm_play_dma_init(void)
156{ 142{
157 freq_ent = pcm_freq_parms[pcm_fsel]; 143 freq_ent = pcm_freq_parms[pcm_fsel];
158 144
159 AUDIOGLOB = (1 << 8) /* IIS1 fifo auto sync */ 145 AUDIOGLOB = AUDIOGLOB_DEFPARM;
160 | (1 << 7) /* PDIR2 fifo auto sync */ 146 DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
161#ifdef HAVE_SPDIF_OUT
162 | (1 << 10) /* EBU TX auto sync */
163#endif
164 ;
165 DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
166 and_l(0xffffff00, &DMAROUTE); 147 and_l(0xffffff00, &DMAROUTE);
167 or_l(DMA0_REQ_AUDIO_1, &DMAROUTE); 148 or_l(DMA0_REQ_AUDIO_1, &DMAROUTE);
168 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ 149 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
169 150 BCR0 = 0; /* No bytes waiting */
170 /* Call pcm_play_dma_stop to initialize everything. */ 151 ICR6 = (6 << 2); /* Enable interrupt at level 6, priority 0 */
171 pcm_play_dma_stop();
172 152
173 /* Setup Coldfire I2S before initializing hardware or changing 153 /* Setup Coldfire I2S before initializing hardware or changing
174 other settings. */ 154 other settings. */
175 or_l(IIS_FIFO_RESET, &IIS_PLAY); 155 or_l(IIS_FIFO_RESET, &IIS_PLAY);
176 SET_IIS_PLAY(IIS_PLAY_DEFPARM | IIS_FIFO_RESET); 156 IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET;
177 audio_set_output_source(AUDIO_SRC_PLAYBACK); 157 audio_set_output_source(AUDIO_SRC_PLAYBACK);
178 158
179 /* Initialize default register values. */ 159 /* Initialize default register values. */
@@ -187,13 +167,12 @@ void pcm_play_dma_init(void)
187#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT) 167#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
188 spdif_init(); 168 spdif_init();
189#endif 169#endif
190 /* Enable interrupt at level 6, priority 0 */
191 ICR6 = (6 << 2);
192} /* pcm_play_dma_init */ 170} /* pcm_play_dma_init */
193 171
194void pcm_postinit(void) 172void pcm_postinit(void)
195{ 173{
196 audiohw_postinit(); 174 audiohw_postinit();
175 iis_play_reset();
197} 176}
198 177
199/** DMA **/ 178/** DMA **/
@@ -225,22 +204,22 @@ void pcm_play_unlock(void)
225/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ 204/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
226void pcm_play_dma_start(const void *addr, size_t size) 205void pcm_play_dma_start(const void *addr, size_t size)
227{ 206{
228 logf("pcm_play_dma_start"); 207 /* Stop any DMA in progress */
208 pcm_play_dma_stop();
229 209
230 /* stop any DMA in progress */ 210 addr = (void *)(((long)addr + 3) & ~3);
231 DSR0 = 1; 211 size &= ~3;
232 DCR0 = 0; 212
213 if (size <= 0)
214 return;
233 215
234 /* Set up DMA transfer */ 216 /* Set up DMA transfer */
235 SAR0 = (unsigned long)addr; /* Source address */ 217 SAR0 = (unsigned long)addr; /* Source address */
236 DAR0 = (unsigned long)&PDOR3; /* Destination address */ 218 DAR0 = (unsigned long)&PDOR3; /* Destination address */
237 BCR0 = (unsigned long)size; /* Bytes to transfer */ 219 BCR0 = (unsigned long)size; /* Bytes to transfer */
238 220
239 /* Enable the FIFO and force one write to it */ 221 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_SINC |
240 _pcm_dma_apply_settings(is_playback_monitoring()); 222 DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
241
242 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
243 DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
244 223
245 dma_play_lock.state = (1 << 14); 224 dma_play_lock.state = (1 << 14);
246} /* pcm_play_dma_start */ 225} /* pcm_play_dma_start */
@@ -248,12 +227,10 @@ void pcm_play_dma_start(const void *addr, size_t size)
248/* Stops the DMA transfer and interrupt */ 227/* Stops the DMA transfer and interrupt */
249void pcm_play_dma_stop(void) 228void pcm_play_dma_stop(void)
250{ 229{
251 DSR0 = 1; 230 and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
252 DCR0 = 0; 231 BCR0 = 0; /* No bytes remaining */
253 BCR0 = 0; 232 DSR0 = 1; /* Clear interrupt, errors, stop transfer */
254 233
255 /* Place TX FIFO in reset condition if playback monitoring is on.
256 Recording monitoring something else should not be stopped. */
257 iis_play_reset_if_playback(true); 234 iis_play_reset_if_playback(true);
258 235
259 dma_play_lock.state = (0 << 14); 236 dma_play_lock.state = (0 << 14);
@@ -264,16 +241,16 @@ void pcm_play_dma_pause(bool pause)
264 if (pause) 241 if (pause)
265 { 242 {
266 /* pause playback on current buffer */ 243 /* pause playback on current buffer */
267 and_l(~DMA_EEXT, &DCR0); 244 and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
245 DSR0 = 1; /* stop channel */
268 iis_play_reset_if_playback(true); 246 iis_play_reset_if_playback(true);
269 dma_play_lock.state = (0 << 14); 247 dma_play_lock.state = (0 << 14);
270 } 248 }
271 else 249 else
272 { 250 {
273 /* restart playback on current buffer */ 251 /* restart playback on current buffer */
274 /* Enable the FIFO and force one write to it */ 252 iis_play_reset_if_playback(true);
275 _pcm_dma_apply_settings(is_playback_monitoring()); 253 or_l(DMA_INT | DMA_EEXT | DMA_START, &DCR0); /* everything ON */
276 or_l(DMA_EEXT | DMA_START, &DCR0);
277 dma_play_lock.state = (1 << 14); 254 dma_play_lock.state = (1 << 14);
278 } 255 }
279} /* pcm_play_dma_pause */ 256} /* pcm_play_dma_pause */
@@ -288,38 +265,14 @@ size_t pcm_get_bytes_waiting(void)
288void DMA0(void) __attribute__ ((interrupt_handler, section(".icode"))); 265void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
289void DMA0(void) 266void DMA0(void)
290{ 267{
291 int res = DSR0; 268 unsigned long res = DSR0;
292
293 DSR0 = 1; /* Clear interrupt */
294 and_l(~DMA_EEXT, &DCR0); /* Disable peripheral request */
295 /* Stop on error */
296 if ((res & 0x70) == 0)
297 {
298 pcm_more_callback_type get_more = pcm_callback_for_more;
299 unsigned char *next_start;
300 size_t next_size = 0;
301 269
302 if (get_more) 270 and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
303 get_more(&next_start, &next_size); 271 DSR0 = 1; /* Clear interrupt and errors */
304 272
305 if (next_size > 0) 273 if (res & 0x70)
306 {
307 SAR0 = (unsigned long)next_start; /* Source address */
308 BCR0 = next_size; /* Bytes to transfer */
309 or_l(DMA_EEXT, &DCR0); /* Enable peripheral request */
310 return;
311 }
312 else
313 {
314 /* Finished playing */
315#if 0
316 /* int. logfs can trash the display */
317 logf("DMA0 No Data:0x%04x", res);
318#endif
319 }
320 }
321 else
322 { 274 {
275 /* Stop on error */
323 logf("DMA0 err: %02x", res); 276 logf("DMA0 err: %02x", res);
324#if 0 277#if 0
325 logf(" SAR0: %08x", SAR0); 278 logf(" SAR0: %08x", SAR0);
@@ -328,6 +281,27 @@ void DMA0(void)
328 logf(" DCR0: %08x", DCR0); 281 logf(" DCR0: %08x", DCR0);
329#endif 282#endif
330 } 283 }
284 else
285 {
286 pcm_more_callback_type get_more = pcm_callback_for_more;
287 unsigned char *start;
288 size_t size = 0;
289
290 if (get_more)
291 get_more(&start, &size);
292
293 start = (unsigned char *)(((long)start + 3) & ~3);
294 size &= ~3;
295
296 if (size > 0)
297 {
298 SAR0 = (unsigned long)start; /* Source address */
299 BCR0 = size; /* Bytes to transfer */
300 or_l(DMA_EEXT | DMA_INT, &DCR0); /* per request and int ON */
301 return;
302 }
303 /* Finished playing */
304 }
331 305
332 /* Stop interrupt and futher transfers */ 306 /* Stop interrupt and futher transfers */
333 pcm_play_dma_stop(); 307 pcm_play_dma_stop();
@@ -337,8 +311,15 @@ void DMA0(void)
337 311
338const void * pcm_play_dma_get_peak_buffer(int *count) 312const void * pcm_play_dma_get_peak_buffer(int *count)
339{ 313{
340 unsigned long addr = SAR0; 314 unsigned long addr, cnt;
341 int cnt = BCR0; 315
316 /* Make sure interrupt doesn't change the second value after we read the
317 * first value. */
318 int level = set_irq_level(DMA_IRQ_LEVEL);
319 addr = SAR0;
320 cnt = BCR0;
321 restore_irq(level);
322
342 *count = (cnt & 0xffffff) >> 2; 323 *count = (cnt & 0xffffff) >> 2;
343 return (void *)((addr + 2) & ~3); 324 return (void *)((addr + 2) & ~3);
344} /* pcm_play_dma_get_peak_buffer */ 325} /* pcm_play_dma_get_peak_buffer */
@@ -370,13 +351,15 @@ void pcm_rec_unlock(void)
370void pcm_rec_dma_start(void *addr, size_t size) 351void pcm_rec_dma_start(void *addr, size_t size)
371{ 352{
372 /* stop any DMA in progress */ 353 /* stop any DMA in progress */
373 and_l(~DMA_EEXT, &DCR1); 354 pcm_rec_dma_stop();
374 DSR1 = 1; 355
356 addr = (void *)(((long)addr + 3) & ~3);
357 size &= ~3;
358
359 if (size <= 0)
360 return;
375 361
376 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL); 362 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
377 /* Clear TX FIFO reset bit if the source is not set to monitor playback
378 otherwise maintain independence between playback and recording. */
379 _pcm_dma_apply_settings(!is_playback_monitoring());
380 363
381 /* Start the DMA transfer.. */ 364 /* Start the DMA transfer.. */
382#ifdef HAVE_SPDIF_REC 365#ifdef HAVE_SPDIF_REC
@@ -384,10 +367,10 @@ void pcm_rec_dma_start(void *addr, size_t size)
384 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22); 367 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
385#endif 368#endif
386 369
387 SAR1 = (unsigned long)&PDIR2; /* Source address */
388 pcm_rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */ 370 pcm_rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */
389 DAR1 = (unsigned long)addr; /* Destination address */ 371 SAR1 = (unsigned long)&PDIR2; /* Source address */
390 BCR1 = (unsigned long)size; /* Bytes to transfer */ 372 DAR1 = (unsigned long)addr; /* Destination address */
373 BCR1 = (unsigned long)size; /* Bytes to transfer */
391 374
392 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC | 375 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
393 DMA_DSIZE(DMA_SIZE_LINE) | DMA_START; 376 DMA_DSIZE(DMA_SIZE_LINE) | DMA_START;
@@ -397,9 +380,10 @@ void pcm_rec_dma_start(void *addr, size_t size)
397 380
398void pcm_rec_dma_stop(void) 381void pcm_rec_dma_stop(void)
399{ 382{
400 DSR1 = 1; /* Clear interrupt */ 383 and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */
401 DCR1 = 0; 384 DSR1 = 1; /* Clear interrupt, errors, stop transfer */
402 BCR1 = 0; 385 BCR1 = 0; /* No bytes received */
386
403 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL); 387 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL);
404 388
405 iis_play_reset_if_playback(false); 389 iis_play_reset_if_playback(false);
@@ -422,6 +406,8 @@ void pcm_rec_dma_init(void)
422 406
423void pcm_rec_dma_close(void) 407void pcm_rec_dma_close(void)
424{ 408{
409 pcm_rec_dma_stop();
410
425 and_l(0xffff00ff, &DMAROUTE); 411 and_l(0xffff00ff, &DMAROUTE);
426 ICR7 = 0x00; /* Disable interrupt */ 412 ICR7 = 0x00; /* Disable interrupt */
427 dma_rec_lock.state = (0 << 15); 413 dma_rec_lock.state = (0 << 15);
@@ -432,12 +418,12 @@ void pcm_rec_dma_close(void)
432void DMA1(void) __attribute__ ((interrupt_handler, section(".icode"))); 418void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
433void DMA1(void) 419void DMA1(void)
434{ 420{
435 int res = DSR1; 421 unsigned long res = DSR1;
436 int status = 0; 422 int status = 0;
437 pcm_more_callback_type2 more_ready; 423 pcm_more_callback_type2 more_ready;
438 424
439 DSR1 = 1; /* Clear interrupt */ 425 and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */
440 and_l(~DMA_EEXT, &DCR1); /* Disable peripheral request */ 426 DSR1 = 1; /* Clear interrupt and errors */
441 427
442 if (res & 0x70) 428 if (res & 0x70)
443 { 429 {
@@ -468,10 +454,6 @@ void DMA1(void)
468 if (more_ready != NULL && more_ready(status) >= 0) 454 if (more_ready != NULL && more_ready(status) >= 0)
469 return; 455 return;
470 456
471#if 0
472 /* int. logfs can trash the display */
473 logf("DMA1 done:%04x %d", res, status);
474#endif
475 /* Finished recording */ 457 /* Finished recording */
476 pcm_rec_dma_stop(); 458 pcm_rec_dma_stop();
477 /* Inform PCM that we're done */ 459 /* Inform PCM that we're done */
@@ -481,16 +463,32 @@ void DMA1(void)
481/* Continue transferring data in - call from interrupt callback */ 463/* Continue transferring data in - call from interrupt callback */
482void pcm_record_more(void *start, size_t size) 464void pcm_record_more(void *start, size_t size)
483{ 465{
466 start = (void *)(((long)start + 3) & ~3);
467 size &= ~3;
468
469 if (size <= 0)
470 {
471 pcm_rec_dma_stop();
472 return;
473 }
474
484 pcm_rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */ 475 pcm_rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
485 DAR1 = (unsigned long)start; /* Destination address */ 476 DAR1 = (unsigned long)start; /* Destination address */
486 BCR1 = (unsigned long)size; /* Bytes to transfer */ 477 BCR1 = (unsigned long)size; /* Bytes to transfer */
487 or_l(DMA_EEXT, &DCR1); /* Enable peripheral request */ 478 or_l(DMA_EEXT | DMA_INT, &DCR1); /* per request and int ON */
488} /* pcm_record_more */ 479} /* pcm_record_more */
489 480
490const void * pcm_rec_dma_get_peak_buffer(int *count) 481const void * pcm_rec_dma_get_peak_buffer(int *count)
491{ 482{
492 unsigned long addr = (unsigned long)pcm_rec_peak_addr; 483 unsigned long addr, end;
493 unsigned long end = DAR1; 484
485 /* Make sure interrupt doesn't change the second value after we read the
486 * first value. */
487 int level = set_irq_level(DMA_IRQ_LEVEL);
488 addr = (unsigned long)pcm_rec_peak_addr;
489 end = DAR1;
490 restore_irq(level);
491
494 addr >>= 2; 492 addr >>= 2;
495 *count = (end >> 2) - addr; 493 *count = (end >> 2) - addr;
496 return (void *)(addr << 2); 494 return (void *)(addr << 2);