summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/target/arm/crt0.S8
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c71
2 files changed, 39 insertions, 40 deletions
diff --git a/firmware/target/arm/crt0.S b/firmware/target/arm/crt0.S
index 581a997477..c513bd7ce7 100644
--- a/firmware/target/arm/crt0.S
+++ b/firmware/target/arm/crt0.S
@@ -193,14 +193,6 @@ prefetch_abort_handler:
193 mov r1, #1 193 mov r1, #1
194 b UIE 194 b UIE
195 195
196fiq_handler:
197 @ Branch straight to FIQ handler in pcm_playback.c. This also handles the
198 @ the correct return sequence.
199 stmfd sp!, {r0-r7, r12, lr}
200 bl fiq
201 ldmfd sp!, {r0-r7, r12, lr}
202 subs pc, lr, #4
203
204data_abort_handler: 196data_abort_handler:
205 sub r0, lr, #8 197 sub r0, lr, #8
206 mov r1, #2 198 mov r1, #2
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 2b4842f880..45558767d3 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
@@ -41,13 +41,11 @@ static int sr_ctrl = GIGABEAT_44100HZ;
41/* Setup for the DMA controller */ 41/* Setup for the DMA controller */
42#define DMA_CONTROL_SETUP ((1<<31) | (1<<29) | (1<<23) | (1<<22) | (1<<20)) 42#define DMA_CONTROL_SETUP ((1<<31) | (1<<29) | (1<<23) | (1<<22) | (1<<20))
43 43
44unsigned short * p;
45size_t p_size;
46
47/* DMA count has hit zero - no more data */ 44/* DMA count has hit zero - no more data */
48/* Get more data from the callback and top off the FIFO */ 45/* Get more data from the callback and top off the FIFO */
49//void fiq(void) __attribute__ ((interrupt ("naked"))); 46/* Uses explicitly coded prologue/epilogue code to get around complier bugs
50void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); 47 in order to be able to use the stack */
48void fiq_handler(void) __attribute__((naked));
51 49
52static void _pcm_apply_settings(void) 50static void _pcm_apply_settings(void)
53{ 51{
@@ -98,14 +96,14 @@ void pcm_postinit(void)
98 96
99void pcm_play_dma_start(const void *addr, size_t size) 97void pcm_play_dma_start(const void *addr, size_t size)
100{ 98{
99 addr = (void *)((unsigned long)addr & ~3); /* Align data */
100 size &= ~3; /* Size must be multiple of 4 */
101
101 /* sanity check: bad pointer or too small file */ 102 /* sanity check: bad pointer or too small file */
102 if (NULL == addr || size <= IIS_FIFO_SIZE) return; 103 if (NULL == addr || size <= IIS_FIFO_SIZE) return;
103 104
104 disable_fiq(); 105 disable_fiq();
105 106
106 p = (unsigned short *)addr;
107 p_size = size;
108
109 /* Enable the IIS clock */ 107 /* Enable the IIS clock */
110 CLKCON |= (1<<17); 108 CLKCON |= (1<<17);
111 109
@@ -127,10 +125,10 @@ void pcm_play_dma_start(const void *addr, size_t size)
127 /* How many transfers to make - we transfer half-word at a time = 2 bytes */ 125 /* How many transfers to make - we transfer half-word at a time = 2 bytes */
128 /* DMA control: CURR_TC int, single service mode, I2SSDO int, HW trig */ 126 /* DMA control: CURR_TC int, single service mode, I2SSDO int, HW trig */
129 /* no auto-reload, half-word (16bit) */ 127 /* no auto-reload, half-word (16bit) */
130 DCON2 = DMA_CONTROL_SETUP | (p_size / 2); 128 DCON2 = DMA_CONTROL_SETUP | (size / 2);
131 129
132 /* set DMA source and options */ 130 /* set DMA source and options */
133 DISRC2 = (int)p + 0x30000000; 131 DISRC2 = (unsigned long)addr + 0x30000000;
134 DISRCC2 = 0x00; /* memory is on AHB bus, increment addresses */ 132 DISRCC2 = 0x00; /* memory is on AHB bus, increment addresses */
135 133
136 /* clear pending DMA interrupt */ 134 /* clear pending DMA interrupt */
@@ -140,8 +138,6 @@ void pcm_play_dma_start(const void *addr, size_t size)
140 138
141 _pcm_apply_settings(); 139 _pcm_apply_settings();
142 140
143 set_fiq_handler(fiq);
144
145 /* unmask the DMA interrupt */ 141 /* unmask the DMA interrupt */
146 INTMSK &= ~(1<<19); 142 INTMSK &= ~(1<<19);
147 143
@@ -181,41 +177,52 @@ static void pcm_play_dma_stop_fiq(void)
181 CLKCON &= ~(1<<17); 177 CLKCON &= ~(1<<17);
182} 178}
183 179
184void fiq(void) 180void fiq_handler(void)
185{ 181{
182 /* r0-r7 are probably not all used by GCC but there's no way to know
183 otherwise this whole thing must be assembly */
184 asm volatile ("stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
185 "sub sp, sp, #8 \n"); /* Reserve stack */
186 register pcm_more_callback_type get_more; /* No stack for this */
187 unsigned char *next_start; /* sp + #0 */
188 size_t next_size; /* sp + #4 */
189
186 /* clear any pending interrupt */ 190 /* clear any pending interrupt */
187 SRCPND = (1<<19); 191 SRCPND = (1<<19);
188 192
189 /* Buffer empty. Try to get more. */ 193 /* Buffer empty. Try to get more. */
190 if (pcm_callback_for_more) 194 get_more = pcm_callback_for_more;
191 { 195 if (get_more == NULL)
192 pcm_callback_for_more((unsigned char**)&p, &p_size);
193 }
194 else
195 { 196 {
196 /* callback func is missing? */ 197 /* Callback missing */
197 pcm_play_dma_stop_fiq(); 198 pcm_play_dma_stop_fiq();
198 return; 199 goto fiq_exit;
199 } 200 }
200 201
201 if (p_size) 202 next_size = 0;
202 { 203 get_more(&next_start, &next_size);
203 /* Flush any pending cache writes */
204 clean_dcache_range(p, p_size);
205
206 /* set the new DMA values */
207 DCON2 = DMA_CONTROL_SETUP | (p_size >> 1);
208 DISRC2 = (int)p + 0x30000000;
209 204
210 /* Re-Activate the channel */ 205 if (next_size == 0)
211 DMASKTRIG2 = 0x2;
212 }
213 else
214 { 206 {
215 /* No more DMA to do */ 207 /* No more DMA to do */
216 pcm_play_dma_stop_fiq(); 208 pcm_play_dma_stop_fiq();
209 goto fiq_exit;
217 } 210 }
218 211
212 /* Flush any pending cache writes */
213 clean_dcache_range(next_start, next_size);
214
215 /* set the new DMA values */
216 DCON2 = DMA_CONTROL_SETUP | (next_size >> 1);
217 DISRC2 = (unsigned long)next_start + 0x30000000;
218
219 /* Re-Activate the channel */
220 DMASKTRIG2 = 0x2;
221
222fiq_exit:
223 asm volatile("add sp, sp, #8 \n" /* Cleanup stack */
224 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
225 "subs pc, lr, #4 \n"); /* Return from FIQ */
219} 226}
220 227
221/* Disconnect the DMA and wait for the FIFO to clear */ 228/* Disconnect the DMA and wait for the FIFO to clear */