1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 by Michael Sevakis
11 * Copyright (C) 2008 by Rob Purchase
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
32 /* NOTE: The order of size and p is important if you use assembler
33 optimised fiq handler, so don't change it. */
43 /****************************************************************************
44 ** Playback DMA transfer
46 struct dma_data dma_play_data SHAREDBSS_ATTR
=
48 /* Initialize to a locked, stopped state */
58 void pcm_postinit(void)
63 const void * pcm_play_dma_get_peak_buffer(int *count
)
65 unsigned long addr
= (unsigned long)dma_play_data
.p
;
66 size_t cnt
= dma_play_data
.size
;
68 return (void *)((addr
+ 2) & ~3);
71 void pcm_play_dma_init(void)
73 DAVC
= 0x0; /* Digital Volume = max */
75 /* Set DAI clock divided from PLL0 (192MHz).
76 The best approximation of 256*44.1kHz is 11.291MHz. */
78 PCLK_DAI
= (1<<28) | 61682; /* DCO mode */
81 /* Enable DAI block in Master mode, 256fs->32fs, 16bit LSB */
83 #elif defined(IAUDIO_7)
85 PCLK_DAI
= (0x800a << 16) | (PCLK_DAI
& 0xffff);
88 /* Master mode, 256->64fs, 16bit LSB*/
90 #elif defined(LOGIK_DAX)
92 #elif defined(SANSA_M200)
94 #elif defined(SANSA_C100)
97 #error "Target isn't supported"
99 /* Set DAI interrupts as FIQs */
100 IRQSEL
= ~(DAI_RX_IRQ_MASK
| DAI_TX_IRQ_MASK
);
102 /* Initialize default register values. */
105 dma_play_data
.size
= 0;
107 dma_play_data
.core
= 0; /* no core in control */
111 void pcm_dma_apply_settings(void)
115 static void play_start_pcm(void)
117 DAMR
&= ~(1<<14); /* disable tx */
118 dma_play_data
.state
= 1;
120 if (dma_play_data
.size
>= 16)
122 DADO_L(0) = *dma_play_data
.p
++;
123 DADO_R(0) = *dma_play_data
.p
++;
124 DADO_L(1) = *dma_play_data
.p
++;
125 DADO_R(1) = *dma_play_data
.p
++;
126 DADO_L(2) = *dma_play_data
.p
++;
127 DADO_R(2) = *dma_play_data
.p
++;
128 DADO_L(3) = *dma_play_data
.p
++;
129 DADO_R(3) = *dma_play_data
.p
++;
130 dma_play_data
.size
-= 16;
133 DAMR
|= (1<<14); /* enable tx */
136 static void play_stop_pcm(void)
138 DAMR
&= ~(1<<14); /* disable tx */
139 dma_play_data
.state
= 0;
142 void pcm_play_dma_start(const void *addr
, size_t size
)
144 dma_play_data
.p
= (uint16_t*)addr
;
145 dma_play_data
.size
= size
;
148 /* This will become more important later - and different ! */
149 dma_play_data
.core
= processor_id(); /* save initiating core */
152 IEN
|= DAI_TX_IRQ_MASK
;
157 void pcm_play_dma_stop(void)
160 dma_play_data
.size
= 0;
162 dma_play_data
.core
= 0; /* no core in control */
166 void pcm_play_lock(void)
168 int status
= disable_fiq_save();
170 if (++dma_play_data
.locked
== 1)
172 IEN
&= ~DAI_TX_IRQ_MASK
;
178 void pcm_play_unlock(void)
180 int status
= disable_fiq_save();
182 if (--dma_play_data
.locked
== 0 && dma_play_data
.state
!= 0)
184 IEN
|= DAI_TX_IRQ_MASK
;
190 void pcm_play_dma_pause(bool pause
)
199 size_t pcm_get_bytes_waiting(void)
201 return dma_play_data
.size
& ~3;
204 #ifdef HAVE_RECORDING
205 /* TODO: implement */
206 void pcm_rec_dma_init(void)
210 void pcm_rec_dma_close(void)
214 void pcm_rec_dma_start(void *addr
, size_t size
)
220 void pcm_rec_dma_stop(void)
224 void pcm_rec_lock(void)
228 void pcm_rec_unlock(void)
232 const void * pcm_rec_dma_get_peak_buffer(void)
238 #if defined(CPU_TCC77X) || defined(CPU_TCC780X)
239 void fiq_handler(void) ICODE_ATTR
__attribute__((naked
));
240 void fiq_handler(void)
242 /* r10 contains DADO_L0 base address (set in crt0.S to minimise code in the
243 * FIQ handler. r11 contains address of p (also set in crt0.S). Most other
244 * addresses we need are generated by using offsets with these two.
245 * r8 and r9 contains local copies of p and size respectively.
246 * r0-r3 and r12 is a working register.
249 #if defined(CPU_TCC780X)
250 "mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */
251 "ldr r9, =0xf3001004 \n" /* CREQ */
252 #elif defined(CPU_TCC77X)
253 "mov r8, #0x0030 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */
254 "ldr r9, =0x80000104 \n" /* CREQ */
256 "str r8, [r9] \n" /* clear DAI IRQs */
257 "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */
258 "cmp r9, #0x10 \n" /* is size <16? */
259 "blt .more_data \n" /* if so, ask pcmbuf for more data */
262 "ldr r12, [r8], #4 \n" /* load two samples */
263 "str r12, [r10, #0x0] \n" /* write top sample to DADO_L0 */
264 "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */
265 "str r12, [r10, #0x4] \n" /* write low sample to DADO_R0*/
266 "ldr r12, [r8], #4 \n" /* load two samples */
267 "str r12, [r10, #0x8] \n" /* write top sample to DADO_L1 */
268 "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */
269 "str r12, [r10, #0xc] \n" /* write low sample to DADO_R1*/
270 "ldr r12, [r8], #4 \n" /* load two samples */
271 "str r12, [r10, #0x10] \n" /* write top sample to DADO_L2 */
272 "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */
273 "str r12, [r10, #0x14] \n" /* write low sample to DADO_R2*/
274 "ldr r12, [r8], #4 \n" /* load two samples */
275 "str r12, [r10, #0x18] \n" /* write top sample to DADO_L3 */
276 "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */
277 "str r12, [r10, #0x1c] \n" /* write low sample to DADO_R3*/
278 "sub r9, r9, #0x10 \n" /* 4 words written */
279 "stmia r11, { r8-r9 } \n" /* save p and size */
282 "subs pc, lr, #4 \n" /* FIQ specific return sequence */
285 "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */
286 "ldr r2, =pcm_play_get_more_callback \n"
287 "mov r0, r11 \n" /* r0 = &p */
288 "add r1, r11, #4 \n" /* r1 = &size */
289 "blx r2 \n" /* call pcm_play_get_more_callback */
290 "ldmia r11, { r8-r9 } \n" /* load new p and size */
291 "cmp r9, #0x10 \n" /* did we actually get enough data? */
292 "ldmfd sp!, { r0-r3, lr } \n"
293 "bpl .fill_fifo \n" /* not stop and enough? refill */
298 #else /* C version for reference */
299 void fiq_handler(void) ICODE_ATTR
__attribute__((naked
));
300 void fiq_handler(void)
302 asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
303 "sub sp, sp, #8 \n"); /* Reserve stack */
305 if (dma_play_data
.size
< 16)
307 /* p is empty, get some more data */
308 pcm_play_get_more_callback((void**)&dma_play_data
.p
,
309 &dma_play_data
.size
);
312 if (dma_play_data
.size
>= 16)
314 DADO_L(0) = *dma_play_data
.p
++;
315 DADO_R(0) = *dma_play_data
.p
++;
316 DADO_L(1) = *dma_play_data
.p
++;
317 DADO_R(1) = *dma_play_data
.p
++;
318 DADO_L(2) = *dma_play_data
.p
++;
319 DADO_R(2) = *dma_play_data
.p
++;
320 DADO_L(3) = *dma_play_data
.p
++;
321 DADO_R(3) = *dma_play_data
.p
++;
323 dma_play_data
.size
-= 16;
326 /* Clear FIQ status */
327 CREQ
= DAI_TX_IRQ_MASK
| DAI_RX_IRQ_MASK
;
329 asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */
330 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
331 "subs pc, lr, #4 \n"); /* Return from FIQ */
335 /* TODO: required by wm8731 codec */