summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-03-07 06:23:02 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-03-07 06:23:02 +0000
commit633f3880024a2f83a21dd96368aa397940bc9ad6 (patch)
tree7c4319b1715c5c86252fd816764fdf53435163fb /firmware
parent2c94c1afc377c6605772008e6c27b06d579cecf4 (diff)
downloadrockbox-633f3880024a2f83a21dd96368aa397940bc9ad6.tar.gz
rockbox-633f3880024a2f83a21dd96368aa397940bc9ad6.zip
Coldfire targets: Shuffle IRQ levels around to have all interaction between low level audio function calls and DMA be atomic. Make recording and playback independently startable and stoppable so one can be running and not interfere with the other. All tests I can do at the moment check out ok (play, record, play+record, FM radio on iRivers, S/PDIF on H120 (w/running optical on/off), and on-the-fly samplerate changes). Recording tested for well over an hour run and no problems.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12658 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/target/coldfire/iaudio/m5/audio-m5.c2
-rw-r--r--firmware/target/coldfire/iaudio/m5/power-m5.c2
-rw-r--r--firmware/target/coldfire/iaudio/x5/audio-x5.c2
-rw-r--r--firmware/target/coldfire/iaudio/x5/power-x5.c2
-rw-r--r--firmware/target/coldfire/iriver/audio-iriver.c4
-rw-r--r--firmware/target/coldfire/iriver/h100/power-h100.c2
-rw-r--r--firmware/target/coldfire/iriver/h100/spdif-h100.c18
-rw-r--r--firmware/target/coldfire/iriver/h300/power-h300.c2
-rw-r--r--firmware/target/coldfire/pcm-coldfire.c134
-rw-r--r--firmware/target/coldfire/system-coldfire.c3
-rw-r--r--firmware/target/coldfire/system-target.h11
11 files changed, 146 insertions, 36 deletions
diff --git a/firmware/target/coldfire/iaudio/m5/audio-m5.c b/firmware/target/coldfire/iaudio/m5/audio-m5.c
index 9531f932ad..2442351fed 100644
--- a/firmware/target/coldfire/iaudio/m5/audio-m5.c
+++ b/firmware/target/coldfire/iaudio/m5/audio-m5.c
@@ -23,6 +23,7 @@
23 23
24void audio_set_output_source(int source) 24void audio_set_output_source(int source)
25{ 25{
26 int level = set_irq_level(DMA_IRQ_LEVEL);
26 unsigned long txsrc; 27 unsigned long txsrc;
27 28
28 if ((unsigned)source >= AUDIO_NUM_SOURCES) 29 if ((unsigned)source >= AUDIO_NUM_SOURCES)
@@ -31,6 +32,7 @@ void audio_set_output_source(int source)
31 txsrc = (4 << 8); /* recording, iis1RcvData */ 32 txsrc = (4 << 8); /* recording, iis1RcvData */
32 33
33 IIS1CONFIG = (IIS1CONFIG & ~(7 << 8)) | txsrc; 34 IIS1CONFIG = (IIS1CONFIG & ~(7 << 8)) | txsrc;
35 set_irq_level(level);
34} /* audio_set_output_source */ 36} /* audio_set_output_source */
35 37
36void audio_set_source(int source, unsigned flags) 38void audio_set_source(int source, unsigned flags)
diff --git a/firmware/target/coldfire/iaudio/m5/power-m5.c b/firmware/target/coldfire/iaudio/m5/power-m5.c
index c689488bfe..f3e7cdd496 100644
--- a/firmware/target/coldfire/iaudio/m5/power-m5.c
+++ b/firmware/target/coldfire/iaudio/m5/power-m5.c
@@ -60,7 +60,7 @@ bool ide_powered(void)
60void power_off(void) 60void power_off(void)
61{ 61{
62 lcd_remote_poweroff(); 62 lcd_remote_poweroff();
63 set_irq_level(HIGHEST_IRQ_LEVEL); 63 set_irq_level(DISABLE_INTERRUPTS);
64 and_l(~0x00000008, &GPIO_OUT); /* Set KEEPACT low */ 64 and_l(~0x00000008, &GPIO_OUT); /* Set KEEPACT low */
65 asm("halt"); 65 asm("halt");
66} 66}
diff --git a/firmware/target/coldfire/iaudio/x5/audio-x5.c b/firmware/target/coldfire/iaudio/x5/audio-x5.c
index e673d4ad47..91100ed751 100644
--- a/firmware/target/coldfire/iaudio/x5/audio-x5.c
+++ b/firmware/target/coldfire/iaudio/x5/audio-x5.c
@@ -23,6 +23,7 @@
23 23
24void audio_set_output_source(int source) 24void audio_set_output_source(int source)
25{ 25{
26 int level = set_irq_level(DMA_IRQ_LEVEL);
26 unsigned long txsrc; 27 unsigned long txsrc;
27 28
28 if ((unsigned)source >= AUDIO_NUM_SOURCES) 29 if ((unsigned)source >= AUDIO_NUM_SOURCES)
@@ -31,6 +32,7 @@ void audio_set_output_source(int source)
31 txsrc = (4 << 8); /* recording, iis1RcvData */ 32 txsrc = (4 << 8); /* recording, iis1RcvData */
32 33
33 IIS1CONFIG = (IIS1CONFIG & ~(7 << 8)) | txsrc; 34 IIS1CONFIG = (IIS1CONFIG & ~(7 << 8)) | txsrc;
35 set_irq_level(level);
34} /* audio_set_output_source */ 36} /* audio_set_output_source */
35 37
36void audio_set_source(int source, unsigned flags) 38void audio_set_source(int source, unsigned flags)
diff --git a/firmware/target/coldfire/iaudio/x5/power-x5.c b/firmware/target/coldfire/iaudio/x5/power-x5.c
index 4d44500fd5..c646570821 100644
--- a/firmware/target/coldfire/iaudio/x5/power-x5.c
+++ b/firmware/target/coldfire/iaudio/x5/power-x5.c
@@ -60,7 +60,7 @@ bool ide_powered(void)
60void power_off(void) 60void power_off(void)
61{ 61{
62 lcd_remote_poweroff(); 62 lcd_remote_poweroff();
63 set_irq_level(HIGHEST_IRQ_LEVEL); 63 set_irq_level(DISABLE_INTERRUPTS);
64 and_l(~0x00000008, &GPIO_OUT); /* Set KEEPACT low */ 64 and_l(~0x00000008, &GPIO_OUT); /* Set KEEPACT low */
65 asm("halt"); 65 asm("halt");
66} 66}
diff --git a/firmware/target/coldfire/iriver/audio-iriver.c b/firmware/target/coldfire/iriver/audio-iriver.c
index 2df7a216a9..bd071430b2 100644
--- a/firmware/target/coldfire/iriver/audio-iriver.c
+++ b/firmware/target/coldfire/iriver/audio-iriver.c
@@ -34,10 +34,14 @@ void audio_set_output_source(int source)
34 #endif 34 #endif
35 }; 35 };
36 36
37 int level = set_irq_level(DMA_IRQ_LEVEL);
38
37 if ((unsigned)source >= AUDIO_NUM_SOURCES) 39 if ((unsigned)source >= AUDIO_NUM_SOURCES)
38 source = AUDIO_SRC_PLAYBACK; 40 source = AUDIO_SRC_PLAYBACK;
39 41
40 IIS2CONFIG = (IIS2CONFIG & ~(7 << 8)) | (txsrc_select[source+1] << 8); 42 IIS2CONFIG = (IIS2CONFIG & ~(7 << 8)) | (txsrc_select[source+1] << 8);
43
44 set_irq_level(level);
41} /* audio_set_output_source */ 45} /* audio_set_output_source */
42 46
43void audio_set_source(int source, unsigned flags) 47void audio_set_source(int source, unsigned flags)
diff --git a/firmware/target/coldfire/iriver/h100/power-h100.c b/firmware/target/coldfire/iriver/h100/power-h100.c
index 75c8bea9dd..ce1c350802 100644
--- a/firmware/target/coldfire/iriver/h100/power-h100.c
+++ b/firmware/target/coldfire/iriver/h100/power-h100.c
@@ -119,7 +119,7 @@ bool ide_powered(void)
119 119
120void power_off(void) 120void power_off(void)
121{ 121{
122 set_irq_level(HIGHEST_IRQ_LEVEL); 122 set_irq_level(DISABLE_INTERRUPTS);
123 and_l(~0x00080000, &GPIO1_OUT); 123 and_l(~0x00080000, &GPIO1_OUT);
124 asm("halt"); 124 asm("halt");
125 while(1) 125 while(1)
diff --git a/firmware/target/coldfire/iriver/h100/spdif-h100.c b/firmware/target/coldfire/iriver/h100/spdif-h100.c
index 35508d10e8..ee4a9402ea 100644
--- a/firmware/target/coldfire/iriver/h100/spdif-h100.c
+++ b/firmware/target/coldfire/iriver/h100/spdif-h100.c
@@ -63,30 +63,42 @@ void spdif_set_output_source(int source, bool src_on)
63 }; 63 };
64 64
65 bool kick; 65 bool kick;
66 int level;
67 int iis2config = 0;
66 68
67 if ((unsigned)source >= ARRAYLEN(ebu1_config)) 69 if ((unsigned)source >= ARRAYLEN(ebu1_config))
68 source = AUDIO_SRC_PLAYBACK; 70 source = AUDIO_SRC_PLAYBACK;
69 71
70 spdif_source = source; 72 spdif_source = source;
71 spdif_on = spdif_powered() && src_on; 73 spdif_on = spdif_powered() && src_on;
72 kick = spdif_on && source == AUDIO_SRC_PLAYBACK; 74
75 /* Keep a DMA interrupt initiated stop from changing play state */
76 level = set_irq_level(DMA_IRQ_LEVEL);
77
78 kick = spdif_on && source == AUDIO_SRC_PLAYBACK
79 && (DCR0 & DMA_EEXT);
73 80
74 /* FIFO must be in reset condition to reprogram bits 15-12 */ 81 /* FIFO must be in reset condition to reprogram bits 15-12 */
75 or_l(0x800, &EBU1CONFIG); 82 or_l(0x800, &EBU1CONFIG);
76 83
77 if (kick) 84 if (kick)
85 {
86 iis2config = IIS2CONFIG;
78 or_l(0x800, &IIS2CONFIG); /* Have to resync IIS2 TXSRC */ 87 or_l(0x800, &IIS2CONFIG); /* Have to resync IIS2 TXSRC */
88 }
79 89
80 /* Tranceiver must be powered or else monitoring will be disabled. 90 /* Tranceiver must be powered or else monitoring will be disabled.
81 CLOCKSEL bits only have relevance to normal operation so just 91 CLOCKSEL bits only have relevance to normal operation so just
82 set them always. */ 92 set them always. */
83 EBU1CONFIG = (spdif_on ? ebu1_config[source + 1] : 0) | (7 << 12); 93 EBU1CONFIG = (spdif_on ? ebu1_config[source + 1] : 0) | (7 << 12);
84 94
85 if (kick && (DCR0 & DMA_EEXT)) /* only if still playing */ 95 if (kick)
86 { 96 {
87 and_l(~0x800, &IIS2CONFIG); 97 IIS2CONFIG = iis2config;
88 PDOR3 = 0; /* A write to the FIFO kick-starts playback */ 98 PDOR3 = 0; /* A write to the FIFO kick-starts playback */
89 } 99 }
100
101 set_irq_level(level);
90} /* spdif_set_output_source */ 102} /* spdif_set_output_source */
91 103
92/* Return the last set S/PDIF audio source */ 104/* Return the last set S/PDIF audio source */
diff --git a/firmware/target/coldfire/iriver/h300/power-h300.c b/firmware/target/coldfire/iriver/h300/power-h300.c
index 2875fa2a47..5e57326c36 100644
--- a/firmware/target/coldfire/iriver/h300/power-h300.c
+++ b/firmware/target/coldfire/iriver/h300/power-h300.c
@@ -91,7 +91,7 @@ bool ide_powered(void)
91 91
92void power_off(void) 92void power_off(void)
93{ 93{
94 set_irq_level(HIGHEST_IRQ_LEVEL); 94 set_irq_level(DISABLE_INTERRUPTS);
95 and_l(~0x00080000, &GPIO1_OUT); 95 and_l(~0x00080000, &GPIO1_OUT);
96 asm("halt"); 96 asm("halt");
97 while(1) 97 while(1)
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/**
diff --git a/firmware/target/coldfire/system-coldfire.c b/firmware/target/coldfire/system-coldfire.c
index 251c97fb73..f2ac075e14 100644
--- a/firmware/target/coldfire/system-coldfire.c
+++ b/firmware/target/coldfire/system-coldfire.c
@@ -324,5 +324,8 @@ void coldfire_set_pllcr_audio_bits(long bits)
324/* Set DATAINCONTROL without disturbing FIFO reset state */ 324/* Set DATAINCONTROL without disturbing FIFO reset state */
325void coldfire_set_dataincontrol(unsigned long value) 325void coldfire_set_dataincontrol(unsigned long value)
326{ 326{
327 /* Have to be atomic against recording stop initiated by DMA1 */
328 int level = set_irq_level(DMA_IRQ_LEVEL);
327 DATAINCONTROL = (DATAINCONTROL & (1 << 9)) | value; 329 DATAINCONTROL = (DATAINCONTROL & (1 << 9)) | value;
330 set_irq_level(level);
328} 331}
diff --git a/firmware/target/coldfire/system-target.h b/firmware/target/coldfire/system-target.h
index 31947a2883..97d096f0e8 100644
--- a/firmware/target/coldfire/system-target.h
+++ b/firmware/target/coldfire/system-target.h
@@ -57,7 +57,16 @@ static inline unsigned long coldfire_get_macsr(void)
57 return m; 57 return m;
58} 58}
59 59
60#define HIGHEST_IRQ_LEVEL (7<<8) 60/* ColdFire IRQ Levels/Priorities in Rockbox summary:
61 * DMA0 - level 6, priority 0 (playback)
62 * DMA1 - level 6, priority 1 (recording)
63 * TIMER1 - level 4, priority 0 (timers)
64 * TIMER0 - level 3, priority 0 (ticks)
65 * GPI0 - level 3, priority 0 (pcf50606 PMU, secondary controller)
66 */
67#define HIGHEST_IRQ_LEVEL (5<<8) /* Disable all but DMA and higher */
68#define DMA_IRQ_LEVEL (6<<8) /* Disable DMA and lower */
69#define DISABLE_INTERRUPTS (7<<8) /* Disable all but NMIs */
61static inline int set_irq_level(int level) 70static inline int set_irq_level(int level)
62{ 71{
63 int oldlevel; 72 int oldlevel;