diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/tcc780x/cowond2/audio-cowond2.c | 92 | ||||
-rw-r--r-- | firmware/target/arm/tcc780x/cowond2/power-cowond2.c | 3 | ||||
-rw-r--r-- | firmware/target/arm/tcc780x/crt0.S | 8 | ||||
-rw-r--r-- | firmware/target/arm/tcc780x/pcm-tcc780x.c | 249 |
4 files changed, 338 insertions, 14 deletions
diff --git a/firmware/target/arm/tcc780x/cowond2/audio-cowond2.c b/firmware/target/arm/tcc780x/cowond2/audio-cowond2.c new file mode 100644 index 0000000000..f73528247c --- /dev/null +++ b/firmware/target/arm/tcc780x/cowond2/audio-cowond2.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Michael Sevakis | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "system.h" | ||
20 | #include "cpu.h" | ||
21 | #include "audio.h" | ||
22 | #include "sound.h" | ||
23 | |||
24 | int audio_channels = 2; | ||
25 | int audio_output_source = AUDIO_SRC_PLAYBACK; | ||
26 | |||
27 | void audio_set_output_source(int source) | ||
28 | { | ||
29 | int oldmode = set_fiq_status(FIQ_DISABLED); | ||
30 | |||
31 | if ((unsigned)source >= AUDIO_NUM_SOURCES) | ||
32 | source = AUDIO_SRC_PLAYBACK; | ||
33 | |||
34 | audio_output_source = source; | ||
35 | |||
36 | /*if (source != AUDIO_SRC_PLAYBACK) | ||
37 | IISCONFIG |= (1 << 29);*/ | ||
38 | |||
39 | set_fiq_status(oldmode); | ||
40 | } | ||
41 | |||
42 | void audio_input_mux(int source, unsigned flags) | ||
43 | { | ||
44 | static int last_source = AUDIO_SRC_PLAYBACK; | ||
45 | static bool last_recording = false; | ||
46 | bool recording = flags & SRCF_RECORDING; | ||
47 | |||
48 | switch (source) | ||
49 | { | ||
50 | default: /* playback - no recording */ | ||
51 | source = AUDIO_SRC_PLAYBACK; | ||
52 | case AUDIO_SRC_PLAYBACK: | ||
53 | audio_channels = 2; | ||
54 | if (source != last_source) | ||
55 | { | ||
56 | /*audiohw_set_monitor(false); | ||
57 | audiohw_disable_recording();*/ | ||
58 | } | ||
59 | break; | ||
60 | |||
61 | case AUDIO_SRC_MIC: /* recording only */ | ||
62 | audio_channels = 1; | ||
63 | if (source != last_source) | ||
64 | { | ||
65 | /*audiohw_set_monitor(false); | ||
66 | audiohw_enable_recording(true); /. source mic */ | ||
67 | } | ||
68 | break; | ||
69 | |||
70 | case AUDIO_SRC_FMRADIO: /* recording and playback */ | ||
71 | audio_channels = 2; | ||
72 | |||
73 | if (source == last_source && recording == last_recording) | ||
74 | break; | ||
75 | |||
76 | last_recording = recording; | ||
77 | |||
78 | if (recording) | ||
79 | { | ||
80 | /*audiohw_set_monitor(false); | ||
81 | audiohw_enable_recording(false);*/ | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | /*audiohw_disable_recording(); | ||
86 | audiohw_set_monitor(true); /. line 1 analog audio path */ | ||
87 | } | ||
88 | break; | ||
89 | } /* end switch */ | ||
90 | |||
91 | last_source = source; | ||
92 | } /* audio_input_mux */ | ||
diff --git a/firmware/target/arm/tcc780x/cowond2/power-cowond2.c b/firmware/target/arm/tcc780x/cowond2/power-cowond2.c index c7441256c5..504f4e6eb8 100644 --- a/firmware/target/arm/tcc780x/cowond2/power-cowond2.c +++ b/firmware/target/arm/tcc780x/cowond2/power-cowond2.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "power.h" | 22 | #include "power.h" |
23 | #include "pcf50606.h" | 23 | #include "pcf50606.h" |
24 | #include "button-target.h" | 24 | #include "button-target.h" |
25 | #include "tuner.h" | ||
25 | 26 | ||
26 | #ifndef SIMULATOR | 27 | #ifndef SIMULATOR |
27 | 28 | ||
@@ -69,7 +70,6 @@ void EXT3(void) | |||
69 | unsigned char data[3]; /* 0 = INT1, 1 = INT2, 2 = INT3 */ | 70 | unsigned char data[3]; /* 0 = INT1, 1 = INT2, 2 = INT3 */ |
70 | 71 | ||
71 | /* Clear pending interrupts from pcf50606 */ | 72 | /* Clear pending interrupts from pcf50606 */ |
72 | int fiq_status = disable_fiq_save(); | ||
73 | pcf50606_read_multiple(0x02, data, 3); | 73 | pcf50606_read_multiple(0x02, data, 3); |
74 | 74 | ||
75 | if (data[0] & 0x04) | 75 | if (data[0] & 0x04) |
@@ -87,7 +87,6 @@ void EXT3(void) | |||
87 | /* Touchscreen event, do something about it */ | 87 | /* Touchscreen event, do something about it */ |
88 | button_set_touch_available(); | 88 | button_set_touch_available(); |
89 | } | 89 | } |
90 | restore_fiq(fiq_status); | ||
91 | } | 90 | } |
92 | #endif | 91 | #endif |
93 | 92 | ||
diff --git a/firmware/target/arm/tcc780x/crt0.S b/firmware/target/arm/tcc780x/crt0.S index cef27f1051..aaa9517329 100644 --- a/firmware/target/arm/tcc780x/crt0.S +++ b/firmware/target/arm/tcc780x/crt0.S | |||
@@ -100,10 +100,18 @@ copied_start: | |||
100 | mov r0,#0xd2 | 100 | mov r0,#0xd2 |
101 | msr cpsr, r0 | 101 | msr cpsr, r0 |
102 | ldr sp, =irq_stack | 102 | ldr sp, =irq_stack |
103 | |||
103 | /* Set up stack for FIQ mode */ | 104 | /* Set up stack for FIQ mode */ |
104 | mov r0,#0xd1 | 105 | mov r0,#0xd1 |
105 | msr cpsr, r0 | 106 | msr cpsr, r0 |
106 | ldr sp, =fiq_stack | 107 | ldr sp, =fiq_stack |
108 | |||
109 | /* Load the banked FIQ mode registers with useful values here. | ||
110 | These values will be used in the FIQ handler in pcm-tcc780x.c */ | ||
111 | .equ DADO_BASE, 0xF0059020 | ||
112 | |||
113 | ldr r10, =DADO_BASE | ||
114 | ldr r11, =dma_play_data | ||
107 | 115 | ||
108 | /* Let abort and undefined modes use IRQ stack */ | 116 | /* Let abort and undefined modes use IRQ stack */ |
109 | mov r0,#0xd7 | 117 | mov r0,#0xd7 |
diff --git a/firmware/target/arm/tcc780x/pcm-tcc780x.c b/firmware/target/arm/tcc780x/pcm-tcc780x.c index a9312749c8..7db775d4c7 100644 --- a/firmware/target/arm/tcc780x/pcm-tcc780x.c +++ b/firmware/target/arm/tcc780x/pcm-tcc780x.c | |||
@@ -7,7 +7,8 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2007 by Karl Kurbjun | 10 | * Copyright (C) 2006 by Michael Sevakis |
11 | * Copyright (C) 2008 by Rob Purchase | ||
11 | * | 12 | * |
12 | * All files in this archive are subject to the GNU General Public License. | 13 | * All files in this archive are subject to the GNU General Public License. |
13 | * See the file COPYING in the source tree root for full license agreement. | 14 | * See the file COPYING in the source tree root for full license agreement. |
@@ -16,52 +17,176 @@ | |||
16 | * KIND, either express or implied. | 17 | * KIND, either express or implied. |
17 | * | 18 | * |
18 | ****************************************************************************/ | 19 | ****************************************************************************/ |
20 | #include <stdlib.h> | ||
19 | #include "system.h" | 21 | #include "system.h" |
20 | #include "kernel.h" | 22 | #include "kernel.h" |
21 | #include "logf.h" | 23 | #include "logf.h" |
22 | #include "audio.h" | 24 | #include "audio.h" |
23 | #include "sound.h" | 25 | #include "sound.h" |
24 | #include "file.h" | 26 | #include "pcm.h" |
27 | |||
28 | struct dma_data | ||
29 | { | ||
30 | /* NOTE: The order of size and p is important if you use assembler | ||
31 | optimised fiq handler, so don't change it. */ | ||
32 | uint16_t *p; | ||
33 | size_t size; | ||
34 | #if NUM_CORES > 1 | ||
35 | unsigned core; | ||
36 | #endif | ||
37 | int locked; | ||
38 | int state; | ||
39 | }; | ||
40 | |||
41 | /**************************************************************************** | ||
42 | ** Playback DMA transfer | ||
43 | **/ | ||
44 | struct dma_data dma_play_data SHAREDBSS_ATTR = | ||
45 | { | ||
46 | /* Initialize to a locked, stopped state */ | ||
47 | .p = NULL, | ||
48 | .size = 0, | ||
49 | #if NUM_CORES > 1 | ||
50 | .core = 0x00, | ||
51 | #endif | ||
52 | .locked = 0, | ||
53 | .state = 0 | ||
54 | }; | ||
55 | |||
56 | static unsigned long pcm_freq SHAREDDATA_ATTR = HW_SAMPR_DEFAULT; /* 44.1 is default */ | ||
25 | 57 | ||
26 | void pcm_postinit(void) | 58 | void pcm_postinit(void) |
27 | { | 59 | { |
60 | /*audiohw_postinit();*/ | ||
61 | pcm_apply_settings(); | ||
28 | } | 62 | } |
29 | 63 | ||
30 | const void * pcm_play_dma_get_peak_buffer(int *count) | 64 | const void * pcm_play_dma_get_peak_buffer(int *count) |
31 | { | 65 | { |
32 | (void) count; | 66 | unsigned long addr = (unsigned long)dma_play_data.p; |
33 | return 0; | 67 | size_t cnt = dma_play_data.size; |
68 | *count = cnt >> 2; | ||
69 | return (void *)((addr + 2) & ~3); | ||
34 | } | 70 | } |
35 | 71 | ||
36 | void pcm_play_dma_init(void) | 72 | void pcm_play_dma_init(void) |
37 | { | 73 | { |
74 | /* Set DAI clock divided from PLL0 (192MHz). | ||
75 | The best approximation of 256*44.1kHz is 11.291MHz. */ | ||
76 | BCLKCTR &= ~DEV_DAI; | ||
77 | PCLK_DAI = (1<<28) | 61682; /* DCO mode */ | ||
78 | BCLKCTR |= DEV_DAI; | ||
79 | |||
80 | /* Enable DAI block in Master mode, 256fs->32fs, 16bit LSB */ | ||
81 | DAMR = 0x3c8e80; | ||
82 | DAVC = 0x0; /* Digital Volume = max */ | ||
83 | |||
84 | /* Set DAI interrupts as FIQs */ | ||
85 | IRQSEL = ~(DAI_RX_IRQ_MASK | DAI_TX_IRQ_MASK); | ||
86 | |||
87 | pcm_set_frequency(SAMPR_44); | ||
88 | |||
89 | /* Initialize default register values. */ | ||
90 | audiohw_init(); | ||
91 | |||
92 | /* Power on */ | ||
93 | audiohw_enable_output(true); | ||
94 | |||
95 | /* Unmute the master channel (DAC should be at zero point now). */ | ||
96 | audiohw_mute(false); | ||
97 | |||
98 | dma_play_data.size = 0; | ||
99 | #if NUM_CORES > 1 | ||
100 | dma_play_data.core = 0; /* no core in control */ | ||
101 | #endif | ||
38 | } | 102 | } |
39 | 103 | ||
40 | void pcm_apply_settings(void) | 104 | void pcm_apply_settings(void) |
41 | { | 105 | { |
106 | pcm_curr_sampr = pcm_freq; | ||
42 | } | 107 | } |
43 | 108 | ||
44 | void pcm_set_frequency(unsigned int frequency) | 109 | void pcm_set_frequency(unsigned int frequency) |
45 | { | 110 | { |
46 | (void) frequency; | 111 | (void) frequency; |
112 | pcm_freq = HW_SAMPR_DEFAULT; | ||
113 | } | ||
114 | |||
115 | static void play_start_pcm(void) | ||
116 | { | ||
117 | pcm_apply_settings(); | ||
118 | |||
119 | DAMR &= ~(1<<14); /* disable tx */ | ||
120 | dma_play_data.state = 1; | ||
121 | |||
122 | if (dma_play_data.size >= 16) | ||
123 | { | ||
124 | DADO_L(0) = *dma_play_data.p++; | ||
125 | DADO_R(0) = *dma_play_data.p++; | ||
126 | DADO_L(1) = *dma_play_data.p++; | ||
127 | DADO_R(1) = *dma_play_data.p++; | ||
128 | DADO_L(2) = *dma_play_data.p++; | ||
129 | DADO_R(2) = *dma_play_data.p++; | ||
130 | DADO_L(3) = *dma_play_data.p++; | ||
131 | DADO_R(3) = *dma_play_data.p++; | ||
132 | dma_play_data.size -= 16; | ||
133 | } | ||
134 | |||
135 | DAMR |= (1<<14); /* enable tx */ | ||
136 | } | ||
137 | |||
138 | static void play_stop_pcm(void) | ||
139 | { | ||
140 | DAMR &= ~(1<<14); /* disable tx */ | ||
141 | dma_play_data.state = 0; | ||
47 | } | 142 | } |
48 | 143 | ||
49 | void pcm_play_dma_start(const void *addr, size_t size) | 144 | void pcm_play_dma_start(const void *addr, size_t size) |
50 | { | 145 | { |
51 | (void) addr; | 146 | dma_play_data.p = (void *)(((uintptr_t)addr + 2) & ~3); |
52 | (void) size; | 147 | dma_play_data.size = (size & ~3); |
148 | |||
149 | #if NUM_CORES > 1 | ||
150 | /* This will become more important later - and different ! */ | ||
151 | dma_play_data.core = processor_id(); /* save initiating core */ | ||
152 | #endif | ||
153 | |||
154 | IEN |= DAI_TX_IRQ_MASK; | ||
155 | |||
156 | play_start_pcm(); | ||
53 | } | 157 | } |
54 | 158 | ||
55 | void pcm_play_dma_stop(void) | 159 | void pcm_play_dma_stop(void) |
56 | { | 160 | { |
161 | play_stop_pcm(); | ||
162 | dma_play_data.size = 0; | ||
163 | #if NUM_CORES > 1 | ||
164 | dma_play_data.core = 0; /* no core in control */ | ||
165 | #endif | ||
57 | } | 166 | } |
58 | 167 | ||
59 | void pcm_play_lock(void) | 168 | void pcm_play_lock(void) |
60 | { | 169 | { |
170 | int status = disable_fiq_save(); | ||
171 | |||
172 | if (++dma_play_data.locked == 1) | ||
173 | { | ||
174 | IEN &= ~DAI_TX_IRQ_MASK; | ||
175 | } | ||
176 | |||
177 | restore_fiq(status); | ||
61 | } | 178 | } |
62 | 179 | ||
63 | void pcm_play_unlock(void) | 180 | void pcm_play_unlock(void) |
64 | { | 181 | { |
182 | int status = disable_fiq_save(); | ||
183 | |||
184 | if (--dma_play_data.locked == 0 && dma_play_data.state != 0) | ||
185 | { | ||
186 | IEN |= DAI_TX_IRQ_MASK; | ||
187 | } | ||
188 | |||
189 | restore_fiq(status); | ||
65 | } | 190 | } |
66 | 191 | ||
67 | void pcm_play_dma_pause(bool pause) | 192 | void pcm_play_dma_pause(bool pause) |
@@ -71,16 +196,116 @@ void pcm_play_dma_pause(bool pause) | |||
71 | 196 | ||
72 | size_t pcm_get_bytes_waiting(void) | 197 | size_t pcm_get_bytes_waiting(void) |
73 | { | 198 | { |
74 | return 0; | 199 | return dma_play_data.size & ~3; |
75 | } | 200 | } |
76 | 201 | ||
202 | #if 1 | ||
203 | void fiq_handler(void) ICODE_ATTR __attribute__((naked)); | ||
77 | void fiq_handler(void) | 204 | void fiq_handler(void) |
78 | { | 205 | { |
79 | /* Clear FIQ status */ | 206 | /* r10 contains DADO_L0 base address (set in crt0.S to minimise code in the |
80 | CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK; | 207 | * FIQ handler. r11 contains address of p (also set in crt0.S). Most other |
81 | 208 | * addresses we need are generated by using offsets with these two. | |
82 | /* Return from FIQ */ | 209 | * r8 and r9 contains local copies of p and size respectively. |
210 | * r0-r3 and r12 is a working register. | ||
211 | */ | ||
83 | asm volatile ( | 212 | asm volatile ( |
84 | "subs pc, lr, #4 \r\n" | 213 | "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */ |
214 | |||
215 | "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ | ||
216 | "cmp r9, #0x10 \n" /* is size <16? */ | ||
217 | "blt .more_data \n" /* if so, ask pcmbuf for more data */ | ||
218 | |||
219 | ".fill_fifo: \n" | ||
220 | "ldr r12, [r8], #4 \n" /* load two samples */ | ||
221 | "str r12, [r10, #0x0] \n" /* write top sample to DADO_L0 */ | ||
222 | "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */ | ||
223 | "str r12, [r10, #0x4] \n" /* write low sample to DADO_R0*/ | ||
224 | "ldr r12, [r8], #4 \n" /* load two samples */ | ||
225 | "str r12, [r10, #0x8] \n" /* write top sample to DADO_L1 */ | ||
226 | "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */ | ||
227 | "str r12, [r10, #0xc] \n" /* write low sample to DADO_R1*/ | ||
228 | "ldr r12, [r8], #4 \n" /* load two samples */ | ||
229 | "str r12, [r10, #0x10] \n" /* write top sample to DADO_L2 */ | ||
230 | "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */ | ||
231 | "str r12, [r10, #0x14] \n" /* write low sample to DADO_R2*/ | ||
232 | "ldr r12, [r8], #4 \n" /* load two samples */ | ||
233 | "str r12, [r10, #0x18] \n" /* write top sample to DADO_L3 */ | ||
234 | "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */ | ||
235 | "str r12, [r10, #0x1c] \n" /* write low sample to DADO_R3*/ | ||
236 | "sub r9, r9, #0x10 \n" /* 4 words written */ | ||
237 | "stmia r11, { r8-r9 } \n" /* save p and size */ | ||
238 | |||
239 | ".exit: \n" | ||
240 | "mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */ | ||
241 | "ldr r9, =0xf3001004 \n" /* CREQ */ | ||
242 | "str r8, [r9] \n" /* clear DAI IRQs */ | ||
243 | "ldmfd sp!, { r0-r3, lr } \n" | ||
244 | "subs pc, lr, #4 \n" /* FIQ specific return sequence */ | ||
245 | |||
246 | ".more_data: \n" | ||
247 | "ldr r2, =pcm_callback_for_more \n" | ||
248 | "ldr r2, [r2] \n" /* get callback address */ | ||
249 | "cmp r2, #0 \n" /* check for null pointer */ | ||
250 | "movne r0, r11 \n" /* r0 = &p */ | ||
251 | "addne r1, r11, #4 \n" /* r1 = &size */ | ||
252 | "blxne r2 \n" /* call pcm_callback_for_more */ | ||
253 | "ldmia r11, { r8-r9 } \n" /* reload p and size */ | ||
254 | "cmp r9, #0x10 \n" /* did we actually get more data? */ | ||
255 | "bge .fill_fifo \n" /* yes: fill the fifo */ | ||
256 | "ldr r12, =pcm_play_dma_stop \n" | ||
257 | "blx r12 \n" /* no: stop playback */ | ||
258 | "ldr r12, =pcm_play_dma_stopped_callback \n" | ||
259 | "blx r12 \n" | ||
260 | "b .exit \n" | ||
261 | ".ltorg \n" | ||
85 | ); | 262 | ); |
86 | } | 263 | } |
264 | #else /* C version for reference */ | ||
265 | void fiq_handler(void) ICODE_ATTR __attribute__((naked)); | ||
266 | void fiq_handler(void) | ||
267 | { | ||
268 | asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */ | ||
269 | "sub sp, sp, #8 \n"); /* Reserve stack */ | ||
270 | |||
271 | register pcm_more_callback_type get_more; | ||
272 | |||
273 | if (dma_play_data.size < 16) | ||
274 | { | ||
275 | /* p is empty, get some more data */ | ||
276 | get_more = pcm_callback_for_more; | ||
277 | if (get_more) | ||
278 | { | ||
279 | get_more((unsigned char**)&dma_play_data.p, | ||
280 | &dma_play_data.size); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | if (dma_play_data.size >= 16) | ||
285 | { | ||
286 | DADO_L(0) = *dma_play_data.p++; | ||
287 | DADO_R(0) = *dma_play_data.p++; | ||
288 | DADO_L(1) = *dma_play_data.p++; | ||
289 | DADO_R(1) = *dma_play_data.p++; | ||
290 | DADO_L(2) = *dma_play_data.p++; | ||
291 | DADO_R(2) = *dma_play_data.p++; | ||
292 | DADO_L(3) = *dma_play_data.p++; | ||
293 | DADO_R(3) = *dma_play_data.p++; | ||
294 | |||
295 | dma_play_data.size -= 16; | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | /* No more data, so disable the FIFO/interrupt */ | ||
300 | pcm_play_dma_stop(); | ||
301 | pcm_play_dma_stopped_callback(); | ||
302 | } | ||
303 | |||
304 | /* Clear FIQ status */ | ||
305 | CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK; | ||
306 | |||
307 | asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */ | ||
308 | "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */ | ||
309 | "subs pc, lr, #4 \n"); /* Return from FIQ */ | ||
310 | } | ||
311 | #endif | ||