diff options
Diffstat (limited to 'firmware/pcm_playback.c')
-rw-r--r-- | firmware/pcm_playback.c | 87 |
1 files changed, 83 insertions, 4 deletions
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 1e9cac31f5..634d280a74 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include "debug.h" | 21 | #include "debug.h" |
22 | #include "panic.h" | 22 | #include "panic.h" |
23 | #include <kernel.h> | 23 | #include <kernel.h> |
24 | #ifndef SIMULATOR | ||
25 | #include "cpu.h" | 24 | #include "cpu.h" |
26 | #include "i2c.h" | 25 | #include "i2c.h" |
27 | #if defined(HAVE_UDA1380) | 26 | #if defined(HAVE_UDA1380) |
@@ -36,7 +35,6 @@ | |||
36 | #include "wm8731l.h" | 35 | #include "wm8731l.h" |
37 | #endif | 36 | #endif |
38 | #include "system.h" | 37 | #include "system.h" |
39 | #endif | ||
40 | #include "logf.h" | 38 | #include "logf.h" |
41 | 39 | ||
42 | #include <stdio.h> | 40 | #include <stdio.h> |
@@ -498,13 +496,93 @@ bool pcm_is_playing(void) | |||
498 | 496 | ||
499 | unsigned int fiq_count IBSS_ATTR; | 497 | unsigned int fiq_count IBSS_ATTR; |
500 | 498 | ||
501 | void fiq(void) ICODE_ATTR; | 499 | /* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode |
500 | has registers r8-r14 banked, and so does not need to be saved. This routine | ||
501 | uses only these registers, and so will never touch the stack unless it | ||
502 | actually needs to do so when calling callback_for_more. C version is still | ||
503 | included below for reference. | ||
504 | */ | ||
505 | #if 1 | ||
506 | void fiq(void) ICODE_ATTR __attribute__((naked)); | ||
507 | void fiq(void) | ||
508 | { | ||
509 | asm volatile ( | ||
510 | "ldr r12, =0x70002800 \n\t" /* r12 = IISCONFIG */ | ||
511 | "ldr r11, [r12] \n\t" | ||
512 | "bic r11, r11, #0x2 \n\t" /* clear interrupt */ | ||
513 | "str r11, [r12] \n\t" | ||
514 | "ldr r8, =p_size \n\t" | ||
515 | "ldr r9, =p \n\t" | ||
516 | "ldr r8, [r8] \n\t" /* r8 = p_size */ | ||
517 | "ldr r9, [r9] \n\t" /* r9 = p */ | ||
518 | "ldr r10, =0x70002840 \n\t" /* r10 = IISFIFO_WR */ | ||
519 | "ldr r11, =0x7000280c \n\t" /* r11 = IISFIFO_CFG */ | ||
520 | ".loop: \n\t" | ||
521 | "cmp r8, #0 \n\t" /* is p_size 0? */ | ||
522 | "beq .more_data \n\t" /* if so, ask pcmbuf for more data */ | ||
523 | ".fifo_loop: \n\t" | ||
524 | "ldr r12, [r11] \n\t" /* read IISFIFO_CFG to check FIFO status */ | ||
525 | "and r12, r12, #0x3f0000\n\t" | ||
526 | "cmp r12, #0x10000 \n\t" | ||
527 | "bls .fifo_full \n\t" /* FIFO full, exit */ | ||
528 | "ldr r12, [r9], #4 \n\t" /* load two samples to r12 */ | ||
529 | "str r12, [r10] \n\t" /* write top sample, lower sample ignored */ | ||
530 | "mov r12, r12, lsl #16\n\t" /* shift lower sample up */ | ||
531 | "str r12, [r10] \n\t" /* then write it */ | ||
532 | "subs r8, r8, #4 \n\t" /* check if we have more samples */ | ||
533 | "bne .loop \n\t" /* yes, continue */ | ||
534 | ".more_data: \n\t" | ||
535 | "stmdb sp!, { r0-r3, lr}\n\t" /* stack scratch regs and lr */ | ||
536 | "ldr r0, =p \n\t" /* load parameters to callback_for_more */ | ||
537 | "ldr r1, =p_size \n\t" | ||
538 | "str r9, [r0] \n\t" /* save internal copies of variables back */ | ||
539 | "str r8, [r1] \n\t" | ||
540 | "ldr r2, =callback_for_more\n\t" | ||
541 | "ldr r2, [r2] \n\t" /* get callback address */ | ||
542 | "cmp r2, #0 \n\t" /* check for null pointer */ | ||
543 | "movne lr, pc \n\t" /* call callback_for_more */ | ||
544 | "bxne r2 \n\t" | ||
545 | "ldmia sp!, { r0-r3, lr}\n\t" | ||
546 | "ldr r8, =p_size \n\t" /* reload p_size and p */ | ||
547 | "ldr r9, =p \n\t" | ||
548 | "ldr r8, [r8] \n\t" | ||
549 | "ldr r9, [r9] \n\t" | ||
550 | "cmp r8, #0 \n\t" /* did we actually get more data? */ | ||
551 | "bne .loop \n\t" /* yes, continue to try feeding FIFO */ | ||
552 | ".dma_stop: \n\t" /* no more data, do dma_stop() and exit */ | ||
553 | "ldr r10, =pcm_playing\n\t" | ||
554 | "mov r12, #0 \n\t" | ||
555 | "strb r12, [r10] \n\t" /* pcm_playing = false */ | ||
556 | "ldr r10, =0x70002800 \n\t" /* r10 = IISCONFIG */ | ||
557 | "ldr r11, [r10] \n\t" | ||
558 | "bic r11, r11, #0x20000002\n\t" /* disable playback FIFO and IRQ */ | ||
559 | "str r11, [r10] \n\t" | ||
560 | "mrs r10, cpsr \n\t" | ||
561 | "orr r10, r10, #0x40 \n\t" /* disable FIQ */ | ||
562 | "msr cpsr_c, r10 \n\t" | ||
563 | "ldr r10, =pcm_paused \n\t" | ||
564 | "strb r12, [r10] \n\t" /* pcm_paused = false */ | ||
565 | ".exit: \n\t" | ||
566 | "ldr r10, =p_size \n\t" /* save back p_size and p, then exit */ | ||
567 | "ldr r11, =p \n\t" | ||
568 | "str r8, [r10] \n\t" | ||
569 | "str r9, [r11] \n\t" | ||
570 | "subs pc, lr, #4 \n\t" /* FIQ specific return sequence */ | ||
571 | ".fifo_full: \n\t" /* enable IRQ and exit */ | ||
572 | "ldr r12, =0x70002800 \n\t" /* r12 = IISCONFIG */ | ||
573 | "ldr r11, [r12] \n\t" | ||
574 | "orr r11, r11, #0x2 \n\t" /* set interrupt */ | ||
575 | "str r11, [r12] \n\t" | ||
576 | "b .exit \n\t" | ||
577 | ); | ||
578 | } | ||
579 | #else | ||
580 | void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); | ||
502 | void fiq(void) | 581 | void fiq(void) |
503 | { | 582 | { |
504 | /* Clear interrupt */ | 583 | /* Clear interrupt */ |
505 | IISCONFIG &= ~0x2; | 584 | IISCONFIG &= ~0x2; |
506 | 585 | ||
507 | fiq_count++; | ||
508 | do { | 586 | do { |
509 | while (p_size) { | 587 | while (p_size) { |
510 | if (FIFO_FREE_COUNT < 2) { | 588 | if (FIFO_FREE_COUNT < 2) { |
@@ -527,6 +605,7 @@ void fiq(void) | |||
527 | /* No more data, so disable the FIFO/FIQ */ | 605 | /* No more data, so disable the FIFO/FIQ */ |
528 | dma_stop(); | 606 | dma_stop(); |
529 | } | 607 | } |
608 | #endif | ||
530 | 609 | ||
531 | void pcm_init(void) | 610 | void pcm_init(void) |
532 | { | 611 | { |