summaryrefslogtreecommitdiff
path: root/firmware/pcm_playback.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/pcm_playback.c')
-rw-r--r--firmware/pcm_playback.c87
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
499unsigned int fiq_count IBSS_ATTR; 497unsigned int fiq_count IBSS_ATTR;
500 498
501void 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
506void fiq(void) ICODE_ATTR __attribute__((naked));
507void 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
580void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
502void fiq(void) 581void 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
531void pcm_init(void) 610void pcm_init(void)
532{ 611{