diff options
author | Barry Wardell <rockbox@barrywardell.net> | 2006-12-18 01:52:21 +0000 |
---|---|---|
committer | Barry Wardell <rockbox@barrywardell.net> | 2006-12-18 01:52:21 +0000 |
commit | df0dc2262ea10f621677c0f97aae1c205e253b87 (patch) | |
tree | d25085132fe9f0504d221360092537492cedd3b8 /firmware/pcm_playback.c | |
parent | 440353a9aa1159584b977a2852e723ae07bad2a6 (diff) | |
download | rockbox-df0dc2262ea10f621677c0f97aae1c205e253b87.tar.gz rockbox-df0dc2262ea10f621677c0f97aae1c205e253b87.zip |
FS#6096. Recording on PortalPlayer targets (H10, iPod Video, iPod 4g, iPod Color, iPod Nano).
* Fix failed compile of enc_config.c when HAVE_MPEG2_SAMPR is not defined.
* Fix bug in AIFF encoder header creation on little endian targets.
* Add recording screen keymaps for H10 and iPod.
* Move pcm_playback PP specific code to target tree.
* Add recording code to wmcodec drivers.
* Add pcm_record code.
Some problems still remain:
* Playback doesn't work after recording until Rockbox is restarted.
* Gain control not implemented.
* Only 16-bit/44KHz for now. The hardware should be capable of up to 24-bit/96KHz.
* Line-in recording not tested on H10.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11794 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/pcm_playback.c')
-rw-r--r-- | firmware/pcm_playback.c | 328 |
1 files changed, 3 insertions, 325 deletions
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 46a458fa8a..92a4c3e5c7 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c | |||
@@ -98,326 +98,6 @@ size_t pcm_get_bytes_waiting(void) | |||
98 | return 0; | 98 | return 0; |
99 | } | 99 | } |
100 | 100 | ||
101 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
102 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) \ | ||
103 | || defined(HAVE_PP5024_CODEC) | ||
104 | |||
105 | /* We need to unify this code with the uda1380 code as much as possible, but | ||
106 | we will keep it separate during early development. | ||
107 | */ | ||
108 | |||
109 | #if CONFIG_CPU == PP5020 | ||
110 | #define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x3f0000) >> 16) | ||
111 | #elif CONFIG_CPU == PP5002 | ||
112 | #define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x7800000) >> 23) | ||
113 | #elif CONFIG_CPU == PP5024 | ||
114 | #define FIFO_FREE_COUNT 4 /* TODO: make this sensible */ | ||
115 | #endif | ||
116 | |||
117 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ | ||
118 | |||
119 | /* NOTE: The order of these two variables is important if you use the iPod | ||
120 | assembler optimised fiq handler, so don't change it. */ | ||
121 | unsigned short* p IBSS_ATTR; | ||
122 | size_t p_size IBSS_ATTR; | ||
123 | |||
124 | void pcm_play_dma_start(const void *addr, size_t size) | ||
125 | { | ||
126 | p=(unsigned short*)addr; | ||
127 | p_size=size; | ||
128 | |||
129 | pcm_playing = true; | ||
130 | |||
131 | #if CONFIG_CPU == PP5020 | ||
132 | /* setup I2S interrupt for FIQ */ | ||
133 | outl(inl(0x6000402c) | I2S_MASK, 0x6000402c); | ||
134 | outl(I2S_MASK, 0x60004024); | ||
135 | #elif CONFIG_CPU == PP5024 | ||
136 | #else | ||
137 | /* setup I2S interrupt for FIQ */ | ||
138 | outl(inl(0xcf00102c) | DMA_OUT_MASK, 0xcf00102c); | ||
139 | outl(DMA_OUT_MASK, 0xcf001024); | ||
140 | #endif | ||
141 | |||
142 | /* Clear the FIQ disable bit in cpsr_c */ | ||
143 | enable_fiq(); | ||
144 | |||
145 | /* Enable playback FIFO */ | ||
146 | #if CONFIG_CPU == PP5020 | ||
147 | IISCONFIG |= 0x20000000; | ||
148 | #elif CONFIG_CPU == PP5002 | ||
149 | IISCONFIG |= 0x4; | ||
150 | #endif | ||
151 | |||
152 | /* Fill the FIFO - we assume there are enough bytes in the pcm buffer to | ||
153 | fill the 32-byte FIFO. */ | ||
154 | while (p_size > 0) { | ||
155 | if (FIFO_FREE_COUNT < 2) { | ||
156 | /* Enable interrupt */ | ||
157 | #if CONFIG_CPU == PP5020 | ||
158 | IISCONFIG |= 0x2; | ||
159 | #elif CONFIG_CPU == PP5002 | ||
160 | IISFIFO_CFG |= (1<<9); | ||
161 | #endif | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | IISFIFO_WR = (*(p++))<<16; | ||
166 | IISFIFO_WR = (*(p++))<<16; | ||
167 | p_size-=4; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /* Stops the DMA transfer and interrupt */ | ||
172 | void pcm_play_dma_stop(void) | ||
173 | { | ||
174 | pcm_playing = false; | ||
175 | |||
176 | #if CONFIG_CPU == PP5020 | ||
177 | |||
178 | /* Disable playback FIFO */ | ||
179 | IISCONFIG &= ~0x20000000; | ||
180 | |||
181 | /* Disable the interrupt */ | ||
182 | IISCONFIG &= ~0x2; | ||
183 | |||
184 | #elif CONFIG_CPU == PP5002 | ||
185 | |||
186 | /* Disable playback FIFO */ | ||
187 | IISCONFIG &= ~0x4; | ||
188 | |||
189 | /* Disable the interrupt */ | ||
190 | IISFIFO_CFG &= ~(1<<9); | ||
191 | #endif | ||
192 | |||
193 | disable_fiq(); | ||
194 | } | ||
195 | |||
196 | void pcm_play_pause_pause(void) | ||
197 | { | ||
198 | #if CONFIG_CPU == PP5020 | ||
199 | /* Disable the interrupt */ | ||
200 | IISCONFIG &= ~0x2; | ||
201 | /* Disable playback FIFO */ | ||
202 | IISCONFIG &= ~0x20000000; | ||
203 | #elif CONFIG_CPU == PP5002 | ||
204 | /* Disable the interrupt */ | ||
205 | IISFIFO_CFG &= ~(1<<9); | ||
206 | /* Disable playback FIFO */ | ||
207 | IISCONFIG &= ~0x4; | ||
208 | #endif | ||
209 | disable_fiq(); | ||
210 | } | ||
211 | |||
212 | void pcm_play_pause_unpause(void) | ||
213 | { | ||
214 | /* Enable the FIFO and fill it */ | ||
215 | |||
216 | enable_fiq(); | ||
217 | |||
218 | /* Enable playback FIFO */ | ||
219 | #if CONFIG_CPU == PP5020 | ||
220 | IISCONFIG |= 0x20000000; | ||
221 | #elif CONFIG_CPU == PP5002 | ||
222 | IISCONFIG |= 0x4; | ||
223 | #endif | ||
224 | |||
225 | /* Fill the FIFO - we assume there are enough bytes in the | ||
226 | pcm buffer to fill the 32-byte FIFO. */ | ||
227 | while (p_size > 0) { | ||
228 | if (FIFO_FREE_COUNT < 2) { | ||
229 | /* Enable interrupt */ | ||
230 | #if CONFIG_CPU == PP5020 | ||
231 | IISCONFIG |= 0x2; | ||
232 | #elif CONFIG_CPU == PP5002 | ||
233 | IISFIFO_CFG |= (1<<9); | ||
234 | #endif | ||
235 | return; | ||
236 | } | ||
237 | |||
238 | IISFIFO_WR = (*(p++))<<16; | ||
239 | IISFIFO_WR = (*(p++))<<16; | ||
240 | p_size-=4; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | void pcm_set_frequency(unsigned int frequency) | ||
245 | { | ||
246 | (void)frequency; | ||
247 | pcm_freq = HW_SAMPR_DEFAULT; | ||
248 | } | ||
249 | |||
250 | size_t pcm_get_bytes_waiting(void) | ||
251 | { | ||
252 | return p_size; | ||
253 | } | ||
254 | |||
255 | /* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode | ||
256 | has registers r8-r14 banked, and so does not need to be saved. This routine | ||
257 | uses only these registers, and so will never touch the stack unless it | ||
258 | actually needs to do so when calling pcm_callback_for_more. C version is | ||
259 | still included below for reference. | ||
260 | */ | ||
261 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 | ||
262 | void fiq(void) ICODE_ATTR __attribute__((naked)); | ||
263 | void fiq(void) | ||
264 | { | ||
265 | /* r12 contains IISCONFIG address (set in crt0.S to minimise code in actual | ||
266 | * FIQ handler. r11 contains address of p (also set in crt0.S). Most other | ||
267 | * addresses we need are generated by using offsets with these two. | ||
268 | * r12 + 0x40 is IISFIFO_WR, and r12 + 0x0c is IISFIFO_CFG. | ||
269 | * r8 and r9 contains local copies of p_size and p respectively. | ||
270 | * r10 is a working register. | ||
271 | */ | ||
272 | asm volatile ( | ||
273 | #if CONFIG_CPU == PP5002 | ||
274 | "ldr r10, =0xcf001040 \n\t" /* Some magic from iPodLinux */ | ||
275 | "ldr r10, [r10] \n\t" | ||
276 | "ldr r10, [r12, #0x1c]\n\t" | ||
277 | "bic r10, r10, #0x200 \n\t" /* clear interrupt */ | ||
278 | "str r10, [r12, #0x1c]\n\t" | ||
279 | #else | ||
280 | "ldr r10, [r12] \n\t" | ||
281 | "bic r10, r10, #0x2 \n\t" /* clear interrupt */ | ||
282 | "str r10, [r12] \n\t" | ||
283 | #endif | ||
284 | "ldr r8, [r11, #4] \n\t" /* r8 = p_size */ | ||
285 | "ldr r9, [r11] \n\t" /* r9 = p */ | ||
286 | ".loop: \n\t" | ||
287 | "cmp r8, #0 \n\t" /* is p_size 0? */ | ||
288 | "beq .more_data \n\t" /* if so, ask pcmbuf for more data */ | ||
289 | ".fifo_loop: \n\t" | ||
290 | #if CONFIG_CPU == PP5002 | ||
291 | "ldr r10, [r12, #0x1c]\n\t" /* read IISFIFO_CFG to check FIFO status */ | ||
292 | "and r10, r10, #0x7800000\n\t" | ||
293 | "cmp r10, #0x800000 \n\t" | ||
294 | #else | ||
295 | "ldr r10, [r12, #0x0c]\n\t" /* read IISFIFO_CFG to check FIFO status */ | ||
296 | "and r10, r10, #0x3f0000\n\t" | ||
297 | "cmp r10, #0x10000 \n\t" | ||
298 | #endif | ||
299 | "bls .fifo_full \n\t" /* FIFO full, exit */ | ||
300 | "ldr r10, [r9], #4 \n\t" /* load two samples */ | ||
301 | "mov r10, r10, ror #16\n\t" /* put left sample at the top bits */ | ||
302 | "str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */ | ||
303 | "mov r10, r10, lsl #16\n\t" /* shift lower sample up */ | ||
304 | "str r10, [r12, #0x40]\n\t" /* then write it */ | ||
305 | "subs r8, r8, #4 \n\t" /* check if we have more samples */ | ||
306 | "bne .fifo_loop \n\t" /* yes, continue */ | ||
307 | ".more_data: \n\t" | ||
308 | "stmdb sp!, { r0-r3, r12, lr}\n\t" /* stack scratch regs and lr */ | ||
309 | "mov r0, r11 \n\t" /* r0 = &p */ | ||
310 | "add r1, r11, #4 \n\t" /* r1 = &p_size */ | ||
311 | "str r9, [r0] \n\t" /* save internal copies of variables back */ | ||
312 | "str r8, [r1] \n\t" | ||
313 | "ldr r2, =pcm_callback_for_more\n\t" | ||
314 | "ldr r2, [r2] \n\t" /* get callback address */ | ||
315 | "cmp r2, #0 \n\t" /* check for null pointer */ | ||
316 | "movne lr, pc \n\t" /* call pcm_callback_for_more */ | ||
317 | "bxne r2 \n\t" | ||
318 | "ldmia sp!, { r0-r3, r12, lr}\n\t" | ||
319 | "ldr r8, [r11, #4] \n\t" /* reload p_size and p */ | ||
320 | "ldr r9, [r11] \n\t" | ||
321 | "cmp r8, #0 \n\t" /* did we actually get more data? */ | ||
322 | "bne .loop \n\t" /* yes, continue to try feeding FIFO */ | ||
323 | ".dma_stop: \n\t" /* no more data, do dma_stop() and exit */ | ||
324 | "ldr r10, =pcm_playing\n\t" | ||
325 | "strb r8, [r10] \n\t" /* pcm_playing = false (r8=0, look above) */ | ||
326 | "ldr r10, [r12] \n\t" | ||
327 | #if CONFIG_CPU == PP5002 | ||
328 | "bic r10, r10, #0x4\n\t" /* disable playback FIFO */ | ||
329 | "str r10, [r12] \n\t" | ||
330 | "ldr r10, [r12, #0x1c] \n\t" | ||
331 | "bic r10, r10, #0x200 \n\t" /* clear interrupt */ | ||
332 | "str r10, [r12, #0x1c] \n\t" | ||
333 | #else | ||
334 | "bic r10, r10, #0x20000002\n\t" /* disable playback FIFO and IRQ */ | ||
335 | "str r10, [r12] \n\t" | ||
336 | #endif | ||
337 | "mrs r10, cpsr \n\t" | ||
338 | "orr r10, r10, #0x40 \n\t" /* disable FIQ */ | ||
339 | "msr cpsr_c, r10 \n\t" | ||
340 | ".exit: \n\t" | ||
341 | "str r8, [r11, #4] \n\t" | ||
342 | "str r9, [r11] \n\t" | ||
343 | "subs pc, lr, #4 \n\t" /* FIQ specific return sequence */ | ||
344 | ".fifo_full: \n\t" /* enable IRQ and exit */ | ||
345 | #if CONFIG_CPU == PP5002 | ||
346 | "ldr r10, [r12, #0x1c]\n\t" | ||
347 | "orr r10, r10, #0x200 \n\t" /* set interrupt */ | ||
348 | "str r10, [r12, #0x1c]\n\t" | ||
349 | #else | ||
350 | "ldr r10, [r12] \n\t" | ||
351 | "orr r10, r10, #0x2 \n\t" /* set interrupt */ | ||
352 | "str r10, [r12] \n\t" | ||
353 | #endif | ||
354 | "b .exit \n\t" | ||
355 | ); | ||
356 | } | ||
357 | #else /* !(CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002) */ | ||
358 | void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); | ||
359 | void fiq(void) | ||
360 | { | ||
361 | /* Clear interrupt */ | ||
362 | #if CONFIG_CPU == PP5020 | ||
363 | IISCONFIG &= ~0x2; | ||
364 | #elif CONFIG_CPU == PP5002 | ||
365 | inl(0xcf001040); | ||
366 | IISFIFO_CFG &= ~(1<<9); | ||
367 | #endif | ||
368 | |||
369 | do { | ||
370 | while (p_size) { | ||
371 | if (FIFO_FREE_COUNT < 2) { | ||
372 | /* Enable interrupt */ | ||
373 | #if CONFIG_CPU == PP5020 | ||
374 | IISCONFIG |= 0x2; | ||
375 | #elif CONFIG_CPU == PP5002 | ||
376 | IISFIFO_CFG |= (1<<9); | ||
377 | #endif | ||
378 | return; | ||
379 | } | ||
380 | |||
381 | IISFIFO_WR = (*(p++))<<16; | ||
382 | IISFIFO_WR = (*(p++))<<16; | ||
383 | p_size-=4; | ||
384 | } | ||
385 | |||
386 | /* p is empty, get some more data */ | ||
387 | if (pcm_callback_for_more) { | ||
388 | pcm_callback_for_more((unsigned char**)&p,&p_size); | ||
389 | } | ||
390 | } while (p_size); | ||
391 | |||
392 | /* No more data, so disable the FIFO/FIQ */ | ||
393 | pcm_play_dma_stop(); | ||
394 | } | ||
395 | #endif /* CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 */ | ||
396 | |||
397 | #ifdef HAVE_PP5024_CODEC | ||
398 | void pcm_init(void) | ||
399 | { | ||
400 | } | ||
401 | #else | ||
402 | void pcm_init(void) | ||
403 | { | ||
404 | pcm_playing = false; | ||
405 | pcm_paused = false; | ||
406 | pcm_callback_for_more = NULL; | ||
407 | |||
408 | /* Initialize default register values. */ | ||
409 | audiohw_init(); | ||
410 | |||
411 | /* Power on */ | ||
412 | audiohw_enable_output(true); | ||
413 | |||
414 | /* Unmute the master channel (DAC should be at zero point now). */ | ||
415 | audiohw_mute(false); | ||
416 | |||
417 | /* Call pcm_play_dma_stop to initialize everything. */ | ||
418 | pcm_play_dma_stop(); | ||
419 | } | ||
420 | #endif /* HAVE_PP5024_CODEC */ | ||
421 | #elif (CONFIG_CPU == PNX0101) | 101 | #elif (CONFIG_CPU == PNX0101) |
422 | 102 | ||
423 | #define DMA_BUF_SAMPLES 0x100 | 103 | #define DMA_BUF_SAMPLES 0x100 |
@@ -608,7 +288,7 @@ void pcm_mute(bool mute) | |||
608 | if (mute) | 288 | if (mute) |
609 | sleep(HZ/16); | 289 | sleep(HZ/16); |
610 | } | 290 | } |
611 | 291 | #if !defined(CPU_PP) | |
612 | /* | 292 | /* |
613 | * This function goes directly into the DMA buffer to calculate the left and | 293 | * This function goes directly into the DMA buffer to calculate the left and |
614 | * right peak values. To avoid missing peaks it tries to look forward two full | 294 | * right peak values. To avoid missing peaks it tries to look forward two full |
@@ -632,9 +312,7 @@ void pcm_calculate_peaks(int *left, int *right) | |||
632 | short *addr; | 312 | short *addr; |
633 | short *end; | 313 | short *end; |
634 | { | 314 | { |
635 | #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | 315 | #if CONFIG_CPU == PNX0101 |
636 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) \ | ||
637 | || (CONFIG_CPU == PNX0101) || defined(HAVE_PP5024_CODEC) | ||
638 | size_t samples = p_size / 4; | 316 | size_t samples = p_size / 4; |
639 | addr = p; | 317 | addr = p; |
640 | #endif | 318 | #endif |
@@ -690,7 +368,7 @@ void pcm_calculate_peaks(int *left, int *right) | |||
690 | } | 368 | } |
691 | #endif | 369 | #endif |
692 | } | 370 | } |
693 | 371 | #endif | |
694 | #endif /* CPU_COLDFIRE */ | 372 | #endif /* CPU_COLDFIRE */ |
695 | 373 | ||
696 | /**************************************************************************** | 374 | /**************************************************************************** |