summaryrefslogtreecommitdiff
path: root/firmware/target/arm/pcm-pp.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/pcm-pp.c')
-rw-r--r--firmware/target/arm/pcm-pp.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c
index c446f98fcf..704296d407 100644
--- a/firmware/target/arm/pcm-pp.c
+++ b/firmware/target/arm/pcm-pp.c
@@ -26,6 +26,7 @@
26#include "sound.h" 26#include "sound.h"
27#include "pcm.h" 27#include "pcm.h"
28#include "pcm_sampr.h" 28#include "pcm_sampr.h"
29#include "pcm-internal.h"
29 30
30/** DMA **/ 31/** DMA **/
31 32
@@ -115,6 +116,7 @@ void pcm_dma_apply_settings(void)
115/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ 116/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
116void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void) 117void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
117{ 118{
119 bool new_buffer = false;
118 register size_t size; 120 register size_t size;
119 121
120 DMA0_STATUS; /* Clear any pending interrupt */ 122 DMA0_STATUS; /* Clear any pending interrupt */
@@ -136,9 +138,14 @@ void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
136 /* Set the new DMA values and activate channel */ 138 /* Set the new DMA values and activate channel */
137 DMA0_RAM_ADDR = dma_play_data.addr; 139 DMA0_RAM_ADDR = dma_play_data.addr;
138 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; 140 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
141
142 if (new_buffer)
143 pcm_play_dma_started_callback();
139 return; 144 return;
140 } 145 }
141 146
147 new_buffer = true;
148
142 /* Buffer empty. Try to get more. */ 149 /* Buffer empty. Try to get more. */
143 pcm_play_get_more_callback((void **)&dma_play_data.addr, 150 pcm_play_get_more_callback((void **)&dma_play_data.addr,
144 &dma_play_data.size); 151 &dma_play_data.size);
@@ -181,8 +188,9 @@ void fiq_playback(void)
181 * r0-r3 and r12 is a working register. 188 * r0-r3 and r12 is a working register.
182 */ 189 */
183 asm volatile ( 190 asm volatile (
184 "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */ 191 "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */
185 192
193 "mov r4, #0 \n" /* Was the callback called? */
186#if CONFIG_CPU == PP5002 194#if CONFIG_CPU == PP5002
187 "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */ 195 "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */
188 "ldr r12, [r12] \n" 196 "ldr r12, [r12] \n"
@@ -212,16 +220,13 @@ void fiq_playback(void)
212 "tst r1, #1 \n" /* two samples (one word) left? */ 220 "tst r1, #1 \n" /* two samples (one word) left? */
213 "ldrne r12, [r8], #4 \n" /* load two samples */ 221 "ldrne r12, [r8], #4 \n" /* load two samples */
214 "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ 222 "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
215
216 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
217 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
218#elif SAMPLE_SIZE == 32 223#elif SAMPLE_SIZE == 32
219 ".check_fifo: \n" 224 ".check_fifo: \n"
220 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ 225 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
221 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */ 226 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */
222 227
223 "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */ 228 "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */
224 "beq .exit \n" /* no complete pair? -> exit */ 229 "beq .fifo_fill_complete \n" /* no complete pair? -> exit */
225 "cmp r1, r9, lsr #2 \n" /* number of words from source */ 230 "cmp r1, r9, lsr #2 \n" /* number of words from source */
226 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ 231 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
227 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ 232 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
@@ -234,11 +239,23 @@ void fiq_playback(void)
234 "subs r1, r1, #1 \n" /* one more loop? */ 239 "subs r1, r1, #1 \n" /* one more loop? */
235 "bgt .fifo_loop \n" /* yes, continue */ 240 "bgt .fifo_loop \n" /* yes, continue */
236 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"
237 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */ 254 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
238 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */ 255 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
239#endif
240 256
241 ".more_data: \n" 257 ".more_data: \n"
258 "mov r4, #1 \n" /* Remember we did this */
242 "ldr r2, =pcm_play_get_more_callback \n" 259 "ldr r2, =pcm_play_get_more_callback \n"
243 "mov r0, r11 \n" /* r0 = &p */ 260 "mov r0, r11 \n" /* r0 = &p */
244 "add r1, r11, #4 \n" /* r1 = &size */ 261 "add r1, r11, #4 \n" /* r1 = &size */
@@ -250,7 +267,7 @@ void fiq_playback(void)
250 267
251 ".exit: \n" /* (r9=0 if stopping, look above) */ 268 ".exit: \n" /* (r9=0 if stopping, look above) */
252 "stmia r11, { r8-r9 } \n" /* save p and size */ 269 "stmia r11, { r8-r9 } \n" /* save p and size */
253 "ldmfd sp!, { r0-r3, lr } \n" 270 "ldmfd sp!, { r0-r4, lr } \n"
254 "subs pc, lr, #4 \n" /* FIQ specific return sequence */ 271 "subs pc, lr, #4 \n" /* FIQ specific return sequence */
255 ".ltorg \n" 272 ".ltorg \n"
256 : /* These must only be integers! No regs */ 273 : /* These must only be integers! No regs */
@@ -264,6 +281,8 @@ void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR;
264/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ 281/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
265void fiq_playback(void) 282void fiq_playback(void)
266{ 283{
284 bool new_buffer = false;
285
267#if CONFIG_CPU == PP5002 286#if CONFIG_CPU == PP5002
268 inl(0xcf001040); 287 inl(0xcf001040);
269#endif 288#endif
@@ -271,6 +290,10 @@ void fiq_playback(void)
271 do { 290 do {
272 while (dma_play_data.size > 0) { 291 while (dma_play_data.size > 0) {
273 if (IIS_TX_FREE_COUNT < 2) { 292 if (IIS_TX_FREE_COUNT < 2) {
293 if (new_buffer) {
294 new_buffer = false;
295 pcm_play_dma_started_callback();
296 }
274 return; 297 return;
275 } 298 }
276#if SAMPLE_SIZE == 16 299#if SAMPLE_SIZE == 16
@@ -282,9 +305,15 @@ void fiq_playback(void)
282 dma_play_data.size -= 4; 305 dma_play_data.size -= 4;
283 } 306 }
284 307
308 if (new_buffer) {
309 new_buffer = false;
310 pcm_play_dma_started_callback();
311 }
312
285 /* p is empty, get some more data */ 313 /* p is empty, get some more data */
286 pcm_play_get_more_callback((void **)&dma_play_data.addr, 314 pcm_play_get_more_callback((void **)&dma_play_data.addr,
287 &dma_play_data.size); 315 &dma_play_data.size);
316 new_buffer = true;
288 } while (dma_play_data.size); 317 } while (dma_play_data.size);
289 318
290 /* No more data */ 319 /* No more data */