diff options
-rw-r--r-- | firmware/target/coldfire/pcm-coldfire.c | 316 |
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 | ||
45 | struct 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)) | |
51 | static bool is_playback_monitoring(void) | 50 | #endif |
52 | { | ||
53 | return (IIS_PLAY & (7 << 8)) == (3 << 8); | ||
54 | } | ||
55 | |||
56 | static 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 | ||
92 | static const unsigned char *freq_ent; | 78 | static const unsigned char *freq_ent; |
93 | 79 | ||
94 | /* apply audio settings */ | 80 | /* Lock status struct for playback and recording */ |
95 | static bool _pcm_dma_apply_settings(bool clear_reset) | 81 | struct 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) | 87 | static 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 | 94 | static 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 | ||
99 | static 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 */ |
141 | void pcm_dma_apply_settings(void) | 111 | void 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 | ||
194 | void pcm_postinit(void) | 172 | void 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 */ |
226 | void pcm_play_dma_start(const void *addr, size_t size) | 205 | void 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 */ |
249 | void pcm_play_dma_stop(void) | 228 | void 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) | |||
288 | void DMA0(void) __attribute__ ((interrupt_handler, section(".icode"))); | 265 | void DMA0(void) __attribute__ ((interrupt_handler, section(".icode"))); |
289 | void DMA0(void) | 266 | void 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 | ||
338 | const void * pcm_play_dma_get_peak_buffer(int *count) | 312 | const 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) | |||
370 | void pcm_rec_dma_start(void *addr, size_t size) | 351 | void 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 | ||
398 | void pcm_rec_dma_stop(void) | 381 | void 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 | ||
423 | void pcm_rec_dma_close(void) | 407 | void 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) | |||
432 | void DMA1(void) __attribute__ ((interrupt_handler, section(".icode"))); | 418 | void DMA1(void) __attribute__ ((interrupt_handler, section(".icode"))); |
433 | void DMA1(void) | 419 | void 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 */ |
482 | void pcm_record_more(void *start, size_t size) | 464 | void 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 | ||
490 | const void * pcm_rec_dma_get_peak_buffer(int *count) | 481 | const 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); |