diff options
Diffstat (limited to 'firmware/target/arm')
-rw-r--r-- | firmware/target/arm/crt0-pp.S | 8 | ||||
-rw-r--r-- | firmware/target/arm/i2s-pp.c | 81 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c | 114 | ||||
-rw-r--r-- | firmware/target/arm/pcm-pp.c | 846 | ||||
-rw-r--r-- | firmware/target/arm/pnx0101/pcm-pnx0101.c | 69 | ||||
-rw-r--r-- | firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c | 374 | ||||
-rw-r--r-- | firmware/target/arm/system-arm.h | 6 | ||||
-rw-r--r-- | firmware/target/arm/system-pp502x.c | 1 | ||||
-rw-r--r-- | firmware/target/arm/system-target.h | 14 |
9 files changed, 673 insertions, 840 deletions
diff --git a/firmware/target/arm/crt0-pp.S b/firmware/target/arm/crt0-pp.S index 858f795aad..8fd1e31f09 100644 --- a/firmware/target/arm/crt0-pp.S +++ b/firmware/target/arm/crt0-pp.S | |||
@@ -243,10 +243,10 @@ cpu_init: | |||
243 | msr cpsr_c, #0xd1 /* IRQ/FIQ disabled */ | 243 | msr cpsr_c, #0xd1 /* IRQ/FIQ disabled */ |
244 | ldr sp, =fiq_stack | 244 | ldr sp, =fiq_stack |
245 | /* We'll load the banked FIQ mode registers with useful values here. | 245 | /* We'll load the banked FIQ mode registers with useful values here. |
246 | These values will be used in the FIQ handler in pcm_playback.c */ | 246 | These values will be used in the FIQ handler in pcm-pp.c */ |
247 | ldr r12, =IIS_CONFIG | 247 | ldr r10, =IIS_CONFIG |
248 | 248 | ||
249 | ldr r11, =p | 249 | ldr r11, =dma_play_data |
250 | 250 | ||
251 | /* Let abort and undefined modes use IRQ stack */ | 251 | /* Let abort and undefined modes use IRQ stack */ |
252 | msr cpsr_c, #0xd7 /* IRQ/FIQ disabled */ | 252 | msr cpsr_c, #0xd7 /* IRQ/FIQ disabled */ |
@@ -328,7 +328,7 @@ vectors: | |||
328 | .word data_abort_handler | 328 | .word data_abort_handler |
329 | .word reserved_handler | 329 | .word reserved_handler |
330 | .word irq_handler | 330 | .word irq_handler |
331 | .word 0 /* fiq handler set in pcm driver */ | 331 | .word fiq_handler |
332 | 332 | ||
333 | .text | 333 | .text |
334 | 334 | ||
diff --git a/firmware/target/arm/i2s-pp.c b/firmware/target/arm/i2s-pp.c index e06ee835a6..24d901a4c1 100644 --- a/firmware/target/arm/i2s-pp.c +++ b/firmware/target/arm/i2s-pp.c | |||
@@ -47,99 +47,40 @@ void i2s_reset(void) | |||
47 | } | 47 | } |
48 | #else /* PP502X */ | 48 | #else /* PP502X */ |
49 | 49 | ||
50 | /* All I2S formats send MSB first */ | ||
51 | |||
52 | /* Data format on the I2S bus */ | ||
53 | #define FORMAT_MASK (0x3 << 10) | ||
54 | #define FORMAT_I2S (0x0 << 10) /* Standard I2S - leading dummy bit */ | ||
55 | #define FORMAT_1 (0x1 << 10) | ||
56 | #define FORMAT_LJUST (0x2 << 10) /* Left justified - no dummy bit */ | ||
57 | #define FORMAT_3 (0x3 << 10) | ||
58 | /* Other formats not yet known */ | ||
59 | |||
60 | /* Data size on I2S bus */ | ||
61 | #define SIZE_MASK (0x3 << 8) | ||
62 | #define SIZE_16BIT (0x0 << 8) | ||
63 | /* Other sizes not yet known */ | ||
64 | |||
65 | /* Data size/format on I2S FIFO */ | ||
66 | #define FIFO_FORMAT_MASK (0x7 << 4) | ||
67 | #define FIFO_FORMAT_0 (0x0 << 4) | ||
68 | /* Big-endian formats - data sent to the FIFO must be big endian. | ||
69 | * I forgot which is which size but did test them. */ | ||
70 | #define FIFO_FORMAT_1 (0x1 << 4) | ||
71 | #define FIFO_FORMAT_2 (0x2 << 4) | ||
72 | /* 32bit-MSB-little endian */ | ||
73 | #define FIFO_FORMAT_LE32 (0x3 << 4) | ||
74 | /* 16bit-MSB-little endian */ | ||
75 | #define FIFO_FORMAT_LE16 (0x4 << 4) | ||
76 | |||
77 | /* FIFO formats 0x5 and above seem equivalent to 0x4 ?? */ | ||
78 | |||
79 | /** | ||
80 | * PP502x | ||
81 | * | ||
82 | * IISCONFIG bits: | ||
83 | * | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | | ||
84 | * | RESET | |TXFIFOEN|RXFIFOEN| | ???? | MS | ???? | | ||
85 | * | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | | ||
86 | * | | | | | | | | | | ||
87 | * | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | | ||
88 | * | | | | | Bus Format[1:0] | Size[1:0] | | ||
89 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | ||
90 | * | | Size Format[2:0] | ???? | ???? | IRQTX | IRQRX | | ||
91 | * | ||
92 | * IISFIFO_CFG bits: | ||
93 | * | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | | ||
94 | * | | Free[6:0] | | ||
95 | * | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | | ||
96 | * | | | | | | | | | | ||
97 | * | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | | ||
98 | * | | | | RXCLR | | | | TXCLR | | ||
99 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | ||
100 | * | | | RX_ATN_LEVEL | | | TX_ATN_LEVEL | | ||
101 | */ | ||
102 | |||
103 | /* Are we I2S Master or slave? */ | ||
104 | #define I2S_MASTER (1<<25) | ||
105 | |||
106 | #define I2S_RESET (0x1 << 31) | ||
107 | |||
108 | /* | 50 | /* |
109 | * Reset the I2S BIT.FORMAT I2S, 16bit, FIFO.FORMAT 32bit | 51 | * Reset the I2S BIT.FORMAT I2S, 16bit, FIFO.FORMAT 32bit |
110 | */ | 52 | */ |
111 | void i2s_reset(void) | 53 | void i2s_reset(void) |
112 | { | 54 | { |
113 | /* I2S soft reset */ | 55 | /* I2S soft reset */ |
114 | IISCONFIG |= I2S_RESET; | 56 | IISCONFIG |= IIS_RESET; |
115 | IISCONFIG &= ~I2S_RESET; | 57 | IISCONFIG &= ~IIS_RESET; |
116 | 58 | ||
117 | /* BIT.FORMAT */ | 59 | /* BIT.FORMAT */ |
118 | IISCONFIG = ((IISCONFIG & ~FORMAT_MASK) | FORMAT_I2S); | 60 | IISCONFIG = ((IISCONFIG & ~IIS_FORMAT_MASK) | IIS_FORMAT_IIS); |
119 | 61 | ||
120 | /* BIT.SIZE */ | 62 | /* BIT.SIZE */ |
121 | IISCONFIG = ((IISCONFIG & ~SIZE_MASK) | SIZE_16BIT); | 63 | IISCONFIG = ((IISCONFIG & ~IIS_SIZE_MASK) | IIS_SIZE_16BIT); |
122 | 64 | ||
123 | /* FIFO.FORMAT */ | 65 | /* FIFO.FORMAT */ |
124 | /* If BIT.SIZE < FIFO.FORMAT low bits will be 0 */ | 66 | /* If BIT.SIZE < FIFO.FORMAT low bits will be 0 */ |
125 | #ifdef HAVE_AS3514 | 67 | #ifdef HAVE_AS3514 |
126 | /* AS3514 can only operate as I2S Slave */ | 68 | /* AS3514 can only operate as I2S Slave */ |
127 | IISCONFIG |= I2S_MASTER; | 69 | IISCONFIG |= IIS_MASTER; |
128 | /* Set I2S to 44.1kHz */ | 70 | /* Set I2S to 44.1kHz */ |
129 | outl((inl(0x70002808) & ~(0x1ff)) | 33, 0x70002808); | 71 | outl((inl(0x70002808) & ~(0x1ff)) | 33, 0x70002808); |
130 | outl(7, 0x60006080); | 72 | outl(7, 0x60006080); |
131 | 73 | IISCONFIG = ((IISCONFIG & ~IIS_FIFO_FORMAT_MASK) | IIS_FIFO_FORMAT_LE16); | |
132 | IISCONFIG = ((IISCONFIG & ~FIFO_FORMAT_MASK) | FIFO_FORMAT_LE16); | ||
133 | #else | 74 | #else |
134 | IISCONFIG = ((IISCONFIG & ~FIFO_FORMAT_MASK) | FIFO_FORMAT_LE32); | 75 | IISCONFIG = ((IISCONFIG & ~IIS_FIFO_FORMAT_MASK) | IIS_FIFO_FORMAT_LE32); |
135 | #endif | 76 | #endif |
136 | 77 | ||
137 | /* RX_ATN_LVL=1 == when 12 slots full */ | 78 | /* RX_ATN_LVL = when 12 slots full */ |
138 | /* TX_ATN_LVL=1 == when 12 slots empty */ | 79 | /* TX_ATN_LVL = when 12 slots empty */ |
139 | IISFIFO_CFG |= 0x33; | 80 | IISFIFO_CFG |= IIS_RX_FULL_LVL_12 | IIS_TX_EMPTY_LVL_12; |
140 | 81 | ||
141 | /* Rx.CLR = 1, TX.CLR = 1 */ | 82 | /* Rx.CLR = 1, TX.CLR = 1 */ |
142 | IISFIFO_CFG |= 0x1100; | 83 | IISFIFO_CFG |= IIS_RXCLR | IIS_TXCLR; |
143 | } | 84 | } |
144 | 85 | ||
145 | #endif /* CONFIG_CPU == */ | 86 | #endif /* CONFIG_CPU == */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c b/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c index 73bd9fef14..c29c4b2930 100644 --- a/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c | |||
@@ -25,69 +25,145 @@ | |||
25 | #include "file.h" | 25 | #include "file.h" |
26 | #include "mmu-imx31.h" | 26 | #include "mmu-imx31.h" |
27 | 27 | ||
28 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ | ||
29 | |||
28 | void fiq_handler(void) __attribute__((naked)); | 30 | void fiq_handler(void) __attribute__((naked)); |
29 | 31 | ||
32 | /* Implement separately on recording and playback - simply disable the | ||
33 | specific DMA interrupt. Disable the FIQ itself only temporarily to sync | ||
34 | with the DMA interrupt and restore its previous state. The pcm routines | ||
35 | will call the lockout first then call into these low-level routines. */ | ||
36 | struct dma_lock | ||
37 | { | ||
38 | int locked; | ||
39 | unsigned long state; | ||
40 | }; | ||
41 | |||
42 | static struct dma_play_lock = | ||
43 | { | ||
44 | .locked = 0, | ||
45 | .state = 0, /* Initialize this as disabled */ | ||
46 | }; | ||
47 | |||
48 | void pcm_play_lock(void) | ||
49 | { | ||
50 | int status = set_fiq_status(FIQ_DISABLED); | ||
51 | if (++dma_play_lock.locked == 1) | ||
52 | ; /* Mask the DMA interrupt */ | ||
53 | set_fiq_status(status); | ||
54 | } | ||
55 | |||
56 | void pcm_play_unlock(void) | ||
57 | { | ||
58 | int status = set_fiq_status(FIQ_DISABLED); | ||
59 | if (--dma_play_lock.locked == 0) | ||
60 | ; /* Unmask the DMA interrupt if enabled */ | ||
61 | set_fiq_status(status); | ||
62 | } | ||
63 | |||
30 | static void _pcm_apply_settings(void) | 64 | static void _pcm_apply_settings(void) |
31 | { | 65 | { |
66 | if (pcm_freq != pcm_curr_sampr) | ||
67 | { | ||
68 | pcm_curr_sampr = pcm_freq; | ||
69 | /* Change hardware sample rate */ | ||
70 | /* */ | ||
71 | } | ||
32 | } | 72 | } |
33 | 73 | ||
34 | void pcm_apply_settings(void) | 74 | void pcm_apply_settings(void) |
35 | { | 75 | { |
76 | /* Lockout FIQ and sync the hardware to the settings */ | ||
77 | int oldstatus = set_fiq_status(FIQ_DISABLED); | ||
78 | _pcm_apply_settings(); | ||
79 | set_fiq_status(oldstatus); | ||
36 | } | 80 | } |
37 | 81 | ||
38 | void pcm_init(void) | 82 | void pcm_play_dma_init(void) |
39 | { | 83 | { |
84 | pcm_set_frequency(SAMPR_44); | ||
85 | |||
86 | #if 0 | ||
87 | /* Do basic init enable output in pcm_postinit if popping is a | ||
88 | problem at boot to enable a lenghy delay and let the boot | ||
89 | process continue */ | ||
90 | audiohw_init(); | ||
91 | #endif | ||
40 | } | 92 | } |
41 | 93 | ||
42 | void pcm_postinit(void) | 94 | void pcm_postinit(void) |
43 | { | 95 | { |
44 | } | 96 | } |
45 | 97 | ||
46 | void pcm_play_dma_start(const void *addr, size_t size) | 98 | /* Connect the DMA and start filling the FIFO */ |
99 | static void play_start_pcm(void) | ||
47 | { | 100 | { |
48 | (void)addr; | 101 | #if 0 |
49 | (void)size; | 102 | /* unmask DMA interrupt when unlocking */ |
103 | dma_play_lock.state = 0; /* Set to allow pcm_play_unlock to unmask interrupt */ | ||
104 | #endif | ||
50 | } | 105 | } |
51 | 106 | ||
52 | static void pcm_play_dma_stop_fiq(void) | 107 | /* Disconnect the DMA and wait for the FIFO to clear */ |
108 | static void play_stop_pcm(void) | ||
53 | { | 109 | { |
110 | #if 0 | ||
111 | /* Keep interrupt masked when unlocking */ | ||
112 | dma_play_lock.state = 0; /* Set to keep pcm_play_unlock from unmasking interrupt */ | ||
113 | #endif | ||
54 | } | 114 | } |
55 | 115 | ||
56 | void fiq_handler(void) | 116 | void pcm_play_dma_start(const void *addr, size_t size) |
57 | { | 117 | { |
118 | (void)addr; | ||
119 | (void)size; | ||
58 | } | 120 | } |
59 | 121 | ||
60 | /* Disconnect the DMA and wait for the FIFO to clear */ | ||
61 | void pcm_play_dma_stop(void) | 122 | void pcm_play_dma_stop(void) |
62 | { | 123 | { |
124 | play_stop_pcm(); | ||
63 | } | 125 | } |
64 | 126 | ||
65 | void pcm_play_pause_pause(void) | 127 | void pcm_play_dma_pause(bool pause) |
66 | { | 128 | { |
129 | if (pause) | ||
130 | { | ||
131 | play_stop_pcm(); | ||
132 | } | ||
133 | else | ||
134 | { | ||
135 | play_start_pcm(); | ||
136 | } | ||
67 | } | 137 | } |
68 | 138 | ||
69 | void pcm_play_pause_unpause(void) | 139 | /* Get more samples to play out - call pcm_play_dma_stop and |
140 | pcm_play_dma_stopped_callback if the data runs out */ | ||
141 | void fiq_handler(void) | ||
70 | { | 142 | { |
143 | #if 0 | ||
144 | /* Callback missing or no more DMA to do */ | ||
145 | pcm_play_dma_stop(); | ||
146 | pcm_play_dma_stopped_callback(); | ||
147 | #endif | ||
71 | } | 148 | } |
72 | 149 | ||
150 | /* Set the pcm frequency hardware will use when play is next started or | ||
151 | when pcm_apply_settings is called. Do not apply the setting to the | ||
152 | hardware here but simply cache it. */ | ||
73 | void pcm_set_frequency(unsigned int frequency) | 153 | void pcm_set_frequency(unsigned int frequency) |
74 | { | 154 | { |
75 | (void)frequency; | 155 | pcm_freq = frequency; |
76 | } | 156 | } |
77 | 157 | ||
158 | /* Return the number of bytes waiting - full L-R sample pairs only */ | ||
78 | size_t pcm_get_bytes_waiting(void) | 159 | size_t pcm_get_bytes_waiting(void) |
79 | { | 160 | { |
80 | } | 161 | } |
81 | 162 | ||
82 | void pcm_mute(bool mute) | 163 | /* Return a pointer to the samples and the number of them in *count */ |
164 | const void * pcm_play_dma_get_peak_buffer(int *count) | ||
83 | { | 165 | { |
166 | (void)count; | ||
84 | } | 167 | } |
85 | 168 | ||
86 | /** | 169 | /* Any recording functionality should be implemented similarly */ |
87 | * Return playback peaks - Peaks ahead in the DMA buffer based upon the | ||
88 | * calling period to attempt to compensate for | ||
89 | * delay. | ||
90 | */ | ||
91 | void pcm_calculate_peaks(int *left, int *right) | ||
92 | { | ||
93 | } | ||
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c index f38757ec6c..50e5b272aa 100644 --- a/firmware/target/arm/pcm-pp.c +++ b/firmware/target/arm/pcm-pp.c | |||
@@ -23,329 +23,286 @@ | |||
23 | #include "audio.h" | 23 | #include "audio.h" |
24 | #include "sound.h" | 24 | #include "sound.h" |
25 | 25 | ||
26 | /* peaks */ | 26 | /** DMA **/ |
27 | #ifdef HAVE_RECORDING | 27 | |
28 | static unsigned long *rec_peak_addr; | 28 | #if defined(HAVE_AS3514) |
29 | static int rec_peak_left, rec_peak_right; | 29 | /* E200 uses 16bit FIFO - all others should be able to as well - |
30 | i2s-pp.c has to set the right size as well */ | ||
31 | #define SAMPLE_SIZE 16 | ||
32 | #else | ||
33 | #define SAMPLE_SIZE 32 | ||
30 | #endif | 34 | #endif |
31 | 35 | ||
32 | /** DMA **/ | 36 | struct dma_data |
33 | #ifdef CPU_PP502x | 37 | { |
34 | #define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x3f000000) >> 24) | 38 | /* NOTE: The order of size and p is important if you use assembler |
35 | #elif CONFIG_CPU == PP5002 | 39 | optimised fiq handler, so don't change it. */ |
36 | #define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x7800000) >> 23) | 40 | #if SAMPLE_SIZE == 16 |
41 | uint32_t *p; | ||
42 | #elif SAMPLE_SIZE == 32 | ||
43 | uint16_t *p; | ||
37 | #endif | 44 | #endif |
45 | size_t size; | ||
46 | #if NUM_CORES > 1 | ||
47 | unsigned core; | ||
48 | #endif | ||
49 | int locked; | ||
50 | int state; | ||
51 | } __attribute__((packed)); | ||
52 | |||
53 | extern void *fiq_function; | ||
54 | |||
55 | /* Dispatch to the proper handler and leave the main vector table alone */ | ||
56 | void fiq_handler(void) ICODE_ATTR __attribute__((naked)); | ||
57 | void fiq_handler(void) | ||
58 | { | ||
59 | asm volatile ( | ||
60 | "ldr pc, [pc, #-4] \n" | ||
61 | "fiq_function: \n" | ||
62 | ".word 0 \n" | ||
63 | ); | ||
64 | } | ||
65 | |||
66 | /* TODO: Get simultaneous recording and playback to work. Just needs some tweaking */ | ||
38 | 67 | ||
39 | /**************************************************************************** | 68 | /**************************************************************************** |
40 | ** Playback DMA transfer | 69 | ** Playback DMA transfer |
41 | **/ | 70 | **/ |
42 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ | 71 | struct dma_data dma_play_data NOCACHEBSS_ATTR = |
72 | { | ||
73 | /* Initialize to a locked, stopped state */ | ||
74 | .p = NULL, | ||
75 | .size = 0, | ||
76 | #if NUM_CORES > 1 | ||
77 | .core = 0x00, | ||
78 | #endif | ||
79 | .locked = 0, | ||
80 | .state = 0 | ||
81 | }; | ||
43 | 82 | ||
44 | /* NOTE: The order of these two variables is important if you use the iPod | 83 | static unsigned long pcm_freq NOCACHEDATA_ATTR = HW_SAMPR_DEFAULT; /* 44.1 is default */ |
45 | assembler optimised fiq handler, so don't change it. */ | 84 | |
46 | unsigned short* p IBSS_ATTR; | 85 | void pcm_set_frequency(unsigned int frequency) |
47 | size_t p_size IBSS_ATTR; | 86 | { |
87 | (void)frequency; | ||
88 | pcm_freq = HW_SAMPR_DEFAULT; | ||
89 | } | ||
90 | |||
91 | void pcm_apply_settings(void) | ||
92 | { | ||
93 | pcm_curr_sampr = pcm_freq; | ||
94 | } | ||
48 | 95 | ||
49 | /* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode | 96 | /* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode |
50 | has registers r8-r14 banked, and so does not need to be saved. This routine | 97 | has registers r8-r14 banked, and so does not need to be saved. This routine |
51 | uses only these registers, and so will never touch the stack unless it | 98 | uses only these registers, and so will never touch the stack unless it |
52 | actually needs to do so when calling pcm_callback_for_more. C version is | 99 | actually needs to do so when calling pcm_callback_for_more. C version is |
53 | still included below for reference. | 100 | still included below for reference and testing. |
54 | */ | 101 | */ |
55 | #if 1 | 102 | #if 1 |
56 | void fiq(void) ICODE_ATTR __attribute__((naked)); | 103 | void fiq_playback(void) ICODE_ATTR __attribute__((naked)); |
57 | void fiq(void) | 104 | void fiq_playback(void) |
58 | { | 105 | { |
59 | /* r12 contains IISCONFIG address (set in crt0.S to minimise code in actual | 106 | /* r10 contains IISCONFIG address (set in crt0.S to minimise code in actual |
60 | * FIQ handler. r11 contains address of p (also set in crt0.S). Most other | 107 | * FIQ handler. r11 contains address of p (also set in crt0.S). Most other |
61 | * addresses we need are generated by using offsets with these two. | 108 | * addresses we need are generated by using offsets with these two. |
62 | * r12 + 0x40 is IISFIFO_WR, and r12 + 0x0c is IISFIFO_CFG. | 109 | * r10 + 0x40 is IISFIFO_WR, and r10 + 0x0c is IISFIFO_CFG. |
63 | * r8 and r9 contains local copies of p_size and p respectively. | 110 | * r8 and r9 contains local copies of p and size respectively. |
64 | * r10 is a working register. | 111 | * r12 is a working register. |
65 | */ | 112 | */ |
66 | asm volatile ( | 113 | asm volatile ( |
67 | #if CONFIG_CPU == PP5002 | 114 | #if CONFIG_CPU == PP5002 |
68 | "ldr r10, =0xcf001040 \n\t" /* Some magic from iPodLinux */ | 115 | "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */ |
69 | "ldr r10, [r10] \n\t" | 116 | "ldr r12, [r12] \n" |
70 | "ldr r10, [r12, #0x1c]\n\t" | ||
71 | "bic r10, r10, #0x200 \n\t" /* clear interrupt */ | ||
72 | "str r10, [r12, #0x1c]\n\t" | ||
73 | #else | ||
74 | "ldr r10, [r12] \n\t" | ||
75 | "bic r10, r10, #0x2 \n\t" /* clear interrupt */ | ||
76 | "str r10, [r12] \n\t" | ||
77 | #endif | ||
78 | "ldr r8, [r11, #4] \n\t" /* r8 = p_size */ | ||
79 | "ldr r9, [r11] \n\t" /* r9 = p */ | ||
80 | ".loop: \n\t" | ||
81 | "cmp r8, #0 \n\t" /* is p_size 0? */ | ||
82 | "beq .more_data \n\t" /* if so, ask pcmbuf for more data */ | ||
83 | ".fifo_loop: \n\t" | ||
84 | #if CONFIG_CPU == PP5002 | ||
85 | "ldr r10, [r12, #0x1c]\n\t" /* read IISFIFO_CFG to check FIFO status */ | ||
86 | "and r10, r10, #0x7800000\n\t" | ||
87 | "cmp r10, #0x800000 \n\t" | ||
88 | #else | ||
89 | "ldr r10, [r12, #0x0c]\n\t" /* read IISFIFO_CFG to check FIFO status */ | ||
90 | "and r10, r10, #0x3f0000\n\t" | ||
91 | "cmp r10, #0x10000 \n\t" | ||
92 | #endif | ||
93 | "bls .fifo_full \n\t" /* FIFO full, exit */ | ||
94 | "ldr r10, [r9], #4 \n\t" /* load two samples */ | ||
95 | #ifdef HAVE_AS3514 | ||
96 | "str r10, [r12, #0x40]\n\t" /* write them */ | ||
97 | #else | ||
98 | "mov r10, r10, ror #16\n\t" /* put left sample at the top bits */ | ||
99 | "str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */ | ||
100 | "mov r10, r10, lsl #16\n\t" /* shift lower sample up */ | ||
101 | "str r10, [r12, #0x40]\n\t" /* then write it */ | ||
102 | #endif | ||
103 | "subs r8, r8, #4 \n\t" /* check if we have more samples */ | ||
104 | "bne .fifo_loop \n\t" /* yes, continue */ | ||
105 | ".more_data: \n\t" | ||
106 | "stmdb sp!, { r0-r3, r12, lr}\n\t" /* stack scratch regs and lr */ | ||
107 | "mov r0, r11 \n\t" /* r0 = &p */ | ||
108 | "add r1, r11, #4 \n\t" /* r1 = &p_size */ | ||
109 | "str r9, [r0] \n\t" /* save internal copies of variables back */ | ||
110 | "str r8, [r1] \n\t" | ||
111 | "ldr r2, =pcm_callback_for_more\n\t" | ||
112 | "ldr r2, [r2] \n\t" /* get callback address */ | ||
113 | "cmp r2, #0 \n\t" /* check for null pointer */ | ||
114 | "movne lr, pc \n\t" /* call pcm_callback_for_more */ | ||
115 | "bxne r2 \n\t" | ||
116 | "ldmia sp!, { r0-r3, r12, lr}\n\t" | ||
117 | "ldr r8, [r11, #4] \n\t" /* reload p_size and p */ | ||
118 | "ldr r9, [r11] \n\t" | ||
119 | "cmp r8, #0 \n\t" /* did we actually get more data? */ | ||
120 | "bne .loop \n\t" /* yes, continue to try feeding FIFO */ | ||
121 | ".dma_stop: \n\t" /* no more data, do dma_stop() and exit */ | ||
122 | "ldr r10, =pcm_playing\n\t" | ||
123 | "strb r8, [r10] \n\t" /* pcm_playing = false (r8=0, look above) */ | ||
124 | "ldr r10, =pcm_paused \n\t" | ||
125 | "strb r8, [r10] \n\t" /* pcm_paused = false (r8=0, look above) */ | ||
126 | "ldr r10, [r12] \n\t" | ||
127 | #if CONFIG_CPU == PP5002 | ||
128 | "bic r10, r10, #0x4\n\t" /* disable playback FIFO */ | ||
129 | "str r10, [r12] \n\t" | ||
130 | "ldr r10, [r12, #0x1c] \n\t" | ||
131 | "bic r10, r10, #0x200 \n\t" /* clear interrupt */ | ||
132 | "str r10, [r12, #0x1c] \n\t" | ||
133 | #else | ||
134 | "bic r10, r10, #0x20000002\n\t" /* disable playback FIFO and IRQ */ | ||
135 | "str r10, [r12] \n\t" | ||
136 | #endif | 117 | #endif |
137 | "mrs r10, cpsr \n\t" | 118 | "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ |
138 | "orr r10, r10, #0x40 \n\t" /* disable FIQ */ | 119 | "cmp r9, #0 \n" /* is size 0? */ |
139 | "msr cpsr_c, r10 \n\t" | 120 | "beq .more_data \n" /* if so, ask pcmbuf for more data */ |
140 | ".exit: \n\t" | 121 | ".fifo_loop: \n" |
141 | "str r8, [r11, #4] \n\t" | 122 | "ldr r12, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ |
142 | "str r9, [r11] \n\t" | 123 | "ands r12, r12, %[mask] \n" |
143 | "subs pc, lr, #4 \n\t" /* FIQ specific return sequence */ | 124 | "beq .exit \n" /* FIFO full, exit */ |
144 | ".fifo_full: \n\t" /* enable IRQ and exit */ | 125 | "ldr r12, [r8], #4 \n" /* load two samples */ |
145 | #if CONFIG_CPU == PP5002 | 126 | #if SAMPLE_SIZE == 16 |
146 | "ldr r10, [r12, #0x1c]\n\t" | 127 | "str r12, [r10, %[wr]] \n" /* write them */ |
147 | "orr r10, r10, #0x200 \n\t" /* set interrupt */ | 128 | #elif SAMPLE_SIZE == 32 |
148 | "str r10, [r12, #0x1c]\n\t" | 129 | "mov r12, r12, ror #16 \n" /* put left sample at the top bits */ |
149 | #else | 130 | "str r12, [r10, %[wr]] \n" /* write top sample, lower sample ignored */ |
150 | "ldr r10, [r12] \n\t" | 131 | "mov r12, r12, lsl #16 \n" /* shift lower sample up */ |
151 | "orr r10, r10, #0x2 \n\t" /* set interrupt */ | 132 | "str r12, [r10, %[wr]] \n" /* then write it */ |
152 | "str r10, [r12] \n\t" | ||
153 | #endif | 133 | #endif |
154 | "b .exit \n\t" | 134 | "subs r9, r9, #4 \n" /* check if we have more samples */ |
135 | "bne .fifo_loop \n" /* yes, continue */ | ||
136 | ".more_data: \n" | ||
137 | "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */ | ||
138 | "ldr r2, =pcm_callback_for_more \n" | ||
139 | "ldr r2, [r2] \n" /* get callback address */ | ||
140 | "cmp r2, #0 \n" /* check for null pointer */ | ||
141 | "stmneia r11, { r8-r9 } \n" /* save internal copies of variables back */ | ||
142 | "movne r0, r11 \n" /* r0 = &p */ | ||
143 | "addne r1, r11, #4 \n" /* r1 = &size */ | ||
144 | "movne lr, pc \n" /* call pcm_callback_for_more */ | ||
145 | "bxne r2 \n" | ||
146 | "ldmia r11, { r8-r9 } \n" /* reload p and size */ | ||
147 | "cmp r9, #0 \n" /* did we actually get more data? */ | ||
148 | "ldmnefd sp!, { r0-r3, lr } \n" | ||
149 | "bne .fifo_loop \n" /* yes, continue to try feeding FIFO */ | ||
150 | "ldr r12, =pcm_play_dma_stop \n" | ||
151 | "mov lr, pc \n" | ||
152 | "bx r12 \n" | ||
153 | "ldr r12, =pcm_play_dma_stopped_callback \n" | ||
154 | "mov lr, pc \n" | ||
155 | "bx r12 \n" | ||
156 | "ldmfd sp!, { r0-r3, lr } \n" | ||
157 | ".exit: \n" /* (r8=0 if stopping, look above) */ | ||
158 | "stmia r11, { r8-r9 } \n" /* save p and size */ | ||
159 | "subs pc, lr, #4 \n" /* FIQ specific return sequence */ | ||
160 | ".ltorg \n" | ||
161 | : /* These must only be integers! No regs */ | ||
162 | : [mask]"i"(IIS_TX_FREE_MASK & (IIS_TX_FREE_MASK-1)), | ||
163 | [cfg]"i"((int)&IISFIFO_CFG - (int)&IISCONFIG), | ||
164 | [wr]"i"((int)&IISFIFO_WR - (int)&IISCONFIG) | ||
155 | ); | 165 | ); |
156 | } | 166 | } |
157 | #else /* C version for reference */ | 167 | #else /* C version for reference */ |
158 | void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); | 168 | void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR; |
159 | void fiq(void) | 169 | /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ |
170 | void fiq_playback(void) | ||
160 | { | 171 | { |
161 | /* Clear interrupt */ | 172 | register pcm_more_callback_type get_more; |
162 | #ifdef CPU_PP502x | 173 | |
163 | IISCONFIG &= ~(1 << 1); | 174 | #if CONFIG_CPU == PP5002 |
164 | #elif CONFIG_CPU == PP5002 | ||
165 | inl(0xcf001040); | 175 | inl(0xcf001040); |
166 | IISFIFO_CFG &= ~(1<<9); | ||
167 | #endif | 176 | #endif |
168 | 177 | ||
169 | do { | 178 | do { |
170 | while (p_size) { | 179 | while (dma_play_data.size > 0) { |
171 | //if (FIFO_FREE_COUNT < 2) { | 180 | if (IIS_TX_FREE_COUNT < 2) { |
172 | if (((IISFIFO_CFG & (0x1f << 16)) >> 16) < 2) { | ||
173 | /* Enable interrupt */ | ||
174 | #ifdef CPU_PP502x | ||
175 | IISCONFIG |= (1 << 1); | ||
176 | #elif CONFIG_CPU == PP5002 | ||
177 | IISFIFO_CFG |= (1<<9); | ||
178 | #endif | ||
179 | return; | 181 | return; |
180 | } | 182 | } |
181 | 183 | #if SAMPLE_SIZE == 16 | |
182 | #ifdef HAVE_AS3514 | 184 | IISFIFO_WR = *dma_play_data.p++; |
183 | IISFIFO_WR = *(int32_t *)p; | 185 | #elif SAMPLE_SIZE == 32 |
184 | p += 2; | 186 | IISFIFO_WR = *dma_play_data.p++ << 16; |
185 | #else | 187 | IISFIFO_WR = *dma_play_data.p++ << 16; |
186 | IISFIFO_WR = (*(p++))<<16; | ||
187 | IISFIFO_WR = (*(p++))<<16; | ||
188 | #endif | 188 | #endif |
189 | p_size-=4; | 189 | dma_play_data.size -= 4; |
190 | } | 190 | } |
191 | 191 | ||
192 | /* p is empty, get some more data */ | 192 | /* p is empty, get some more data */ |
193 | if (pcm_callback_for_more) { | 193 | get_more = pcm_callback_for_more; |
194 | pcm_callback_for_more((unsigned char**)&p,&p_size); | 194 | if (get_more) { |
195 | get_more((unsigned char**)&dma_play_data.p, | ||
196 | &dma_play_data.size); | ||
195 | } | 197 | } |
196 | } while (p_size); | 198 | } while (dma_play_data.size); |
197 | 199 | ||
198 | /* No more data, so disable the FIFO/FIQ */ | 200 | /* No more data, so disable the FIFO/interrupt */ |
199 | pcm_play_dma_stop(); | 201 | pcm_play_dma_stop(); |
202 | pcm_play_dma_stopped_callback(); | ||
200 | } | 203 | } |
201 | #endif /* ASM / C selection */ | 204 | #endif /* ASM / C selection */ |
202 | 205 | ||
203 | void pcm_play_dma_start(const void *addr, size_t size) | 206 | /* For the locks, FIQ must be disabled because the handler manipulates |
207 | IISCONFIG and the operation is not atomic - dual core support | ||
208 | will require other measures */ | ||
209 | void pcm_play_lock(void) | ||
204 | { | 210 | { |
205 | p=(unsigned short*)addr; | 211 | int status = set_fiq_status(FIQ_DISABLED); |
206 | p_size=size; | ||
207 | |||
208 | pcm_playing = true; | ||
209 | |||
210 | #ifdef CPU_PP502x | ||
211 | CPU_INT_PRIORITY |= I2S_MASK; /* FIQ priority for I2S */ | ||
212 | CPU_INT_EN = I2S_MASK; /* Enable I2S interrupt */ | ||
213 | #else | ||
214 | /* setup I2S interrupt for FIQ */ | ||
215 | outl(inl(0xcf00102c) | DMA_OUT_MASK, 0xcf00102c); | ||
216 | outl(DMA_OUT_MASK, 0xcf001024); | ||
217 | #endif | ||
218 | 212 | ||
219 | /* Clear the FIQ disable bit in cpsr_c */ | 213 | if (++dma_play_data.locked == 1) { |
220 | set_fiq_handler(fiq); | 214 | IIS_IRQTX_REG &= ~IIS_IRQTX; |
221 | enable_fiq(); | 215 | } |
222 | 216 | ||
223 | #if defined(CPU_PP502x) | 217 | set_fiq_status(status); |
224 | /* Enable playback FIFO */ | 218 | } |
225 | IISCONFIG |= (1 << 29); | ||
226 | #elif CONFIG_CPU == PP5002 | ||
227 | IISCONFIG |= 0x4; | ||
228 | #endif | ||
229 | 219 | ||
230 | /* Fill the FIFO - we assume there are enough bytes in the pcm buffer to | 220 | void pcm_play_unlock(void) |
231 | fill the 32-byte FIFO. */ | 221 | { |
232 | while (p_size > 0) { | 222 | int status = set_fiq_status(FIQ_DISABLED); |
233 | if (FIFO_FREE_COUNT < 2) { | ||
234 | /* Enable interrupt */ | ||
235 | #ifdef CPU_PP502x | ||
236 | IISCONFIG |= (1 << 1); | ||
237 | #elif CONFIG_CPU == PP5002 | ||
238 | IISFIFO_CFG |= (1<<9); | ||
239 | #endif | ||
240 | return; | ||
241 | } | ||
242 | 223 | ||
243 | #ifdef HAVE_AS3514 | 224 | if (--dma_play_data.locked == 0 && dma_play_data.state != 0) { |
244 | IISFIFO_WR = *(int32_t *)p; | 225 | IIS_IRQTX_REG |= IIS_IRQTX; |
245 | p += 2; | ||
246 | #else | ||
247 | IISFIFO_WR = (*(p++))<<16; | ||
248 | IISFIFO_WR = (*(p++))<<16; | ||
249 | #endif | ||
250 | p_size-=4; | ||
251 | } | 226 | } |
227 | |||
228 | set_fiq_status(status); | ||
252 | } | 229 | } |
253 | 230 | ||
254 | /* Stops the DMA transfer and interrupt */ | 231 | static void play_start_pcm(void) |
255 | void pcm_play_dma_stop(void) | ||
256 | { | 232 | { |
257 | pcm_playing = false; | 233 | fiq_function = fiq_playback; |
258 | if (!audio_status()) | 234 | pcm_apply_settings(); |
259 | pcm_paused = false; | ||
260 | 235 | ||
261 | #if CONFIG_CPU == PP5020 | 236 | IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */ |
262 | /* Disable TX interrupt */ | 237 | dma_play_data.state = 1; |
263 | IISCONFIG &= ~(1 << 1); | 238 | |
264 | #elif defined(CPU_PP502x) | 239 | /* Fill the FIFO or start when data is used up */ |
265 | /* Disable playback FIFO and interrupt */ | 240 | while (1) { |
266 | IISCONFIG &= ~((1 << 29) | (1 << 1)); | 241 | if (IIS_TX_FREE_COUNT < 2 || dma_play_data.size == 0) { |
267 | #elif CONFIG_CPU == PP5002 | 242 | IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */ |
268 | /* Disable playback FIFO */ | 243 | return; |
269 | IISCONFIG &= ~0x4; | 244 | } |
270 | |||
271 | /* Disable the interrupt */ | ||
272 | IISFIFO_CFG &= ~(1<<9); | ||
273 | #endif | ||
274 | 245 | ||
275 | disable_fiq(); | 246 | #if SAMPLE_SIZE == 16 |
247 | IISFIFO_WR = *dma_play_data.p++; | ||
248 | #elif SAMPLE_SIZE == 32 | ||
249 | IISFIFO_WR = *dma_play_data.p++ << 16; | ||
250 | IISFIFO_WR = *dma_play_data.p++ << 16; | ||
251 | #endif | ||
252 | dma_play_data.size -= 4; | ||
253 | } | ||
276 | } | 254 | } |
277 | 255 | ||
278 | void pcm_play_pause_pause(void) | 256 | static void play_stop_pcm(void) |
279 | { | 257 | { |
280 | #if CONFIG_CPU == PP5020 | ||
281 | /* Disable TX interrupt */ | 258 | /* Disable TX interrupt */ |
282 | IISCONFIG &= ~(1 << 1); | 259 | IIS_IRQTX_REG &= ~IIS_IRQTX; |
283 | #elif defined(CPU_PP502x) | 260 | dma_play_data.state = 0; |
284 | /* Disable playback FIFO and interrupt */ | ||
285 | IISCONFIG &= ~((1 << 29) | (1 << 1)); | ||
286 | #elif CONFIG_CPU == PP5002 | ||
287 | /* Disable the interrupt */ | ||
288 | IISFIFO_CFG &= ~(1<<9); | ||
289 | /* Disable playback FIFO */ | ||
290 | IISCONFIG &= ~0x4; | ||
291 | #endif | ||
292 | disable_fiq(); | ||
293 | } | 261 | } |
294 | 262 | ||
295 | void pcm_play_pause_unpause(void) | 263 | void pcm_play_dma_start(const void *addr, size_t size) |
296 | { | 264 | { |
297 | /* Enable the FIFO and fill it */ | 265 | dma_play_data.p = (void *)addr; |
298 | 266 | dma_play_data.size = size; | |
299 | set_fiq_handler(fiq); | ||
300 | enable_fiq(); | ||
301 | 267 | ||
302 | #if defined(CPU_PP502x) | 268 | #if NUM_CORES > 1 |
303 | /* Enable playback FIFO */ | 269 | /* This will become more important later - and different ! */ |
304 | IISCONFIG |= (1 << 29); | 270 | dma_play_data.core = processor_id(); /* save initiating core */ |
305 | #elif CONFIG_CPU == PP5002 | ||
306 | IISCONFIG |= 0x4; | ||
307 | #endif | 271 | #endif |
308 | 272 | ||
309 | /* Fill the FIFO - we assume there are enough bytes in the | 273 | CPU_INT_PRIORITY |= IIS_MASK; /* FIQ priority for I2S */ |
310 | pcm buffer to fill the 32-byte FIFO. */ | 274 | CPU_INT_EN = IIS_MASK; |
311 | while (p_size > 0) { | ||
312 | if (FIFO_FREE_COUNT < 2) { | ||
313 | /* Enable interrupt */ | ||
314 | #ifdef CPU_PP502x | ||
315 | IISCONFIG |= (1 << 1); | ||
316 | #elif CONFIG_CPU == PP5002 | ||
317 | IISFIFO_CFG |= (1<<9); | ||
318 | #endif | ||
319 | return; | ||
320 | } | ||
321 | 275 | ||
322 | #ifdef HAVE_AS3514 | 276 | play_start_pcm(); |
323 | IISFIFO_WR = *(int32_t *)p; | 277 | } |
324 | p += 2; | 278 | |
325 | #else | 279 | /* Stops the DMA transfer and interrupt */ |
326 | IISFIFO_WR = (*(p++))<<16; | 280 | void pcm_play_dma_stop(void) |
327 | IISFIFO_WR = (*(p++))<<16; | 281 | { |
282 | play_stop_pcm(); | ||
283 | dma_play_data.size = 0; | ||
284 | #if NUM_CORES > 1 | ||
285 | dma_play_data.core = 0; /* no core in control */ | ||
328 | #endif | 286 | #endif |
329 | p_size-=4; | ||
330 | } | ||
331 | } | 287 | } |
332 | 288 | ||
333 | void pcm_set_frequency(unsigned int frequency) | 289 | void pcm_play_dma_pause(bool pause) |
334 | { | 290 | { |
335 | (void)frequency; | 291 | if (pause) { |
336 | pcm_freq = HW_SAMPR_DEFAULT; | 292 | play_stop_pcm(); |
293 | } else { | ||
294 | play_start_pcm(); | ||
295 | } | ||
337 | } | 296 | } |
338 | 297 | ||
339 | size_t pcm_get_bytes_waiting(void) | 298 | size_t pcm_get_bytes_waiting(void) |
340 | { | 299 | { |
341 | return p_size; | 300 | return dma_play_data.size & ~3; |
342 | } | 301 | } |
343 | 302 | ||
344 | void pcm_init(void) | 303 | void pcm_play_dma_init(void) |
345 | { | 304 | { |
346 | pcm_playing = false; | 305 | pcm_set_frequency(SAMPR_44); |
347 | pcm_paused = false; | ||
348 | pcm_callback_for_more = NULL; | ||
349 | 306 | ||
350 | /* Initialize default register values. */ | 307 | /* Initialize default register values. */ |
351 | audiohw_init(); | 308 | audiohw_init(); |
@@ -357,91 +314,129 @@ void pcm_init(void) | |||
357 | audiohw_mute(false); | 314 | audiohw_mute(false); |
358 | #endif | 315 | #endif |
359 | 316 | ||
360 | /* Call pcm_play_dma_stop to initialize everything. */ | 317 | dma_play_data.size = 0; |
361 | pcm_play_dma_stop(); | 318 | #if NUM_CORES > 1 |
362 | 319 | dma_play_data.core = 0; /* no core in control */ | |
363 | #if CONFIG_CPU == PP5020 | ||
364 | /* This processor doesn't like this disabled */ | ||
365 | IISCONFIG |= (1 << 29); | ||
366 | #endif | 320 | #endif |
321 | |||
322 | IISCONFIG |= IIS_TXFIFOEN; | ||
367 | } | 323 | } |
368 | 324 | ||
369 | void pcm_postinit(void) | 325 | void pcm_postinit(void) |
370 | { | 326 | { |
371 | audiohw_postinit(); | 327 | audiohw_postinit(); |
328 | pcm_apply_settings(); | ||
329 | } | ||
330 | |||
331 | const void * pcm_play_dma_get_peak_buffer(int *count) | ||
332 | { | ||
333 | unsigned long addr = (unsigned long)dma_play_data.p; | ||
334 | size_t cnt = dma_play_data.size; | ||
335 | *count = cnt >> 2; | ||
336 | return (void *)((addr + 2) & ~3); | ||
372 | } | 337 | } |
373 | 338 | ||
374 | /**************************************************************************** | 339 | /**************************************************************************** |
375 | ** Recording DMA transfer | 340 | ** Recording DMA transfer |
376 | **/ | 341 | **/ |
377 | #ifdef HAVE_RECORDING | 342 | #ifdef HAVE_RECORDING |
343 | /* PCM recording interrupt routine lockout */ | ||
344 | static struct dma_data dma_rec_data NOCACHEBSS_ATTR = | ||
345 | { | ||
346 | /* Initialize to a locked, stopped state */ | ||
347 | .p = NULL, | ||
348 | .size = 0, | ||
349 | #if NUM_CORES > 1 | ||
350 | .core = 0x00, | ||
351 | #endif | ||
352 | .locked = 0, | ||
353 | .state = 0 | ||
354 | }; | ||
355 | |||
356 | /* For the locks, FIQ must be disabled because the handler manipulates | ||
357 | IISCONFIG and the operation is not atomic - dual core support | ||
358 | will require other measures */ | ||
359 | void pcm_rec_lock(void) | ||
360 | { | ||
361 | int status = set_fiq_status(FIQ_DISABLED); | ||
378 | 362 | ||
379 | #ifdef HAVE_AS3514 | 363 | if (++dma_rec_data.locked == 1) |
380 | void fiq_record(void) ICODE_ATTR __attribute__((naked)); | 364 | IIS_IRQRX_REG &= ~IIS_IRQRX; |
381 | void fiq_record(void) | 365 | |
366 | set_fiq_status(status); | ||
367 | } | ||
368 | |||
369 | void pcm_rec_unlock(void) | ||
382 | { | 370 | { |
383 | register pcm_more_callback_type2 more_ready; | 371 | int status = set_fiq_status(FIQ_DISABLED); |
384 | register int32_t value1, value2; | 372 | |
373 | if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0) | ||
374 | IIS_IRQRX_REG |= IIS_IRQRX; | ||
385 | 375 | ||
386 | asm volatile ("stmfd sp!, {r0-r7, ip, lr} \n"); /* Store context */ | 376 | set_fiq_status(status); |
377 | } | ||
378 | |||
379 | /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ | ||
380 | void fiq_record(void) ICODE_ATTR __attribute__((interrupt ("FIQ"))); | ||
387 | 381 | ||
388 | IISCONFIG &= ~(1 << 0); | 382 | #if defined(SANSA_C200) || defined(SANSA_E200) |
383 | void fiq_record(void) | ||
384 | { | ||
385 | register pcm_more_callback_type2 more_ready; | ||
386 | register int32_t value; | ||
389 | 387 | ||
390 | if (audio_channels == 2) { | 388 | if (audio_channels == 2) { |
391 | /* RX is stereo */ | 389 | /* RX is stereo */ |
392 | while (p_size > 0) { | 390 | while (dma_rec_data.size > 0) { |
393 | if (FIFO_FREE_COUNT < 2) { | 391 | if (IIS_RX_FULL_COUNT < 2) { |
394 | /* enable interrupt */ | 392 | return; |
395 | IISCONFIG |= (1 << 0); | ||
396 | goto fiq_record_exit; | ||
397 | } | 393 | } |
398 | 394 | ||
399 | /* Discard every other sample since ADC clock is 1/2 LRCK */ | 395 | /* Discard every other sample since ADC clock is 1/2 LRCK */ |
400 | value1 = IISFIFO_RD; | 396 | value = IISFIFO_RD; |
401 | value2 = IISFIFO_RD; | 397 | IISFIFO_RD; |
402 | 398 | ||
403 | *(int32_t *)p = value1; | 399 | *dma_rec_data.p++ = value; |
404 | p += 2; | 400 | dma_rec_data.size -= 4; |
405 | p_size -= 4; | ||
406 | 401 | ||
407 | /* TODO: Figure out how to do IIS loopback */ | 402 | /* TODO: Figure out how to do IIS loopback */ |
408 | if (audio_output_source != AUDIO_SRC_PLAYBACK) { | 403 | if (audio_output_source != AUDIO_SRC_PLAYBACK) { |
409 | if ((IISFIFO_CFG & (0x3f << 16)) >= (16 << 16)) { | 404 | if (IIS_TX_FREE_COUNT >= 16) { |
410 | /* Resync the output FIFO - it ran dry */ | 405 | /* Resync the output FIFO - it ran dry */ |
411 | IISFIFO_WR = 0; | 406 | IISFIFO_WR = 0; |
412 | IISFIFO_WR = 0; | 407 | IISFIFO_WR = 0; |
413 | } | 408 | } |
414 | IISFIFO_WR = value1; | 409 | IISFIFO_WR = value; |
415 | IISFIFO_WR = value1; | 410 | IISFIFO_WR = value; |
416 | } | 411 | } |
417 | } | 412 | } |
418 | } | 413 | } |
419 | else { | 414 | else { |
420 | /* RX is left channel mono */ | 415 | /* RX is left channel mono */ |
421 | while (p_size > 0) { | 416 | while (dma_rec_data.size > 0) { |
422 | if (FIFO_FREE_COUNT < 2) { | 417 | if (IIS_RX_FULL_COUNT < 2) { |
423 | /* enable interrupt */ | 418 | return; |
424 | IISCONFIG |= (1 << 0); | ||
425 | goto fiq_record_exit; | ||
426 | } | 419 | } |
427 | 420 | ||
428 | /* Discard every other sample since ADC clock is 1/2 LRCK */ | 421 | /* Discard every other sample since ADC clock is 1/2 LRCK */ |
429 | value1 = IISFIFO_RD; | 422 | value = IISFIFO_RD; |
430 | value2 = IISFIFO_RD; | 423 | IISFIFO_RD; |
431 | *p++ = value1; | 424 | |
432 | *p++ = value1; | 425 | value = (uint16_t)value | (value << 16); |
433 | p_size -= 4; | 426 | |
427 | *dma_rec_data.p++ = value; | ||
428 | dma_rec_data.size -= 4; | ||
434 | 429 | ||
435 | if (audio_output_source != AUDIO_SRC_PLAYBACK) { | 430 | if (audio_output_source != AUDIO_SRC_PLAYBACK) { |
436 | if ((IISFIFO_CFG & (0x3f << 16)) >= (16 << 16)) { | 431 | if (IIS_TX_FREE_COUNT >= 16) { |
437 | /* Resync the output FIFO - it ran dry */ | 432 | /* Resync the output FIFO - it ran dry */ |
438 | IISFIFO_WR = 0; | 433 | IISFIFO_WR = 0; |
439 | IISFIFO_WR = 0; | 434 | IISFIFO_WR = 0; |
440 | } | 435 | } |
441 | 436 | ||
442 | value1 = *((int32_t *)p - 1); | 437 | value = *((int32_t *)dma_rec_data.p - 1); |
443 | IISFIFO_WR = value1; | 438 | IISFIFO_WR = value; |
444 | IISFIFO_WR = value1; | 439 | IISFIFO_WR = value; |
445 | } | 440 | } |
446 | } | 441 | } |
447 | } | 442 | } |
@@ -451,281 +446,112 @@ void fiq_record(void) | |||
451 | if (more_ready == NULL || more_ready(0) < 0) { | 446 | if (more_ready == NULL || more_ready(0) < 0) { |
452 | /* Finished recording */ | 447 | /* Finished recording */ |
453 | pcm_rec_dma_stop(); | 448 | pcm_rec_dma_stop(); |
449 | pcm_rec_dma_stopped_callback(); | ||
454 | } | 450 | } |
455 | |||
456 | fiq_record_exit: | ||
457 | asm volatile("ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */ | ||
458 | "subs pc, lr, #4 \n"); /* Return from FIQ */ | ||
459 | } | 451 | } |
460 | 452 | ||
461 | #else | 453 | #else |
462 | static short peak_l, peak_r IBSS_ATTR; | ||
463 | |||
464 | /* Temporary to stop playback crashing after record */ | ||
465 | void fiq_record(void) ICODE_ATTR __attribute__((naked)); | ||
466 | void fiq_record(void) | 454 | void fiq_record(void) |
467 | { | 455 | { |
468 | asm volatile ("stmfd sp!, {r0-r7, r11, ip, lr} \n"); /* Store context */ | ||
469 | |||
470 | register short value; | ||
471 | register pcm_more_callback_type2 more_ready; | 456 | register pcm_more_callback_type2 more_ready; |
472 | register int status = 0; | ||
473 | 457 | ||
474 | /* Clear interrupt */ | 458 | while (dma_rec_data.size > 0) { |
475 | #ifdef CPU_PP502x | 459 | if (IIS_RX_FULL_COUNT < 2) { |
476 | IISCONFIG &= ~(1 << 0); | 460 | return; |
477 | #elif CONFIG_CPU == PP5002 | ||
478 | /* TODO */ | ||
479 | #endif | ||
480 | |||
481 | while (p_size > 0) { | ||
482 | if (FIFO_FREE_COUNT < 2) { | ||
483 | /* enable interrupt */ | ||
484 | #ifdef CPU_PP502x | ||
485 | IISCONFIG |= (1 << 0); | ||
486 | #elif CONFIG_CPU == PP5002 | ||
487 | /* TODO */ | ||
488 | #endif | ||
489 | goto fiq_record_exit; | ||
490 | } | 461 | } |
491 | 462 | ||
492 | value = (unsigned short)(IISFIFO_RD >> 16); | 463 | #if SAMPLE_SIZE == 16 |
493 | if (value > peak_l) peak_l = value; | 464 | *dma_rec_data.p++ = IISFIFO_RD; |
494 | else if (-value > peak_l) peak_l = -value; | 465 | #elif SAMPLE_SIZE == 32 |
495 | *(p++) = value; | 466 | *dma_rec_data.p++ = IISFIFO_RD >> 16; |
496 | 467 | *dma_rec_data.p++ = IISFIFO_RD >> 16; | |
497 | value = (unsigned short)(IISFIFO_RD >> 16); | 468 | #endif |
498 | if (value > peak_r) peak_r = value; | 469 | dma_rec_data.size -= 4; |
499 | else if (-value > peak_r) peak_r = -value; | ||
500 | *(p++) = value; | ||
501 | |||
502 | p_size -= 4; | ||
503 | |||
504 | /* If we have filled the current chunk, start a new one */ | ||
505 | if (p_size == 0) { | ||
506 | rec_peak_left = peak_l; | ||
507 | rec_peak_right = peak_r; | ||
508 | peak_l = peak_r = 0; | ||
509 | } | ||
510 | } | 470 | } |
511 | 471 | ||
512 | more_ready = pcm_callback_more_ready; | 472 | more_ready = pcm_callback_more_ready; |
513 | 473 | ||
514 | if (more_ready != NULL && more_ready(status) >= 0) | 474 | if (more_ready == NULL || more_ready(0) < 0) { |
515 | goto fiq_record_exit; | 475 | /* Finished recording */ |
516 | 476 | pcm_rec_dma_stop(); | |
517 | /* Finished recording */ | 477 | pcm_rec_dma_stopped_callback(); |
518 | pcm_rec_dma_stop(); | 478 | } |
519 | |||
520 | fiq_record_exit: | ||
521 | asm volatile("ldmfd sp!, {r0-r7, r11, ip, lr} \n" /* Restore context */ | ||
522 | "subs pc, lr, #4 \n"); /* Return from FIQ */ | ||
523 | } | 479 | } |
524 | 480 | ||
525 | #endif /* HAVE_AS3514 */ | 481 | #endif /* SANSA_E200 */ |
526 | 482 | ||
527 | /* Continue transferring data in */ | 483 | /* Continue transferring data in */ |
528 | void pcm_record_more(void *start, size_t size) | 484 | void pcm_record_more(void *start, size_t size) |
529 | { | 485 | { |
530 | rec_peak_addr = start; /* Start peaking at dest */ | 486 | pcm_rec_peak_addr = start; /* Start peaking at dest */ |
531 | p = start; /* Start of RX buffer */ | 487 | dma_rec_data.p = start; /* Start of RX buffer */ |
532 | p_size = size; /* Bytes to transfer */ | 488 | dma_rec_data.size = size; /* Bytes to transfer */ |
533 | #ifdef CPU_PP502x | ||
534 | IISCONFIG |= (1 << 0); | ||
535 | #elif CONFIG_CPU == PP5002 | ||
536 | /* TODO */ | ||
537 | #endif | ||
538 | } | 489 | } |
539 | 490 | ||
540 | void pcm_rec_dma_stop(void) | 491 | void pcm_rec_dma_stop(void) |
541 | { | 492 | { |
542 | logf("pcm_rec_dma_stop"); | 493 | /* disable interrupt */ |
543 | 494 | IIS_IRQRX_REG &= ~IIS_IRQRX; | |
544 | disable_fiq(); | ||
545 | 495 | ||
546 | /* clear interrupt, disable fifo */ | 496 | dma_rec_data.state = 0; |
547 | IISCONFIG &= ~((1 << 28) | (1 << 0)); | 497 | dma_rec_data.size = 0; |
548 | 498 | #if NUM_CORES > 1 | |
549 | /* clear rx fifo */ | 499 | dma_rec_data.core = 0x00; |
550 | IISFIFO_CFG |= (1 << 12); | 500 | #endif |
551 | 501 | ||
552 | pcm_recording = false; | 502 | /* disable fifo */ |
503 | IISCONFIG &= ~IIS_RXFIFOEN; | ||
504 | IISFIFO_CFG |= IIS_RXCLR; | ||
553 | } | 505 | } |
554 | 506 | ||
555 | void pcm_rec_dma_start(void *addr, size_t size) | 507 | void pcm_rec_dma_start(void *addr, size_t size) |
556 | { | 508 | { |
557 | logf("pcm_rec_dma_start"); | 509 | pcm_rec_dma_stop(); |
558 | |||
559 | pcm_recording = true; | ||
560 | 510 | ||
561 | #ifndef HAVE_AS3514 | 511 | pcm_rec_peak_addr = addr; |
562 | peak_l = peak_r = 0; | 512 | dma_rec_data.p = addr; |
513 | dma_rec_data.size = size; | ||
514 | #if NUM_CORES > 1 | ||
515 | /* This will become more important later - and different ! */ | ||
516 | dma_rec_data.core = processor_id(); /* save initiating core */ | ||
563 | #endif | 517 | #endif |
518 | /* setup FIQ handler */ | ||
519 | fiq_function = fiq_record; | ||
564 | 520 | ||
565 | p_size = size; | 521 | /* interrupt on full fifo, enable record fifo interrupt */ |
566 | p = addr; | 522 | dma_rec_data.state = 1; |
567 | |||
568 | /* setup FIQ */ | ||
569 | CPU_INT_PRIORITY |= I2S_MASK; | ||
570 | CPU_INT_EN = I2S_MASK; | ||
571 | 523 | ||
572 | /* interrupt on full fifo, enable record fifo */ | 524 | /* enable RX FIFO */ |
573 | IISCONFIG |= (1 << 28) | (1 << 0); | 525 | IISCONFIG |= IIS_RXFIFOEN; |
574 | 526 | ||
575 | set_fiq_handler(fiq_record); | 527 | /* enable IIS interrupt as FIQ */ |
576 | enable_fiq(); | 528 | CPU_INT_PRIORITY |= IIS_MASK; |
529 | CPU_INT_EN = IIS_MASK; | ||
577 | } | 530 | } |
578 | 531 | ||
579 | void pcm_close_recording(void) | 532 | void pcm_rec_dma_close(void) |
580 | { | 533 | { |
581 | logf("pcm_close_recording"); | ||
582 | pcm_rec_dma_stop(); | 534 | pcm_rec_dma_stop(); |
583 | } /* pcm_close_recording */ | 535 | } /* pcm_close_recording */ |
584 | 536 | ||
585 | void pcm_init_recording(void) | 537 | void pcm_rec_dma_init(void) |
586 | { | 538 | { |
587 | logf("pcm_init_recording"); | ||
588 | |||
589 | pcm_recording = false; | ||
590 | pcm_callback_more_ready = NULL; | ||
591 | |||
592 | #ifdef CPU_PP502x | ||
593 | #if defined(IPOD_COLOR) || defined (IPOD_4G) | 539 | #if defined(IPOD_COLOR) || defined (IPOD_4G) |
594 | /* The usual magic from IPL - I'm guessing this configures the headphone | 540 | /* The usual magic from IPL - I'm guessing this configures the headphone |
595 | socket to be input or output - in this case, input. */ | 541 | socket to be input or output - in this case, input. */ |
596 | GPIOI_OUTPUT_VAL &= ~0x40; | 542 | GPIOI_OUTPUT_VAL &= ~0x40; |
597 | GPIOA_OUTPUT_VAL &= ~0x4; | 543 | GPIOA_OUTPUT_VAL &= ~0x4; |
598 | #endif | 544 | #endif |
599 | /* Setup the recording FIQ handler */ | ||
600 | set_fiq_handler(fiq_record); | ||
601 | #endif | ||
602 | 545 | ||
603 | pcm_rec_dma_stop(); | 546 | pcm_rec_dma_stop(); |
604 | } /* pcm_init */ | 547 | } /* pcm_init */ |
605 | 548 | ||
606 | void pcm_calculate_rec_peaks(int *left, int *right) | 549 | const void * pcm_rec_dma_get_peak_buffer(int *count) |
607 | { | 550 | { |
608 | #ifdef HAVE_AS3514 | 551 | unsigned long addr = (unsigned long)pcm_rec_peak_addr; |
609 | if (pcm_recording) | 552 | unsigned long end = (unsigned long)dma_rec_data.p; |
610 | { | 553 | *count = (end >> 2) - (addr >> 2); |
611 | unsigned long *start = rec_peak_addr; | 554 | return (void *)(addr & ~3); |
612 | unsigned long *end = (unsigned long *)p; | 555 | } /* pcm_rec_dma_get_peak_buffer */ |
613 | |||
614 | if (start < end) | ||
615 | { | ||
616 | unsigned long *addr = start; | ||
617 | long peak_l = 0, peak_r = 0; | ||
618 | long peaksq_l = 0, peaksq_r = 0; | ||
619 | |||
620 | do | ||
621 | { | ||
622 | long value = *addr; | ||
623 | long ch, chsq; | ||
624 | |||
625 | ch = (int16_t)value; | ||
626 | chsq = ch*ch; | ||
627 | if (chsq > peaksq_l) | ||
628 | peak_l = ch, peaksq_l = chsq; | ||
629 | |||
630 | ch = value >> 16; | ||
631 | chsq = ch*ch; | ||
632 | if (chsq > peaksq_r) | ||
633 | peak_r = ch, peaksq_r = chsq; | ||
634 | |||
635 | addr += 4; | ||
636 | } | ||
637 | while (addr < end); | ||
638 | |||
639 | if (start == rec_peak_addr) | ||
640 | rec_peak_addr = end; | ||
641 | |||
642 | rec_peak_left = abs(peak_l); | ||
643 | rec_peak_right = abs(peak_r); | ||
644 | } | ||
645 | } | ||
646 | else | ||
647 | { | ||
648 | rec_peak_left = rec_peak_right = 0; | ||
649 | } | ||
650 | #endif /* HAVE_AS3514 */ | ||
651 | |||
652 | if (left) | ||
653 | *left = rec_peak_left; | ||
654 | 556 | ||
655 | if (right) | ||
656 | *right = rec_peak_right; | ||
657 | } | ||
658 | #endif /* HAVE_RECORDING */ | 557 | #endif /* HAVE_RECORDING */ |
659 | |||
660 | /* | ||
661 | * This function goes directly into the DMA buffer to calculate the left and | ||
662 | * right peak values. To avoid missing peaks it tries to look forward two full | ||
663 | * peek periods (2/HZ sec, 100% overlap), although it's always possible that | ||
664 | * the entire period will not be visible. To reduce CPU load it only looks at | ||
665 | * every third sample, and this can be reduced even further if needed (even | ||
666 | * every tenth sample would still be pretty accurate). | ||
667 | */ | ||
668 | |||
669 | /* Check for a peak every PEAK_STRIDE samples */ | ||
670 | #define PEAK_STRIDE 3 | ||
671 | /* Up to 1/50th of a second of audio for peak calculation */ | ||
672 | /* This should use NATIVE_FREQUENCY, or eventually an adjustable freq. value */ | ||
673 | #define PEAK_SAMPLES (44100/50) | ||
674 | void pcm_calculate_peaks(int *left, int *right) | ||
675 | { | ||
676 | short *addr; | ||
677 | short *end; | ||
678 | { | ||
679 | size_t samples = p_size / 4; | ||
680 | addr = p; | ||
681 | |||
682 | if (samples > PEAK_SAMPLES) | ||
683 | samples = PEAK_SAMPLES - (PEAK_STRIDE - 1); | ||
684 | else | ||
685 | samples -= MIN(PEAK_STRIDE - 1, samples); | ||
686 | |||
687 | end = &addr[samples * 2]; | ||
688 | } | ||
689 | |||
690 | if (left && right) { | ||
691 | int left_peak = 0, right_peak = 0; | ||
692 | |||
693 | while (addr < end) { | ||
694 | int value; | ||
695 | if ((value = addr [0]) > left_peak) | ||
696 | left_peak = value; | ||
697 | else if (-value > left_peak) | ||
698 | left_peak = -value; | ||
699 | |||
700 | if ((value = addr [PEAK_STRIDE | 1]) > right_peak) | ||
701 | right_peak = value; | ||
702 | else if (-value > right_peak) | ||
703 | right_peak = -value; | ||
704 | |||
705 | addr = &addr[PEAK_STRIDE * 2]; | ||
706 | } | ||
707 | |||
708 | *left = left_peak; | ||
709 | *right = right_peak; | ||
710 | } | ||
711 | else if (left || right) { | ||
712 | int peak_value = 0, value; | ||
713 | |||
714 | if (right) | ||
715 | addr += (PEAK_STRIDE | 1); | ||
716 | |||
717 | while (addr < end) { | ||
718 | if ((value = addr [0]) > peak_value) | ||
719 | peak_value = value; | ||
720 | else if (-value > peak_value) | ||
721 | peak_value = -value; | ||
722 | |||
723 | addr += PEAK_STRIDE * 2; | ||
724 | } | ||
725 | |||
726 | if (left) | ||
727 | *left = peak_value; | ||
728 | else | ||
729 | *right = peak_value; | ||
730 | } | ||
731 | } | ||
diff --git a/firmware/target/arm/pnx0101/pcm-pnx0101.c b/firmware/target/arm/pnx0101/pcm-pnx0101.c index 8b076cc918..adfc752e8e 100644 --- a/firmware/target/arm/pnx0101/pcm-pnx0101.c +++ b/firmware/target/arm/pnx0101/pcm-pnx0101.c | |||
@@ -25,9 +25,36 @@ | |||
25 | short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; | 25 | short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; |
26 | short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; | 26 | short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; |
27 | 27 | ||
28 | /* From pcm_playback.c */ | 28 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ |
29 | extern unsigned short* p; | 29 | |
30 | extern size_t p_size; | 30 | unsigned short* p IBSS_ATTR; |
31 | size_t p_size IBSS_ATTR; | ||
32 | |||
33 | void pcm_play_lock(void) | ||
34 | { | ||
35 | } | ||
36 | |||
37 | void pcm_play_unlock(void) | ||
38 | { | ||
39 | } | ||
40 | |||
41 | void pcm_play_dma_start(const void *addr, size_t size) | ||
42 | { | ||
43 | pcm_apply_settings(); | ||
44 | |||
45 | p = (unsigned short*)addr; | ||
46 | p_size = size; | ||
47 | } | ||
48 | |||
49 | void pcm_play_dma_stop(void) | ||
50 | { | ||
51 | } | ||
52 | |||
53 | void pcm_play_dma_pause(bool pause) | ||
54 | { | ||
55 | if (!pause) | ||
56 | pcm_apply_settings(); | ||
57 | } | ||
31 | 58 | ||
32 | static inline void fill_dma_buf(int offset) | 59 | static inline void fill_dma_buf(int offset) |
33 | { | 60 | { |
@@ -85,7 +112,8 @@ static inline void fill_dma_buf(int offset) | |||
85 | &p_size); | 112 | &p_size); |
86 | } | 113 | } |
87 | while (p_size); | 114 | while (p_size); |
88 | pcm_playing = false; | 115 | |
116 | pcm_play_dma_stopped_callback(); | ||
89 | } | 117 | } |
90 | 118 | ||
91 | if (l < lend) | 119 | if (l < lend) |
@@ -117,9 +145,7 @@ void pcm_init(void) | |||
117 | { | 145 | { |
118 | int i; | 146 | int i; |
119 | 147 | ||
120 | pcm_playing = false; | 148 | pcm_set_frequency(HW_SAMPR_DEFAULT); |
121 | pcm_paused = false; | ||
122 | pcm_callback_for_more = NULL; | ||
123 | 149 | ||
124 | memset(dma_buf_left, 0, sizeof(dma_buf_left)); | 150 | memset(dma_buf_left, 0, sizeof(dma_buf_left)); |
125 | memset(dma_buf_right, 0, sizeof(dma_buf_right)); | 151 | memset(dma_buf_right, 0, sizeof(dma_buf_right)); |
@@ -159,3 +185,32 @@ void pcm_init(void) | |||
159 | DMAR10(1) |= 1; | 185 | DMAR10(1) |= 1; |
160 | } | 186 | } |
161 | 187 | ||
188 | void pcm_postinit(void) | ||
189 | { | ||
190 | audiohw_postinit(); | ||
191 | pcm_apply_settings(); | ||
192 | } | ||
193 | |||
194 | void pcm_set_frequency(unsigned int frequency) | ||
195 | { | ||
196 | (void)frequency; | ||
197 | pcm_freq = HW_SAMPR_DEFAULT; | ||
198 | } | ||
199 | |||
200 | void pcm_apply_settings(void) | ||
201 | { | ||
202 | pcm_curr_sampr = pcm_freq; | ||
203 | } | ||
204 | |||
205 | size_t pcm_get_bytes_waiting(void) | ||
206 | { | ||
207 | return p_size & ~3; | ||
208 | } | ||
209 | |||
210 | const void * pcm_play_dma_get_peak_buffer(int *count) | ||
211 | { | ||
212 | unsigned long addr = (unsigned long)p; | ||
213 | size_t cnt = p_size; | ||
214 | *count = cnt >> 2; | ||
215 | return (void *)((addr + 2) & ~3); | ||
216 | } | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c index 57873faaff..a38b4e424e 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c | |||
@@ -25,31 +25,42 @@ | |||
25 | #include "file.h" | 25 | #include "file.h" |
26 | #include "mmu-meg-fx.h" | 26 | #include "mmu-meg-fx.h" |
27 | 27 | ||
28 | /* All exact rates for 16.9344MHz clock */ | ||
28 | #define GIGABEAT_11025HZ (0x19 << 1) | 29 | #define GIGABEAT_11025HZ (0x19 << 1) |
29 | #define GIGABEAT_22050HZ (0x1b << 1) | 30 | #define GIGABEAT_22050HZ (0x1b << 1) |
30 | #define GIGABEAT_44100HZ (0x11 << 1) | 31 | #define GIGABEAT_44100HZ (0x11 << 1) |
31 | #define GIGABEAT_88200HZ (0x1f << 1) | 32 | #define GIGABEAT_88200HZ (0x1f << 1) |
32 | 33 | ||
33 | static int pcm_freq = 0; /* 44.1 is default */ | 34 | /* PCM interrupt routine lockout */ |
35 | static struct | ||
36 | { | ||
37 | int locked; | ||
38 | unsigned long state; | ||
39 | } dma_play_lock = | ||
40 | { | ||
41 | .locked = 0, | ||
42 | .state = (0<<19) | ||
43 | }; | ||
44 | |||
45 | /* Last samplerate set by pcm_set_frequency */ | ||
46 | static unsigned long pcm_freq = 0; /* 44.1 is default */ | ||
47 | /* Samplerate control for audio codec */ | ||
34 | static int sr_ctrl = 0; | 48 | static int sr_ctrl = 0; |
35 | #define FIFO_COUNT ((IISFCON >> 6) & 0x01F) | 49 | |
50 | #define FIFO_COUNT ((IISFCON >> 6) & 0x3F) | ||
36 | 51 | ||
37 | /* Setup for the DMA controller */ | 52 | /* Setup for the DMA controller */ |
38 | #define DMA_CONTROL_SETUP ((1<<31) | (1<<29) | (1<<23) | (1<<22) | (1<<20)) | 53 | #define DMA_CONTROL_SETUP ((1<<31) | (1<<29) | (1<<23) | (1<<22) | (1<<20)) |
39 | 54 | ||
40 | /* DMA count has hit zero - no more data */ | 55 | /* DMA count has hit zero - no more data */ |
41 | /* Get more data from the callback and top off the FIFO */ | 56 | /* Get more data from the callback and top off the FIFO */ |
42 | /* Uses explicitly coded prologue/epilogue code to get around complier bugs | 57 | void fiq_handler(void) __attribute__((interrupt ("FIQ"))); |
43 | in order to be able to use the stack */ | ||
44 | void fiq_handler(void) __attribute__((naked)); | ||
45 | 58 | ||
46 | static void _pcm_apply_settings(void) | 59 | static void _pcm_apply_settings(void) |
47 | { | 60 | { |
48 | static int last_freqency = 0; | 61 | if (pcm_freq != pcm_curr_sampr) |
49 | |||
50 | if (pcm_freq != last_freqency) | ||
51 | { | 62 | { |
52 | last_freqency = pcm_freq; | 63 | pcm_curr_sampr = pcm_freq; |
53 | audiohw_set_frequency(sr_ctrl); | 64 | audiohw_set_frequency(sr_ctrl); |
54 | } | 65 | } |
55 | } | 66 | } |
@@ -61,29 +72,50 @@ void pcm_apply_settings(void) | |||
61 | set_fiq_status(oldstatus); | 72 | set_fiq_status(oldstatus); |
62 | } | 73 | } |
63 | 74 | ||
64 | void pcm_init(void) | 75 | /* For the locks, DMA interrupt must be disabled because the handler |
76 | manipulates INTMSK and the operation is not atomic */ | ||
77 | void pcm_play_lock(void) | ||
78 | { | ||
79 | int status = set_fiq_status(FIQ_DISABLED); | ||
80 | if (++dma_play_lock.locked == 1) | ||
81 | INTMSK |= (1<<19); /* Mask the DMA interrupt */ | ||
82 | set_fiq_status(status); | ||
83 | } | ||
84 | |||
85 | void pcm_play_unlock(void) | ||
65 | { | 86 | { |
66 | pcm_playing = false; | 87 | int status = set_fiq_status(FIQ_DISABLED); |
67 | pcm_paused = false; | 88 | if (--dma_play_lock.locked == 0) |
68 | pcm_callback_for_more = NULL; | 89 | INTMSK &= ~dma_play_lock.state; /* Unmask the DMA interrupt if enabled */ |
90 | set_fiq_status(status); | ||
91 | } | ||
69 | 92 | ||
93 | void pcm_play_dma_init(void) | ||
94 | { | ||
70 | pcm_set_frequency(SAMPR_44); | 95 | pcm_set_frequency(SAMPR_44); |
71 | 96 | ||
72 | /* slave */ | 97 | /* slave */ |
73 | IISMOD |= (1<<8); | 98 | IISMOD |= (1<<8); |
74 | 99 | ||
100 | /* RX,TX off,idle */ | ||
101 | IISCON |= (1<<3) | (1<<2); | ||
102 | |||
75 | audiohw_init(); | 103 | audiohw_init(); |
76 | 104 | ||
77 | /* init GPIO */ | 105 | /* init GPIO */ |
78 | GPCCON = (GPCCON & ~(3<<14)) | (1<<14); | 106 | GPCCON = (GPCCON & ~(3<<14)) | (1<<14); |
79 | GPCDAT |= 1<<7; | 107 | GPCDAT |= (1<<7); |
80 | GPECON |= 0x2aa; | 108 | /* GPE4=I2SDO, GPE3=I2SDI, GPE2=CDCLK, GPE1=I2SSCLK, GPE0=I2SLRCK */ |
109 | GPECON = (GPECON & ~0x3ff) | 0x2aa; | ||
81 | 110 | ||
82 | /* Do not service DMA requests, yet */ | 111 | /* Do not service DMA requests, yet */ |
112 | |||
83 | /* clear any pending int and mask it */ | 113 | /* clear any pending int and mask it */ |
84 | INTMSK |= (1<<19); /* mask the interrupt */ | 114 | INTMSK |= (1<<19); |
85 | SRCPND = (1<<19); /* clear any pending interrupts */ | 115 | SRCPND = (1<<19); |
86 | INTMOD |= (1<<19); /* connect to FIQ */ | 116 | |
117 | /* connect to FIQ */ | ||
118 | INTMOD |= (1<<19); | ||
87 | } | 119 | } |
88 | 120 | ||
89 | void pcm_postinit(void) | 121 | void pcm_postinit(void) |
@@ -92,21 +124,69 @@ void pcm_postinit(void) | |||
92 | pcm_apply_settings(); | 124 | pcm_apply_settings(); |
93 | } | 125 | } |
94 | 126 | ||
95 | void pcm_play_dma_start(const void *addr, size_t size) | 127 | /* Connect the DMA and start filling the FIFO */ |
128 | static void play_start_pcm(void) | ||
129 | { | ||
130 | /* clear pending DMA interrupt */ | ||
131 | SRCPND = (1<<19); | ||
132 | |||
133 | _pcm_apply_settings(); | ||
134 | |||
135 | /* Flush any pending writes */ | ||
136 | clean_dcache_range((void*)DISRC2, (DCON2 & 0xFFFFF) * 2); | ||
137 | |||
138 | /* unmask DMA interrupt when unlocking */ | ||
139 | dma_play_lock.state = (1<<19); | ||
140 | |||
141 | /* turn on the request */ | ||
142 | IISCON |= (1<<5); | ||
143 | |||
144 | /* Activate the channel */ | ||
145 | DMASKTRIG2 = 0x2; | ||
146 | |||
147 | /* turn off the idle */ | ||
148 | IISCON &= ~(1<<3); | ||
149 | |||
150 | /* start the IIS */ | ||
151 | IISCON |= (1<<0); | ||
152 | } | ||
153 | |||
154 | /* Disconnect the DMA and wait for the FIFO to clear */ | ||
155 | static void play_stop_pcm(void) | ||
96 | { | 156 | { |
97 | addr = (void *)((unsigned long)addr & ~3); /* Align data */ | 157 | /* Mask DMA interrupt */ |
98 | size &= ~3; /* Size must be multiple of 4 */ | 158 | INTMSK |= (1<<19); |
159 | |||
160 | /* De-Activate the DMA channel */ | ||
161 | DMASKTRIG2 = 0x4; | ||
162 | |||
163 | /* are we playing? wait for the chunk to finish */ | ||
164 | if (dma_play_lock.state != 0) | ||
165 | { | ||
166 | /* wait for the FIFO to empty and DMA to stop */ | ||
167 | while ((IISCON & (1<<7)) || (DMASKTRIG2 & 0x2)); | ||
168 | } | ||
169 | |||
170 | /* Keep interrupt masked when unlocking */ | ||
171 | dma_play_lock.state = 0; | ||
172 | |||
173 | /* turn off the request */ | ||
174 | IISCON &= ~(1<<5); | ||
99 | 175 | ||
100 | /* sanity check: bad pointer or too small file */ | 176 | /* turn on the idle */ |
101 | if (NULL == addr || size == 0) return; | 177 | IISCON |= (1<<3); |
102 | 178 | ||
103 | disable_fiq(); | 179 | /* stop the IIS */ |
180 | IISCON &= ~(1<<0); | ||
181 | } | ||
104 | 182 | ||
183 | void pcm_play_dma_start(const void *addr, size_t size) | ||
184 | { | ||
105 | /* Enable the IIS clock */ | 185 | /* Enable the IIS clock */ |
106 | CLKCON |= (1<<17); | 186 | CLKCON |= (1<<17); |
107 | 187 | ||
108 | /* IIS interface setup and set to idle */ | 188 | /* stop any DMA in progress - idle IIS */ |
109 | IISCON = (1<<5) | (1<<3); | 189 | play_stop_pcm(); |
110 | 190 | ||
111 | /* slave, transmit mode, 16 bit samples - MCLK 384fs - use 16.9344Mhz - | 191 | /* slave, transmit mode, 16 bit samples - MCLK 384fs - use 16.9344Mhz - |
112 | BCLK 32fs */ | 192 | BCLK 32fs */ |
@@ -116,155 +196,80 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
116 | IISFCON = (1<<15) | (1<<13); | 196 | IISFCON = (1<<15) | (1<<13); |
117 | 197 | ||
118 | /* set DMA dest */ | 198 | /* set DMA dest */ |
119 | DIDST2 = (int)&IISFIFO; | 199 | DIDST2 = (unsigned int)&IISFIFO; |
120 | 200 | ||
121 | /* IIS is on the APB bus, INT when TC reaches 0, fixed dest addr */ | 201 | /* IIS is on the APB bus, INT when TC reaches 0, fixed dest addr */ |
122 | DIDSTC2 = 0x03; | 202 | DIDSTC2 = 0x03; |
123 | 203 | ||
204 | /* set DMA source and options */ | ||
205 | DISRC2 = (unsigned int)addr + 0x30000000; | ||
124 | /* How many transfers to make - we transfer half-word at a time = 2 bytes */ | 206 | /* How many transfers to make - we transfer half-word at a time = 2 bytes */ |
125 | /* DMA control: CURR_TC int, single service mode, I2SSDO int, HW trig */ | 207 | /* DMA control: CURR_TC int, single service mode, I2SSDO int, HW trig */ |
126 | /* no auto-reload, half-word (16bit) */ | 208 | /* no auto-reload, half-word (16bit) */ |
127 | DCON2 = DMA_CONTROL_SETUP | (size / 2); | 209 | DCON2 = DMA_CONTROL_SETUP | (size / 2); |
128 | |||
129 | /* set DMA source and options */ | ||
130 | DISRC2 = (unsigned long)addr + 0x30000000; | ||
131 | DISRCC2 = 0x00; /* memory is on AHB bus, increment addresses */ | 210 | DISRCC2 = 0x00; /* memory is on AHB bus, increment addresses */ |
132 | 211 | ||
133 | /* clear pending DMA interrupt */ | 212 | play_start_pcm(); |
134 | SRCPND = 1<<19; | 213 | } |
135 | |||
136 | pcm_playing = true; | ||
137 | |||
138 | _pcm_apply_settings(); | ||
139 | |||
140 | /* unmask the DMA interrupt */ | ||
141 | INTMSK &= ~(1<<19); | ||
142 | |||
143 | /* Flush any pending writes */ | ||
144 | clean_dcache_range(addr, size); | ||
145 | |||
146 | /* Activate the channel */ | ||
147 | DMASKTRIG2 = 0x2; | ||
148 | |||
149 | /* turn off the idle */ | ||
150 | IISCON &= ~(1<<3); | ||
151 | 214 | ||
152 | /* start the IIS */ | 215 | /* Promptly stop DMA transfers and stop IIS */ |
153 | IISCON |= (1<<0); | 216 | void pcm_play_dma_stop(void) |
217 | { | ||
218 | play_stop_pcm(); | ||
154 | 219 | ||
155 | enable_fiq(); | 220 | /* Disconnect the IIS clock */ |
221 | CLKCON &= ~(1<<17); | ||
156 | } | 222 | } |
157 | 223 | ||
158 | static void pcm_play_dma_stop_fiq(void) | 224 | void pcm_play_dma_pause(bool pause) |
159 | { | 225 | { |
160 | INTMSK |= (1<<19); /* mask the DMA interrupt */ | 226 | if (pause) |
161 | IISCON &= ~(1<<5); /* disable fifo request */ | ||
162 | DMASKTRIG2 = 0x4; /* De-Activate the DMA channel */ | ||
163 | |||
164 | /* are we playing? wait for the chunk to finish */ | ||
165 | if (pcm_playing) | ||
166 | { | 227 | { |
167 | /* wait for the FIFO to empty before turning things off */ | 228 | /* pause playback on current buffer */ |
168 | while (IISCON & (1<<7)) ; | 229 | play_stop_pcm(); |
169 | 230 | } | |
170 | pcm_playing = false; | 231 | else |
171 | if (!audio_status()) | 232 | { |
172 | pcm_paused = false; | 233 | /* restart playback on current buffer */ |
234 | /* make sure we're aligned on left channel - skip any right | ||
235 | channel sample left waiting */ | ||
236 | DISRC2 = (DCSRC2 + 2) & ~0x3; | ||
237 | DCON2 = DMA_CONTROL_SETUP | (DSTAT2 & 0xFFFFE); | ||
238 | play_start_pcm(); | ||
173 | } | 239 | } |
174 | |||
175 | /* Disconnect the IIS clock */ | ||
176 | CLKCON &= ~(1<<17); | ||
177 | } | 240 | } |
178 | 241 | ||
179 | void fiq_handler(void) | 242 | void fiq_handler(void) |
180 | { | 243 | { |
181 | /* r0-r7 are probably not all used by GCC but there's no way to know | 244 | static unsigned char *start; |
182 | otherwise this whole thing must be assembly */ | 245 | static size_t size; |
183 | asm volatile ("stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */ | ||
184 | "sub sp, sp, #8 \n"); /* Reserve stack */ | ||
185 | register pcm_more_callback_type get_more; /* No stack for this */ | 246 | register pcm_more_callback_type get_more; /* No stack for this */ |
186 | unsigned char *next_start; /* sp + #0 */ | ||
187 | size_t next_size; /* sp + #4 */ | ||
188 | 247 | ||
189 | /* clear any pending interrupt */ | 248 | /* clear any pending interrupt */ |
190 | SRCPND = (1<<19); | 249 | SRCPND = (1<<19); |
191 | 250 | ||
192 | /* Buffer empty. Try to get more. */ | 251 | /* Buffer empty. Try to get more. */ |
193 | get_more = pcm_callback_for_more; | 252 | get_more = pcm_callback_for_more; |
194 | if (get_more == NULL) | 253 | size = 0; |
195 | { | ||
196 | /* Callback missing */ | ||
197 | pcm_play_dma_stop_fiq(); | ||
198 | goto fiq_exit; | ||
199 | } | ||
200 | |||
201 | next_size = 0; | ||
202 | get_more(&next_start, &next_size); | ||
203 | 254 | ||
204 | if (next_size == 0) | 255 | if (get_more == NULL || (get_more(&start, &size), size == 0)) |
205 | { | 256 | { |
206 | /* No more DMA to do */ | 257 | /* Callback missing or no more DMA to do */ |
207 | pcm_play_dma_stop_fiq(); | 258 | pcm_play_dma_stop(); |
208 | goto fiq_exit; | 259 | pcm_play_dma_stopped_callback(); |
209 | } | 260 | } |
210 | 261 | else | |
211 | /* Flush any pending cache writes */ | ||
212 | clean_dcache_range(next_start, next_size); | ||
213 | |||
214 | /* set the new DMA values */ | ||
215 | DCON2 = DMA_CONTROL_SETUP | (next_size >> 1); | ||
216 | DISRC2 = (unsigned long)next_start + 0x30000000; | ||
217 | |||
218 | /* Re-Activate the channel */ | ||
219 | DMASKTRIG2 = 0x2; | ||
220 | |||
221 | fiq_exit: | ||
222 | asm volatile("add sp, sp, #8 \n" /* Cleanup stack */ | ||
223 | "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */ | ||
224 | "subs pc, lr, #4 \n"); /* Return from FIQ */ | ||
225 | } | ||
226 | |||
227 | /* Disconnect the DMA and wait for the FIFO to clear */ | ||
228 | void pcm_play_dma_stop(void) | ||
229 | { | ||
230 | disable_fiq(); | ||
231 | pcm_play_dma_stop_fiq(); | ||
232 | } | ||
233 | |||
234 | void pcm_play_pause_pause(void) | ||
235 | { | ||
236 | /* stop servicing refills */ | ||
237 | int oldstatus = set_fiq_status(FIQ_DISABLED); | ||
238 | INTMSK |= (1<<19); /* mask interrupt request */ | ||
239 | IISCON &= ~(1<<5); /* turn off FIFO request */ | ||
240 | DMASKTRIG2 = 0x4; /* stop DMA at end of atomic transfer */ | ||
241 | |||
242 | if (pcm_playing) | ||
243 | { | 262 | { |
244 | /* playing - wait for the FIFO to empty */ | 263 | /* Flush any pending cache writes */ |
245 | while (IISCON & (1<<7)) ; | 264 | clean_dcache_range(start, size); |
246 | } | ||
247 | 265 | ||
248 | set_fiq_status(oldstatus); | 266 | /* set the new DMA values */ |
249 | } | 267 | DCON2 = DMA_CONTROL_SETUP | (size >> 1); |
268 | DISRC2 = (unsigned int)start + 0x30000000; | ||
250 | 269 | ||
251 | void pcm_play_pause_unpause(void) | 270 | /* Re-Activate the channel */ |
252 | { | 271 | DMASKTRIG2 = 0x2; |
253 | /* refill buffer and keep going */ | ||
254 | int oldstatus = set_fiq_status(FIQ_DISABLED); | ||
255 | _pcm_apply_settings(); | ||
256 | if (pcm_playing) | ||
257 | { | ||
258 | /* make sure we're aligned on left channel - skip any right channel | ||
259 | sample left waiting */ | ||
260 | DISRC2 = (DCSRC2 + 2) & ~0x3; | ||
261 | DCON2 = (DSTAT2 & 0xFFFFE); | ||
262 | |||
263 | SRCPND = (1<<19); /* clear pending DMA interrupt */ | ||
264 | INTMSK &= ~(1<<19); /* unmask interrupt request */ | ||
265 | IISCON |= (1<<5); /* enable FIFO request */ | ||
266 | } | 272 | } |
267 | set_fiq_status(oldstatus); | ||
268 | } | 273 | } |
269 | 274 | ||
270 | void pcm_set_frequency(unsigned int frequency) | 275 | void pcm_set_frequency(unsigned int frequency) |
@@ -296,89 +301,10 @@ size_t pcm_get_bytes_waiting(void) | |||
296 | return (DSTAT2 & 0xFFFFE) * 2; | 301 | return (DSTAT2 & 0xFFFFE) * 2; |
297 | } | 302 | } |
298 | 303 | ||
299 | /** **/ | 304 | const void * pcm_play_dma_get_peak_buffer(int *count) |
300 | |||
301 | void pcm_mute(bool mute) | ||
302 | { | 305 | { |
303 | audiohw_mute(mute); | 306 | unsigned long addr = DCSRC2; |
304 | if (mute) | 307 | int cnt = DSTAT2; |
305 | sleep(HZ/16); | 308 | *count = (cnt & 0xFFFFF) >> 1; |
309 | return (void *)((addr + 2) & ~3); | ||
306 | } | 310 | } |
307 | |||
308 | /** | ||
309 | * Return playback peaks - Peaks ahead in the DMA buffer based upon the | ||
310 | * calling period to attempt to compensate for | ||
311 | * delay. | ||
312 | */ | ||
313 | void pcm_calculate_peaks(int *left, int *right) | ||
314 | { | ||
315 | static unsigned long last_peak_tick = 0; | ||
316 | static unsigned long frame_period = 0; | ||
317 | static int peaks_l = 0, peaks_r = 0; | ||
318 | |||
319 | /* Throttled peak ahead based on calling period */ | ||
320 | unsigned long period = current_tick - last_peak_tick; | ||
321 | |||
322 | /* Keep reasonable limits on period */ | ||
323 | if (period < 1) | ||
324 | period = 1; | ||
325 | else if (period > HZ/5) | ||
326 | period = HZ/5; | ||
327 | |||
328 | frame_period = (3*frame_period + period) >> 2; | ||
329 | |||
330 | last_peak_tick = current_tick; | ||
331 | |||
332 | if (pcm_playing && !pcm_paused) | ||
333 | { | ||
334 | unsigned long *addr = (unsigned long *)DCSRC2; | ||
335 | long samples = DSTAT2; | ||
336 | long samp_frames; | ||
337 | |||
338 | addr = (unsigned long *)((unsigned long)addr & ~3); | ||
339 | samples &= 0xFFFFE; | ||
340 | samp_frames = frame_period*pcm_freq/(HZ/2); | ||
341 | samples = MIN(samp_frames, samples) >> 1; | ||
342 | |||
343 | if (samples > 0) | ||
344 | { | ||
345 | long peak_l = 0, peak_r = 0; | ||
346 | long peaksq_l = 0, peaksq_r = 0; | ||
347 | |||
348 | addr -= 0x30000000 >> 2; | ||
349 | addr = (long *)((long)addr & ~3); | ||
350 | |||
351 | do | ||
352 | { | ||
353 | long value = *addr; | ||
354 | long ch, chsq; | ||
355 | |||
356 | ch = (int16_t)value; | ||
357 | chsq = ch*ch; | ||
358 | if (chsq > peaksq_l) | ||
359 | peak_l = ch, peaksq_l = chsq; | ||
360 | |||
361 | ch = value >> 16; | ||
362 | chsq = ch*ch; | ||
363 | if (chsq > peaksq_r) | ||
364 | peak_r = ch, peaksq_r = chsq; | ||
365 | |||
366 | addr += 4; | ||
367 | } | ||
368 | while ((samples -= 4) > 0); | ||
369 | |||
370 | peaks_l = abs(peak_l); | ||
371 | peaks_r = abs(peak_r); | ||
372 | } | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | peaks_l = peaks_r = 0; | ||
377 | } | ||
378 | |||
379 | if (left) | ||
380 | *left = peaks_l; | ||
381 | |||
382 | if (right) | ||
383 | *right = peaks_r; | ||
384 | } /* pcm_calculate_peaks */ | ||
diff --git a/firmware/target/arm/system-arm.h b/firmware/target/arm/system-arm.h index c3af652ebc..774cdbcff4 100644 --- a/firmware/target/arm/system-arm.h +++ b/firmware/target/arm/system-arm.h | |||
@@ -74,12 +74,6 @@ static inline uint32_t swap_odd_even32(uint32_t value) | |||
74 | return value; | 74 | return value; |
75 | } | 75 | } |
76 | 76 | ||
77 | static inline void set_fiq_handler(void(*fiq_handler)(void)) | ||
78 | { | ||
79 | /* Install the FIQ handler */ | ||
80 | *((unsigned int*)(15*4)) = (unsigned int)fiq_handler; | ||
81 | } | ||
82 | |||
83 | static inline void enable_fiq(void) | 77 | static inline void enable_fiq(void) |
84 | { | 78 | { |
85 | /* Clear FIQ disable bit */ | 79 | /* Clear FIQ disable bit */ |
diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c index 576459d6c1..8110cfc127 100644 --- a/firmware/target/arm/system-pp502x.c +++ b/firmware/target/arm/system-pp502x.c | |||
@@ -214,6 +214,7 @@ void system_init(void) | |||
214 | outl(inl(0x70000024) | 0xc0, 0x70000024); | 214 | outl(inl(0x70000024) | 0xc0, 0x70000024); |
215 | DEV_RS = 0; | 215 | DEV_RS = 0; |
216 | DEV_OFF_MASK = 0; | 216 | DEV_OFF_MASK = 0; |
217 | STRAP_OPT_A = 0x80; | ||
217 | #endif | 218 | #endif |
218 | 219 | ||
219 | #if !defined(SANSA_E200) && !defined(SANSA_C200) | 220 | #if !defined(SANSA_E200) && !defined(SANSA_C200) |
diff --git a/firmware/target/arm/system-target.h b/firmware/target/arm/system-target.h index 6b35a49c97..7a1ff4f79a 100644 --- a/firmware/target/arm/system-target.h +++ b/firmware/target/arm/system-target.h | |||
@@ -70,6 +70,20 @@ static inline unsigned int current_core(void) | |||
70 | return core; | 70 | return core; |
71 | } | 71 | } |
72 | 72 | ||
73 | /* Return the actual ID instead of core index */ | ||
74 | static inline unsigned int processor_id(void) | ||
75 | { | ||
76 | unsigned char id; | ||
77 | |||
78 | asm volatile ( | ||
79 | "ldrb %0, [%1] \n" | ||
80 | : "=r"(id) | ||
81 | : "r"(&PROCESSOR_ID) | ||
82 | ); | ||
83 | |||
84 | return id; | ||
85 | } | ||
86 | |||
73 | #ifdef BOOTLOADER | 87 | #ifdef BOOTLOADER |
74 | /* All addresses within rockbox are in IRAM in the bootloader so | 88 | /* All addresses within rockbox are in IRAM in the bootloader so |
75 | are therefore uncached */ | 89 | are therefore uncached */ |