summaryrefslogtreecommitdiff
path: root/firmware/target/arm/pp/pcm-pp.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/pp/pcm-pp.c')
-rw-r--r--firmware/target/arm/pp/pcm-pp.c734
1 files changed, 734 insertions, 0 deletions
diff --git a/firmware/target/arm/pp/pcm-pp.c b/firmware/target/arm/pp/pcm-pp.c
new file mode 100644
index 0000000000..3854206ae8
--- /dev/null
+++ b/firmware/target/arm/pp/pcm-pp.c
@@ -0,0 +1,734 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdlib.h>
22#include "system.h"
23#include "kernel.h"
24#include "logf.h"
25#include "audio.h"
26#include "sound.h"
27#include "pcm.h"
28#include "pcm_sampr.h"
29#include "pcm-internal.h"
30
31/** DMA **/
32
33#ifdef CPU_PP502x
34/* 16-bit, L-R packed into 32 bits with left in the least significant halfword */
35#define SAMPLE_SIZE 16
36/* DMA Requests from IIS, Memory to peripheral, single transfer,
37 wait for DMA request, interrupt on complete */
38#define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \
39 DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \
40 DMA_CMD_WAIT_REQ | DMA_CMD_INTR)
41/* DMA status cannot be viewed from outside code in control because that can
42 * clear the interrupt from outside the handler and prevent the handler from
43 * from being called. Split up transfers to a reasonable size that is good as
44 * a timer, obtaining a keyclick position and peaking yet still keeps the
45 * FIQ count low.
46 */
47#define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */
48#else
49/* 32-bit, one left 32-bit sample followed by one right 32-bit sample */
50#define SAMPLE_SIZE 32
51#endif
52
53struct dma_data
54{
55/* NOTE: The order of size and p is important if you use assembler
56 optimised fiq handler, so don't change it. */
57 union
58 {
59 unsigned long addr;
60 uint32_t *p16; /* For packed 16-16 stereo pairs */
61 uint16_t *p32; /* For individual samples converted to 32-bit */
62 };
63 size_t size;
64#if NUM_CORES > 1
65 unsigned core;
66#endif
67 int locked;
68 int state;
69};
70
71extern void *fiq_function;
72
73/* Dispatch to the proper handler and leave the main vector table alone */
74void fiq_handler(void) ICODE_ATTR __attribute__((naked));
75void fiq_handler(void)
76{
77 asm volatile (
78 "ldr pc, [pc, #-4] \n"
79 "fiq_function: \n"
80 ".word 0 \n"
81 );
82}
83
84#ifdef HAVE_PCM_DMA_ADDRESS
85void * pcm_dma_addr(void *addr)
86{
87 if (addr != NULL && (unsigned long)addr < UNCACHED_BASE_ADDR)
88 addr = UNCACHED_ADDR(addr);
89 return addr;
90}
91#endif
92
93/* TODO: Get simultaneous recording and playback to work. Just needs some tweaking */
94
95/****************************************************************************
96 ** Playback DMA transfer
97 **/
98static struct dma_data dma_play_data IBSS_ATTR =
99{
100 /* Initialize to a locked, stopped state */
101 { .addr = 0 },
102 .size = 0,
103#if NUM_CORES > 1
104 .core = 0x00,
105#endif
106 .locked = 0,
107 .state = 0
108};
109
110void pcm_dma_apply_settings(void)
111{
112 audiohw_set_frequency(pcm_fsel);
113}
114
115#if defined(CPU_PP502x)
116/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
117void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
118{
119 bool new_buffer = false;
120 register size_t size;
121
122 DMA0_STATUS; /* Clear any pending interrupt */
123
124 size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused this
125 interrupt */
126 dma_play_data.addr += size;
127 dma_play_data.size -= size;
128
129 while (1)
130 {
131 if (dma_play_data.size > 0) {
132 size = MAX_DMA_CHUNK_SIZE;
133 /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less
134 * than a FIFO's worth of data after this transfer? */
135 if (size + 16*4 > dma_play_data.size)
136 size = dma_play_data.size;
137
138 /* Set the new DMA values and activate channel */
139 DMA0_RAM_ADDR = dma_play_data.addr;
140 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
141
142 if (new_buffer)
143 pcm_play_dma_started_callback();
144 return;
145 }
146
147 new_buffer = true;
148
149 /* Buffer empty. Try to get more. */
150 pcm_play_get_more_callback((void **)&dma_play_data.addr,
151 &dma_play_data.size);
152
153 if (dma_play_data.size == 0) {
154 /* No more data */
155 return;
156 }
157
158 if (dma_play_data.addr < UNCACHED_BASE_ADDR) {
159 /* Flush any pending cache writes */
160 dma_play_data.addr = UNCACHED_ADDR(dma_play_data.addr);
161 commit_discard_idcache();
162 }
163 }
164}
165#else
166/* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by
167 * evalutation of free IISFIFO-slots against available source buffer words.
168 * Through this it is possible to move the check for IIS_TX_FREE_COUNT outside
169 * the loop and do some further optimization. Right after the loops (source
170 * buffer -> IISFIFO) are done we need to check whether we have to exit FIQ
171 * handler (this must be done, if all free FIFO slots were filled) or we will
172 * have to get some new source data. Important information kept from former
173 * ASM implementation (not used anymore): GCC fails to make use of the fact
174 * that FIQ mode has registers r8-r14 banked, and so does not need to be saved.
175 * This routine uses only these registers, and so will never touch the stack
176 * unless it actually needs to do so when calling pcm_callback_for_more.
177 * C version is still included below for reference and testing.
178 */
179#if 1
180void fiq_playback(void) ICODE_ATTR __attribute__((naked));
181void fiq_playback(void)
182{
183 /* r10 contains IISCONFIG address (set in crt0.S to minimise code in actual
184 * FIQ handler. r11 contains address of p (also set in crt0.S). Most other
185 * addresses we need are generated by using offsets with these two.
186 * r10 + 0x40 is IISFIFO_WR, and r10 + 0x0c is IISFIFO_CFG.
187 * r8 and r9 contains local copies of p and size respectively.
188 * r0-r3 and r12 is a working register.
189 */
190 asm volatile (
191 "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */
192
193 "mov r4, #0 \n" /* Was the callback called? */
194#if CONFIG_CPU == PP5002
195 "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */
196 "ldr r12, [r12] \n"
197#endif
198 "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */
199 "cmp r9, #0 \n" /* is size 0? */
200 "beq .more_data \n" /* if so, ask pcmbuf for more data */
201
202#if SAMPLE_SIZE == 16
203 ".check_fifo: \n"
204 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
205 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 16 (PP502x) */
206
207 "mov r1, r0, lsr #16 \n" /* number of free FIFO slots */
208 "cmp r1, r9, lsr #2 \n" /* number of words from source */
209 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
210 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
211
212 "subs r1, r1, #2 \n"
213 ".fifo_loop_2: \n"
214 "ldmgeia r8!, {r2, r12} \n" /* load four samples */
215 "strge r2 , [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
216 "strge r12, [r10, %[wr]] \n" /* write sample 2-3 to IISFIFO_WR */
217 "subges r1, r1, #2 \n" /* one more loop? */
218 "bge .fifo_loop_2 \n" /* yes, continue */
219
220 "tst r1, #1 \n" /* two samples (one word) left? */
221 "ldrne r12, [r8], #4 \n" /* load two samples */
222 "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
223#elif SAMPLE_SIZE == 32
224 ".check_fifo: \n"
225 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
226 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */
227
228 "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */
229 "beq .fifo_fill_complete \n" /* no complete pair? -> exit */
230 "cmp r1, r9, lsr #2 \n" /* number of words from source */
231 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
232 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
233
234 ".fifo_loop: \n"
235 "ldr r12, [r8], #4 \n" /* load two samples */
236 "mov r2 , r12, lsl #16 \n" /* put left sample at the top bits */
237 "str r2 , [r10, %[wr]] \n" /* write top sample to IISFIFO_WR */
238 "str r12, [r10, %[wr]] \n" /* write low sample to IISFIFO_WR*/
239 "subs r1, r1, #1 \n" /* one more loop? */
240 "bgt .fifo_loop \n" /* yes, continue */
241
242 ".fifo_fill_complete: \n"
243#endif
244 "cmp r4, #0 \n" /* If fill came after get_more... */
245 "beq .still_old_buffer \n"
246 "mov r4, #0 \n"
247 "ldr r2, =pcm_play_dma_started \n"
248 "ldrne r2, [r2] \n"
249 "cmp r2, #0 \n"
250 "movne lr, pc \n"
251 "bxne r2 \n"
252
253 ".still_old_buffer: \n"
254 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
255 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
256
257 ".more_data: \n"
258 "mov r4, #1 \n" /* Remember we did this */
259 "ldr r2, =pcm_play_get_more_callback \n"
260 "mov r0, r11 \n" /* r0 = &p */
261 "add r1, r11, #4 \n" /* r1 = &size */
262 "mov lr, pc \n" /* call pcm_play_get_more_callback */
263 "bx r2 \n"
264 "ldmia r11, { r8-r9 } \n" /* load new p and size */
265 "cmp r9, #0 \n"
266 "bne .check_fifo \n" /* size != 0? refill */
267
268 ".exit: \n" /* (r9=0 if stopping, look above) */
269 "stmia r11, { r8-r9 } \n" /* save p and size */
270 "ldmfd sp!, { r0-r4, lr } \n"
271 "subs pc, lr, #4 \n" /* FIQ specific return sequence */
272 ".ltorg \n"
273 : /* These must only be integers! No regs */
274 : [mask]"i"(IIS_TX_FREE_MASK),
275 [cfg]"i"((int)&IISFIFO_CFG - (int)&IISCONFIG),
276 [wr]"i"((int)&IISFIFO_WR - (int)&IISCONFIG)
277 );
278}
279#else /* C version for reference */
280void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR;
281/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
282void fiq_playback(void)
283{
284 bool new_buffer = false;
285
286#if CONFIG_CPU == PP5002
287 inl(0xcf001040);
288#endif
289
290 do {
291 while (dma_play_data.size > 0) {
292 if (IIS_TX_FREE_COUNT < 2) {
293 if (new_buffer) {
294 new_buffer = false;
295 pcm_play_dma_started_callback();
296 }
297 return;
298 }
299#if SAMPLE_SIZE == 16
300 IISFIFO_WR = *dma_play_data.p16++;
301#elif SAMPLE_SIZE == 32
302 IISFIFO_WR = *dma_play_data.p32++ << 16;
303 IISFIFO_WR = *dma_play_data.p32++ << 16;
304#endif
305 dma_play_data.size -= 4;
306 }
307
308 if (new_buffer) {
309 new_buffer = false;
310 pcm_play_dma_started_callback();
311 }
312
313 /* p is empty, get some more data */
314 pcm_play_get_more_callback((void **)&dma_play_data.addr,
315 &dma_play_data.size);
316 new_buffer = true;
317 } while (dma_play_data.size);
318
319 /* No more data */
320}
321#endif /* ASM / C selection */
322#endif /* CPU_PP502x */
323
324/* For the locks, FIQ must be disabled because the handler manipulates
325 IISCONFIG and the operation is not atomic - dual core support
326 will require other measures */
327void pcm_play_lock(void)
328{
329 int status = disable_fiq_save();
330
331 if (++dma_play_data.locked == 1) {
332#ifdef CPU_PP502x
333 CPU_INT_DIS = DMA_MASK;
334#else
335 IIS_IRQTX_REG &= ~IIS_IRQTX;
336#endif
337 }
338
339 restore_fiq(status);
340}
341
342void pcm_play_unlock(void)
343{
344 int status = disable_fiq_save();
345
346 if (--dma_play_data.locked == 0 && dma_play_data.state != 0) {
347#ifdef CPU_PP502x
348 CPU_INT_EN = DMA_MASK;
349#else
350 IIS_IRQTX_REG |= IIS_IRQTX;
351#endif
352 }
353
354 restore_fiq(status);
355}
356
357static void play_start_pcm(void)
358{
359 fiq_function = fiq_playback;
360
361#ifdef CPU_PP502x
362 /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less than a
363 * FIFO's worth of data after this transfer? */
364 size_t size = MAX_DMA_CHUNK_SIZE;
365 if (size + 16*4 > dma_play_data.size)
366 size = dma_play_data.size;
367
368 DMA0_RAM_ADDR = dma_play_data.addr;
369 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
370 dma_play_data.state = 1;
371#else
372 IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */
373
374 /* Fill the FIFO or start when data is used up */
375 while (1) {
376 if (IIS_TX_FREE_COUNT < 2 || dma_play_data.size == 0) {
377 IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */
378 dma_play_data.state = 1;
379 return;
380 }
381
382#if SAMPLE_SIZE == 16
383 IISFIFO_WR = *dma_play_data.p16++;
384#elif SAMPLE_SIZE == 32
385 IISFIFO_WR = *dma_play_data.p32++ << 16;
386 IISFIFO_WR = *dma_play_data.p32++ << 16;
387#endif
388 dma_play_data.size -= 4;
389 }
390#endif
391}
392
393static void play_stop_pcm(void)
394{
395#ifdef CPU_PP502x
396 unsigned long status = DMA0_STATUS; /* Snapshot- resume from this point */
397 unsigned long cmd = DMA0_CMD;
398 size_t size = 0;
399
400 /* Stop transfer */
401 DMA0_CMD = cmd & ~(DMA_CMD_START | DMA_CMD_INTR);
402
403 /* Wait for not busy + clear int */
404 while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR));
405
406 if (status & DMA_STATUS_BUSY) {
407 /* Transfer was interrupted - leave what's left */
408 size = (cmd & 0xfffc) - (status & 0xfffc);
409 }
410 else if (status & DMA_STATUS_INTR) {
411 /* Transfer was finished - DMA0_STATUS will have been reloaded
412 * automatically with size in DMA0_CMD. Setup to restart on next
413 * segment. */
414 size = (cmd & 0xfffc) + 4;
415 }
416 /* else not an active state - size = 0 */
417
418 dma_play_data.addr += size;
419 dma_play_data.size -= size;
420
421 if (dma_play_data.size == 0)
422 dma_play_data.addr = 0; /* Entire buffer has completed. */
423#else
424 /* Disable TX interrupt */
425 IIS_IRQTX_REG &= ~IIS_IRQTX;
426#endif
427
428 /* Wait for FIFO to empty */
429 while (!IIS_TX_IS_EMPTY);
430
431 dma_play_data.state = 0;
432}
433
434void pcm_play_dma_start(const void *addr, size_t size)
435{
436#if NUM_CORES > 1
437 /* This will become more important later - and different ! */
438 dma_play_data.core = processor_id(); /* save initiating core */
439#endif
440
441 pcm_play_dma_stop();
442
443#ifdef CPU_PP502x
444 if ((unsigned long)addr < UNCACHED_BASE_ADDR) {
445 /* Flush any pending cache writes */
446 addr = UNCACHED_ADDR(addr);
447 commit_discard_idcache();
448 }
449
450 dma_play_data.addr = (unsigned long)addr;
451 dma_play_data.size = size;
452 DMA0_PER_ADDR = (unsigned long)&IISFIFO_WR;
453 DMA0_FLAGS = DMA_FLAGS_UNK26;
454 DMA0_INCR = DMA_INCR_RANGE_FIXED | DMA_INCR_WIDTH_32BIT;
455#else
456 dma_play_data.addr = (unsigned long)addr;
457 dma_play_data.size = size;
458#endif
459
460 play_start_pcm();
461}
462
463/* Stops the DMA transfer and interrupt */
464void pcm_play_dma_stop(void)
465{
466 play_stop_pcm();
467 dma_play_data.addr = 0;
468 dma_play_data.size = 0;
469#if NUM_CORES > 1
470 dma_play_data.core = 0; /* no core in control */
471#endif
472}
473
474void pcm_play_dma_pause(bool pause)
475{
476 if (pause) {
477 play_stop_pcm();
478 } else {
479 play_start_pcm();
480 }
481}
482
483size_t pcm_get_bytes_waiting(void)
484{
485 return dma_play_data.size & ~3;
486}
487
488void pcm_play_dma_init(void)
489{
490 /* Initialize default register values. */
491 audiohw_init();
492
493#ifdef CPU_PP502x
494 /* Enable DMA controller */
495 DMA_MASTER_CONTROL |= DMA_MASTER_CONTROL_EN;
496 /* FIQ priority for DMA */
497 CPU_INT_PRIORITY |= DMA_MASK;
498 /* Enable request?? Not setting or clearing everything doesn't seem to
499 * prevent it operating. Perhaps important for reliability (how requests
500 * are handled). */
501 DMA_REQ_STATUS |= 1ul << DMA_REQ_IIS;
502 DMA0_STATUS;
503#else
504 /* Set up banked registers for FIQ mode */
505
506 /* Use non-banked registers for scratch. */
507 register volatile void *iiscfg asm("r0") = &IISCONFIG;
508 register volatile void *dmapd asm("r1") = &dma_play_data;
509
510 asm volatile (
511 "mrs r2, cpsr \n" /* Save mode and interrupt status */
512 "msr cpsr_c, #0xd1 \n" /* Switch to FIQ mode */
513 "mov r8, #0 \n"
514 "mov r9, #0 \n"
515 "mov r10, %[iiscfg] \n"
516 "mov r11, %[dmapd] \n"
517 "msr cpsr_c, r2 \n"
518 :
519 : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd)
520 : "r2");
521
522 /* FIQ priority for I2S */
523 CPU_INT_PRIORITY |= IIS_MASK;
524 CPU_INT_EN = IIS_MASK;
525#endif
526
527 IISCONFIG |= IIS_TXFIFOEN;
528}
529
530void pcm_play_dma_postinit(void)
531{
532 audiohw_postinit();
533}
534
535const void * pcm_play_dma_get_peak_buffer(int *count)
536{
537 unsigned long addr, size;
538
539 int status = disable_fiq_save();
540 addr = dma_play_data.addr;
541 size = dma_play_data.size;
542 restore_fiq(status);
543
544 *count = size >> 2;
545 return (void *)((addr + 2) & ~3);
546}
547
548/****************************************************************************
549 ** Recording DMA transfer
550 **/
551#ifdef HAVE_RECORDING
552/* PCM recording interrupt routine lockout */
553static struct dma_data dma_rec_data IBSS_ATTR =
554{
555 /* Initialize to a locked, stopped state */
556 { .addr = 0 },
557 .size = 0,
558#if NUM_CORES > 1
559 .core = 0x00,
560#endif
561 .locked = 0,
562 .state = 0
563};
564
565/* For the locks, FIQ must be disabled because the handler manipulates
566 IISCONFIG and the operation is not atomic - dual core support
567 will require other measures */
568void pcm_rec_lock(void)
569{
570 int status = disable_fiq_save();
571
572 if (++dma_rec_data.locked == 1)
573 IIS_IRQRX_REG &= ~IIS_IRQRX;
574
575 restore_fiq(status);
576}
577
578void pcm_rec_unlock(void)
579{
580 int status = disable_fiq_save();
581
582 if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0)
583 IIS_IRQRX_REG |= IIS_IRQRX;
584
585 restore_fiq(status);
586}
587
588/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
589void fiq_record(void) ICODE_ATTR __attribute__((interrupt ("FIQ")));
590
591#if defined(SANSA_C200) || defined(SANSA_E200)
592void fiq_record(void)
593{
594 register int32_t value;
595
596 if (audio_channels == 2) {
597 /* RX is stereo */
598 while (dma_rec_data.size > 0) {
599 if (IIS_RX_FULL_COUNT < 2) {
600 return;
601 }
602
603 /* Discard every other sample since ADC clock is 1/2 LRCK */
604 value = IISFIFO_RD;
605 IISFIFO_RD;
606
607 *dma_rec_data.p16++ = value;
608 dma_rec_data.size -= 4;
609
610 /* TODO: Figure out how to do IIS loopback */
611 if (audio_output_source != AUDIO_SRC_PLAYBACK) {
612 if (IIS_TX_FREE_COUNT >= 16) {
613 /* Resync the output FIFO - it ran dry */
614 IISFIFO_WR = 0;
615 IISFIFO_WR = 0;
616 }
617 IISFIFO_WR = value;
618 IISFIFO_WR = value;
619 }
620 }
621 }
622 else {
623 /* RX is left channel mono */
624 while (dma_rec_data.size > 0) {
625 if (IIS_RX_FULL_COUNT < 2) {
626 return;
627 }
628
629 /* Discard every other sample since ADC clock is 1/2 LRCK */
630 value = IISFIFO_RD;
631 IISFIFO_RD;
632
633 value = (uint16_t)value | (value << 16);
634
635 *dma_rec_data.p16++ = value;
636 dma_rec_data.size -= 4;
637
638 if (audio_output_source != AUDIO_SRC_PLAYBACK) {
639 if (IIS_TX_FREE_COUNT >= 16) {
640 /* Resync the output FIFO - it ran dry */
641 IISFIFO_WR = 0;
642 IISFIFO_WR = 0;
643 }
644
645 value = *((int32_t *)dma_rec_data.p16 - 1);
646 IISFIFO_WR = value;
647 IISFIFO_WR = value;
648 }
649 }
650 }
651
652 pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr,
653 &dma_rec_data.size);
654}
655
656#else
657void fiq_record(void)
658{
659 while (dma_rec_data.size > 0) {
660 if (IIS_RX_FULL_COUNT < 2) {
661 return;
662 }
663
664#if SAMPLE_SIZE == 16
665 *dma_rec_data.p16++ = IISFIFO_RD;
666#elif SAMPLE_SIZE == 32
667 *dma_rec_data.p32++ = IISFIFO_RD >> 16;
668 *dma_rec_data.p32++ = IISFIFO_RD >> 16;
669#endif
670 dma_rec_data.size -= 4;
671 }
672
673 pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr,
674 &dma_rec_data.size);
675}
676
677#endif /* SANSA_E200 */
678
679void pcm_rec_dma_stop(void)
680{
681 /* disable interrupt */
682 IIS_IRQRX_REG &= ~IIS_IRQRX;
683
684 dma_rec_data.state = 0;
685 dma_rec_data.size = 0;
686#if NUM_CORES > 1
687 dma_rec_data.core = 0x00;
688#endif
689
690 /* disable fifo */
691 IISCONFIG &= ~IIS_RXFIFOEN;
692 IISFIFO_CFG |= IIS_RXCLR;
693}
694
695void pcm_rec_dma_start(void *addr, size_t size)
696{
697 pcm_rec_dma_stop();
698
699 dma_rec_data.addr = (unsigned long)addr;
700 dma_rec_data.size = size;
701#if NUM_CORES > 1
702 /* This will become more important later - and different ! */
703 dma_rec_data.core = processor_id(); /* save initiating core */
704#endif
705 /* setup FIQ handler */
706 fiq_function = fiq_record;
707
708 /* interrupt on full fifo, enable record fifo interrupt */
709 dma_rec_data.state = 1;
710
711 /* enable RX FIFO */
712 IISCONFIG |= IIS_RXFIFOEN;
713
714 /* enable IIS interrupt as FIQ */
715 CPU_INT_PRIORITY |= IIS_MASK;
716 CPU_INT_EN = IIS_MASK;
717}
718
719void pcm_rec_dma_close(void)
720{
721 pcm_rec_dma_stop();
722} /* pcm_close_recording */
723
724void pcm_rec_dma_init(void)
725{
726 pcm_rec_dma_stop();
727} /* pcm_init */
728
729const void * pcm_rec_dma_get_peak_buffer(void)
730{
731 return (void *)((unsigned long)dma_rec_data.addr & ~3);
732} /* pcm_rec_dma_get_peak_buffer */
733
734#endif /* HAVE_RECORDING */