diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2018-06-28 06:24:26 -0400 |
---|---|---|
committer | Michael Giacomelli <giac2000@hotmail.com> | 2018-07-28 10:56:31 -0400 |
commit | 0662793ca0050e823cd1207cc4689a1cba5068bd (patch) | |
tree | 08cd2ec59c9044c96b697b5bf8d0640841d044e0 /firmware/target/mips/ingenic_jz47xx/pcm-jz4760.c | |
parent | b3e2bd619b1b7ea94ef29d32db48e80b347a1990 (diff) | |
download | rockbox-0662793ca0050e823cd1207cc4689a1cba5068bd.tar.gz rockbox-0662793ca0050e823cd1207cc4689a1cba5068bd.zip |
Add cleaned-up xDuoo X3 support
Cleaned up, rebased, and forward-ported from the xvortex fork.
(original credit to vsoftster@gmail.com)
Change-Id: Ibcc023a0271ea81e901450a88317708c2683236d
Signed-off-by: Solomon Peachy <pizza@shaftnet.org>
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/pcm-jz4760.c')
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/pcm-jz4760.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/pcm-jz4760.c b/firmware/target/mips/ingenic_jz47xx/pcm-jz4760.c new file mode 100644 index 0000000000..39df037f76 --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/pcm-jz4760.c | |||
@@ -0,0 +1,240 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2016 by Roman Stolyarov | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "system.h" | ||
23 | #include "kernel.h" | ||
24 | #include "logf.h" | ||
25 | #include "audio.h" | ||
26 | #include "sound.h" | ||
27 | #include "pcm.h" | ||
28 | #include "pcm-internal.h" | ||
29 | #include "cpu.h" | ||
30 | |||
31 | |||
32 | /**************************************************************************** | ||
33 | ** Playback DMA transfer | ||
34 | **/ | ||
35 | |||
36 | void pcm_play_dma_postinit(void) | ||
37 | { | ||
38 | audiohw_postinit(); | ||
39 | |||
40 | /* Flush FIFO */ | ||
41 | __aic_flush_tfifo(); | ||
42 | } | ||
43 | |||
44 | void pcm_play_dma_init(void) | ||
45 | { | ||
46 | system_enable_irq(DMA_IRQ(DMA_AIC_TX_CHANNEL)); | ||
47 | |||
48 | /* Initialize default register values. */ | ||
49 | audiohw_init(); | ||
50 | } | ||
51 | |||
52 | void pcm_dma_apply_settings(void) | ||
53 | { | ||
54 | audiohw_set_frequency(pcm_fsel); | ||
55 | } | ||
56 | |||
57 | static const void* playback_address; | ||
58 | static inline void set_dma(const void *addr, size_t size) | ||
59 | { | ||
60 | int burst_size; | ||
61 | logf("%x %d %x", (unsigned int)addr, size, REG_AIC_SR); | ||
62 | |||
63 | dma_cache_wback_inv((unsigned long)addr, size); | ||
64 | |||
65 | if(size % 16) | ||
66 | { | ||
67 | if(size % 4) | ||
68 | { | ||
69 | size /= 2; | ||
70 | burst_size = DMAC_DCMD_DS_16BIT; | ||
71 | } | ||
72 | else | ||
73 | { | ||
74 | size /= 4; | ||
75 | burst_size = DMAC_DCMD_DS_32BIT; | ||
76 | } | ||
77 | } | ||
78 | else | ||
79 | { | ||
80 | size /= 16; | ||
81 | burst_size = DMAC_DCMD_DS_16BYTE; | ||
82 | } | ||
83 | |||
84 | REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = 0; | ||
85 | REG_DMAC_DSAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)addr); | ||
86 | REG_DMAC_DTAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)AIC_DR); | ||
87 | REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) = size; | ||
88 | REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT; | ||
89 | REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | burst_size | DMAC_DCMD_DWDH_16 | DMAC_DCMD_TIE); | ||
90 | REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; | ||
91 | |||
92 | playback_address = addr; | ||
93 | } | ||
94 | |||
95 | static inline void play_dma_callback(void) | ||
96 | { | ||
97 | const void *start; | ||
98 | size_t size; | ||
99 | |||
100 | if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) | ||
101 | { | ||
102 | set_dma(start, size); | ||
103 | REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN; | ||
104 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void) __attribute__ ((section(".icode"))); | ||
109 | void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void) | ||
110 | { | ||
111 | if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_AR) | ||
112 | { | ||
113 | logf("PCM DMA address error"); | ||
114 | REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_AR; | ||
115 | } | ||
116 | |||
117 | if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_HLT) | ||
118 | { | ||
119 | logf("PCM DMA halt"); | ||
120 | REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_HLT; | ||
121 | } | ||
122 | |||
123 | if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_TT) | ||
124 | { | ||
125 | REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_TT; | ||
126 | play_dma_callback(); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | void pcm_play_dma_start(const void *addr, size_t size) | ||
131 | { | ||
132 | __dmac_channel_enable_clk(DMA_AIC_TX_CHANNEL); | ||
133 | |||
134 | set_dma(addr, size); | ||
135 | |||
136 | __aic_enable_replay(); | ||
137 | |||
138 | __dmac_channel_enable_irq(DMA_AIC_TX_CHANNEL); | ||
139 | } | ||
140 | |||
141 | void pcm_play_dma_stop(void) | ||
142 | { | ||
143 | int flags = disable_irq_save(); | ||
144 | |||
145 | REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) | DMAC_DCCSR_HLT) & ~DMAC_DCCSR_EN; | ||
146 | |||
147 | __dmac_channel_disable_clk(DMA_AIC_TX_CHANNEL); | ||
148 | |||
149 | __aic_disable_replay(); | ||
150 | |||
151 | restore_irq(flags); | ||
152 | } | ||
153 | |||
154 | static unsigned int play_lock = 0; | ||
155 | void pcm_play_lock(void) | ||
156 | { | ||
157 | int flags = disable_irq_save(); | ||
158 | |||
159 | if (++play_lock == 1) | ||
160 | __dmac_channel_disable_irq(DMA_AIC_TX_CHANNEL); | ||
161 | |||
162 | restore_irq(flags); | ||
163 | } | ||
164 | |||
165 | void pcm_play_unlock(void) | ||
166 | { | ||
167 | int flags = disable_irq_save(); | ||
168 | |||
169 | if (--play_lock == 0) | ||
170 | __dmac_channel_enable_irq(DMA_AIC_TX_CHANNEL); | ||
171 | |||
172 | restore_irq(flags); | ||
173 | } | ||
174 | |||
175 | void pcm_play_dma_pause(bool pause) | ||
176 | { | ||
177 | int flags = disable_irq_save(); | ||
178 | |||
179 | if(pause) | ||
180 | REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_EN; | ||
181 | else | ||
182 | REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN; | ||
183 | |||
184 | restore_irq(flags); | ||
185 | } | ||
186 | |||
187 | static int get_dma_count(void) | ||
188 | { | ||
189 | int count = REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL); | ||
190 | switch(REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) & DMAC_DCMD_DS_MASK) | ||
191 | { | ||
192 | case DMAC_DCMD_DS_16BIT: | ||
193 | count *= 2; | ||
194 | break; | ||
195 | case DMAC_DCMD_DS_32BIT: | ||
196 | count *= 4; | ||
197 | break; | ||
198 | case DMAC_DCMD_DS_16BYTE: | ||
199 | count *= 16; | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | return count; | ||
204 | } | ||
205 | |||
206 | size_t pcm_get_bytes_waiting(void) | ||
207 | { | ||
208 | int bytes, flags = disable_irq_save(); | ||
209 | |||
210 | if(REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_EN) | ||
211 | bytes = get_dma_count() & ~3; | ||
212 | else | ||
213 | bytes = 0; | ||
214 | |||
215 | restore_irq(flags); | ||
216 | |||
217 | return bytes; | ||
218 | } | ||
219 | |||
220 | const void * pcm_play_dma_get_peak_buffer(int *count) | ||
221 | { | ||
222 | int flags = disable_irq_save(); | ||
223 | |||
224 | const void* addr; | ||
225 | if(REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_EN) | ||
226 | { | ||
227 | int bytes = get_dma_count(); | ||
228 | *count = bytes >> 2; | ||
229 | addr = (const void*)((int)(playback_address + bytes + 2) & ~3); | ||
230 | } | ||
231 | else | ||
232 | { | ||
233 | *count = 0; | ||
234 | addr = NULL; | ||
235 | } | ||
236 | |||
237 | restore_irq(flags); | ||
238 | |||
239 | return addr; | ||
240 | } | ||