1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2008 by Maurus Cuelenaere
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
31 /****************************************************************************
32 ** Playback DMA transfer
35 void pcm_postinit(void)
39 /* playback sample: 16 bits burst: 16 bytes */
40 __i2s_set_iss_sample_size(16);
41 __i2s_set_oss_sample_size(16);
42 __i2s_set_transmit_trigger(10);
43 __i2s_set_receive_trigger(1);
49 void pcm_play_dma_init(void)
53 system_enable_irq(DMA_IRQ(DMA_AIC_TX_CHANNEL
));
55 /* Initialize default register values. */
59 void pcm_dma_apply_settings(void)
62 audiohw_set_frequency(pcm_sampr
);
65 static void* playback_address
;
66 static inline void set_dma(const void *addr
, size_t size
)
69 logf("%x %d %x", (unsigned int)addr
, size
, REG_AIC_SR
);
76 burst_size
= DMAC_DCMD_DS_16BIT
;
81 burst_size
= DMAC_DCMD_DS_32BIT
;
87 burst_size
= DMAC_DCMD_DS_16BYTE
;
90 __dcache_writeback_all();
91 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) = DMAC_DCCSR_NDES
;
92 REG_DMAC_DSAR(DMA_AIC_TX_CHANNEL
) = PHYSADDR((unsigned long)addr
);
93 REG_DMAC_DTAR(DMA_AIC_TX_CHANNEL
) = PHYSADDR((unsigned long)AIC_DR
);
94 REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL
) = size
;
95 REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL
) = DMAC_DRSR_RS_AICOUT
;
96 REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL
) = (DMAC_DCMD_SAI
| DMAC_DCMD_SWDH_32
| burst_size
| DMAC_DCMD_DWDH_16
| DMAC_DCMD_TIE
);
98 playback_address
= (void*)addr
;
101 static inline void play_dma_callback(void)
103 unsigned char *start
= NULL
;
106 if(pcm_callback_for_more
)
107 pcm_callback_for_more(&start
, &size
);
109 if(LIKELY(size
> 0 && start
))
111 set_dma(start
, size
);
112 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) |= DMAC_DCCSR_EN
;
116 /* Error, callback missing or no more DMA to do */
118 pcm_play_dma_stopped_callback();
122 void DMA_CALLBACK(DMA_AIC_TX_CHANNEL
)(void) __attribute__ ((section(".icode")));
123 void DMA_CALLBACK(DMA_AIC_TX_CHANNEL
)(void)
125 if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) & DMAC_DCCSR_AR
)
127 logf("PCM DMA address error");
128 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) &= ~DMAC_DCCSR_AR
;
131 if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) & DMAC_DCCSR_HLT
)
133 logf("PCM DMA halt");
134 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) &= ~DMAC_DCCSR_HLT
;
137 if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) & DMAC_DCCSR_TT
)
139 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) &= ~DMAC_DCCSR_TT
;
144 void pcm_play_dma_start(const void *addr
, size_t size
)
150 __aic_enable_transmit_dma();
151 __aic_enable_replay();
153 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) |= DMAC_DCCSR_EN
;
156 void pcm_play_dma_stop(void)
158 int flags
= disable_irq_save();
160 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) = (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) | DMAC_DCCSR_HLT
) & ~DMAC_DCCSR_EN
;
164 __aic_disable_transmit_dma();
165 __aic_disable_replay();
170 static unsigned int play_lock
= 0;
171 void pcm_play_lock(void)
173 int flags
= disable_irq_save();
175 if (++play_lock
== 1)
176 __dmac_channel_disable_irq(DMA_AIC_TX_CHANNEL
);
181 void pcm_play_unlock(void)
183 int flags
= disable_irq_save();
185 if (--play_lock
== 0)
186 __dmac_channel_enable_irq(DMA_AIC_TX_CHANNEL
);
191 void pcm_play_dma_pause(bool pause
)
193 int flags
= disable_irq_save();
196 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) &= ~DMAC_DCCSR_EN
;
198 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) |= DMAC_DCCSR_EN
;
203 static int get_dma_count(void)
205 int count
= REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL
);
206 switch(REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL
) & DMAC_DCMD_DS_MASK
)
208 case DMAC_DCMD_DS_16BIT
:
211 case DMAC_DCMD_DS_32BIT
:
214 case DMAC_DCMD_DS_16BYTE
:
222 size_t pcm_get_bytes_waiting(void)
224 int bytes
, flags
= disable_irq_save();
226 if(REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) & DMAC_DCCSR_EN
)
227 bytes
= get_dma_count() & ~3;
236 const void * pcm_play_dma_get_peak_buffer(int *count
)
238 int flags
= disable_irq_save();
241 if(REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL
) & DMAC_DCCSR_EN
)
243 int bytes
= get_dma_count();
245 addr
= (const void*)((int)(playback_address
+ bytes
+ 2) & ~3);
258 void audiohw_close(void)
260 /* TODO: prevent pop */
263 #ifdef HAVE_RECORDING
265 void pcm_rec_dma_init(void)
269 void pcm_rec_dma_close(void)
273 void pcm_rec_dma_start(void *addr
, size_t size
)
279 void pcm_rec_dma_stop(void)
283 void pcm_rec_lock(void)
287 void pcm_rec_unlock(void)
291 const void * pcm_rec_dma_get_peak_buffer(void)
296 void pcm_rec_dma_record_more(void *start
, size_t size
)