diff options
Diffstat (limited to 'firmware/target/arm/pcm-pp.c')
-rw-r--r-- | firmware/target/arm/pcm-pp.c | 43 |
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 */ |
116 | void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void) | 117 | void 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 */ |
265 | void fiq_playback(void) | 282 | void 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 */ |